2.1 OpenCV随手简记(二)

为后续项目学习做准备,我们需要了解LinuxOpenCV、Mediapipe、ROS、QT等知识。

一、图像显示与保存

1、基本原理

1.1 图像像素存储形式

首先得了解下图像在计算机中存储形式:(为了方便画图,每列像素值都写一样了)。对于只有黑白颜色的灰度图,为单通道,一个像素块对应矩阵中一个数字,数值为0到255, 其中0表示最暗(黑色) ,255表示最亮(白色)

对于采用RGB模式的彩色图片,为三通道图,Red、Green、Blue三原色,按不同比例相加,一个像素块对应矩阵中的一个向量, 如[24,180, 50],分别表示三种颜色的比列, 即对应深度上的数字,如下图所示:

 需要注意的是,由于历史遗留问题,opencv采用BGR模式,而不是RGB


2、API说明

API名: cv2.destroyAllWindows( )

删除所有我们建立的窗口

API名: cv2.destroyWindow(指定窗口名)

删除特定的窗口可以使用,在括号内输入你想删 除的窗口名。

API名: cv2.imshow('窗口名', 图像变量):

用“窗口名”显示图像

API名:cv2.resizeWindow(‘窗口名’, 宽, 高)  

调整窗口大小

API名:cv2.imwrite('图像文件地址',图像变量)

将图像变量保存到指定位置的指定文件中

 API名:cv.namedWindow(winname, flags=None)

参数:winname

窗口名字

flags窗口标志

标志参数

作用

WINDOW_NORMAL

显示图像后,允许用户随意调整窗口大小

WINDOW_AUTOSIZE

根据图像大小显示窗口,不允许用户调整大小

WINDOW_FREERATIO

窗口大小自适应比例

WINDOW_KEEPRATIO

保持图像的比例

1、具体代码展示标志效果

1.1 窗口大小可变

cv.namedWindow("show Image",cv.)

或者 cv.namedWindow("show Image",cv.WINDOW_GUI_NORMAL)

或者 cv.namedWindow("show Image",0)

此时的图片是可以自由拉伸改变大小的

1.2 窗口大小不可变,自动适应图片大小(默认)

cv.namedWindow("show Image",cv.WINDOW_AUTOSIZE)

或者 cv.namedWindow("show Image",1)

1.3 窗口大小自适应比例

cv.namedWindow("show Image",cv.WINDOW_FREERATIO)

1.4 窗口大小跟随图片保持其比例

cv.namedWindow("show Image",cv.WINDOW_KEEPRATIO)

说明:如果在imshow()之前加上namedWindow()方法来显示一张图片的话,该窗口显示的图片是可交互的。

1、这里使用imshow()和namedWindow()方法时候窗口的标识名称(传递的第一个参数)要一样。

2、namedWindow()方法要写在imshow()方法之前才可以。

 API名:cv.namedWindow(winname, flags=None)

参数:winname

窗口名字

flags窗口标志

标志参数

作用

WINDOW_NORMAL

显示图像后,允许用户随意调整窗口大小

WINDOW_AUTOSIZE

根据图像大小显示窗口,不允许用户调整大小

WINDOW_FREERATIO

窗口大小自适应比例

WINDOW_KEEPRATIO

保持图像的比例

1、具体代码展示标志效果

1.1 窗口大小可变

cv.namedWindow("show Image",cv.)

或者 cv.namedWindow("show Image",cv.WINDOW_GUI_NORMAL)

或者 cv.namedWindow("show Image",0)

此时的图片是可以自由拉伸改变大小的

1.2 窗口大小不可变,自动适应图片大小(默认)

cv.namedWindow("show Image",cv.WINDOW_AUTOSIZE)

或者 cv.namedWindow("show Image",1)

1.3 窗口大小自适应比例

cv.namedWindow("show Image",cv.WINDOW_FREERATIO)

1.4 窗口大小跟随图片保持其比例

cv.namedWindow("show Image",cv.WINDOW_KEEPRATIO)

说明:如果在imshow()之前加上namedWindow()方法来显示一张图片的话,该窗口显示的图片是可交互的。

1、这里使用imshow()和namedWindow()方法时候窗口的标识名称(传递的第一个参数)要一样。

2、namedWindow()方法要写在imshow()方法之前才可以。


三、代码示例

使用 Matplotlib显示图片

import cv2

from matplotlib import pyplot as plt

 

if __name__ == "__main__":

    img = cv2.imread('1.jpg',0)

    plt.imshow(img, cmap = 'gray', interpolation = 'bicubic')

    plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis

plt.show()

使用 Matplotlib显示图片并进行一些操作

import cv2

from matplotlib import pyplot as plt

 

if __name__ == "__main__":

    img = cv2.imread('2.jpg')

    edges = cv2.Canny(img,100,200)

 

    plt.subplot(121),plt.imshow(img,cmap = 'gray')

    plt.title('Original Image'),  plt.xticks([]), plt.yticks([])

    plt.subplot(122),  plt.imshow(edges,cmap = 'gray')

    plt.title('Edge Image'), plt.xticks([]), plt.yticks([])

    plt.show()

说明:plt.imshow()函数负责对图像进行处理,并显示其格式,而plt.show()则是将plt.imshow()处理后的函数显示出来。



二、图像处理基础

1.1、获取图像属性

所谓获取图像属性,实际上就说当我们把一幅图像读入内存后,这幅图像就如同一个三维或二维数组,那既然是个numpy数组,必然可以获取它的shape、它的size以及它的dtype。乃至于,你可以像操作numpy数组那样,在图像上做诸如求平均值、方差之类的各种数学操作。因此,实际上获取图像的属性操作也很简单,比如下面这个例子就分别展示了如何获得图像的shape(指示是三维还是二维图像,或者说彩色图还是灰度图)、size(图像中像素的总数,依据这个总数以及每个像素的dtype就可以获得这幅图像当前总共占据多少内存存储空间)、dtype(每个像素值的数据类型:float32还是int等等):

img = cv2.imread('test.jpg')

获取图像的属性

img.shape

可以获取图像的形状。他的返回值是:一个包含(行数(高),列数(宽), 通道数)的元组。

img.size

返回图像的像素数目

img.dtype

返回返回图像的数据类型

API名:cv2.imwrite('图像文件地址',图像变量)

将图像变量保存到指定位置的指定文件中

先查看原始图像的shape、size、dtype:(675, 1200, 3) 2430000 uint8

再查看颜色模式为HSV后的图像的shape、size、dtype:(675, 1200, 3) 2430000 uint8

最后查看变成灰度图后图像的shape、size、dtype:(675, 1200) 810000 uint8

从结果来看,当彩色图变成灰度图之后,通道数没有了,意味着图像的像素总数也会大幅减少。


1.2 图像像素更改

        图像像素的更改行为,往往在机器视觉中是最最简单的一种行为,其操作起来也如同我们更改一个list或者一个numpy数组中的元素那样简单。要知道,任何一幅图像实际上读到内存之后就是一个numpy数组,因此,图像像素的修改就如同我们在修改一个n维数组中的某个元素那样简单。所不同的是,修改图像像素,我们需要指定图像像素的坐标:

         如果是RGB格式的,坐标就分别是R、G、B三个通道的值来共同定位一个像素;如果是HSV或别的什么颜色模式下的图像,也如同像RGB那样指定出三维坐标系各个坐标轴上的坐标值即可。

        如果是一个灰度图,则如同一个平面坐标系那般简单,只需要指定横纵坐标的值即可圈定一个像素。

        当然,通常情况下,我们只需要给出像素的行和列坐标值即可获得像素内的值。此时,对于RGB或HSV等三维颜色格式的图像来说,返回的是图像的三维坐标的值,比如RGB就是返回R、G、B;HSV的就是返回H、S、V;对于灰度图来说则是返回的是灰度值。

        同时,给定像素的行、列坐标值就可以依据像操作numpy二维数组那样来给指定的像素点修改像素值。

获取像素值并修改

参数含义:y坐标x:x坐标

bgr:BGR通道,0:B通道,1:G通道,2:R通道

获取像素值 img[y,x]

获取(x,y)处的通道值,返回列表


img = cv2.imread('test.jpg')

# 获取像素值px = img[100, 200]

img[y,x,bgr] 

获取(x,y)处一个通道值

获取像素中的B通道颜色值blue = img[100, 200, 0]

修改像素值 img[y,x]=[b,g,r]

将一个颜色赋值给一个像素点

# 修改像素值img[100, 200] = [0, 123, 155]

比如下面这段小代码就很好地解释了如何获取不同颜色格式下的像素值内容:

import numpy as npimport cv2#读入原始图片,并将其进行颜色空间转换为HSV和灰度图#再分别读出相同的行、列坐标值下的像素值以加深对像素值更操作的理解
import numpy as npimport cv2#读入原始图片,并将其进行颜色空间转换为HSV和灰度图#再分别读出相同的行、列坐标值下的像素值以加深对像素值更操作的理解
img = cv2.imread(r'E:\tmp\maerdaifu.jpg',cv2.IMREAD_UNCHANGED)
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
print('以下为不同颜色模式下获取像素值的输出结果')
print(img[100,100])
print(hsv[100,100])
print(gray[100,100])img[100,100]=[192, 212, 222]
hsv[100,100]=[198, 218, 228]
gray[100,100]=255print('以下为不同颜色模式下修改像素值的输出结果')
print(img[100,100])
print(hsv[100,100])
print(gray[100,100])

以下为不同颜色模式下获取像素值的输出结果

[217 121  55][108 190 217]  

以下为不同颜色模式下修改像素值的输出结果[192 212 222][198 218 228]

1.3 获取图像的感兴趣区域(ROI)

        图像的感兴趣区域(ROI:region of interest),是指在机器视觉、图像处理中,从被处理的图像以方框、圆、椭圆、不规则多边形等方式勾勒出需要处理的区域,称为感兴趣区域。在图像处理领域,感兴趣区域是从图像中选择的一个图像区域,这个区域是你的图像分析所关注的重点。圈定该区域以便进行进一步处理。使用ROI圈定你想读的目标,可以减少处理时间,增加精度。感兴趣区是图像的一部分,它通过在图像上选择或使用诸如设定阈值(thresholding) 或者从其他文件(如矢量> 转换获得等方法生成。感趣区可以是点、线、面不规则的形状,通常用来作为图像分类的样本、掩膜、裁剪区或及其他操作。

        比如,我想要抠出下面这幅图中的房子:

图1 马尔代夫风景图

        那么首先我需要知道图中的房子大约在哪些像素坐标范围之内,也即其行坐标范围和列坐标范围。这里我们需要事先弄清楚感兴趣区域在图像中的坐标范围:即行列坐标的坐标值范围。

        确定坐标范围后,我们利用切片操作,像在Numpy数组中获取一定范围内的数据那样,即可获得我们感兴趣的区域内的目标对象——房子。整个获取ROI的代码如下所示:

import cv2
#读入原始图片
img = cv2.imread(r'E:\tmp\maerdaifu.jpg',cv2.IMREAD_UNCHANGED)
#扣除我们感兴趣的房子区域并予以单独显示
house = img[126:353,316:908]
cv2.imshow('HouseTest1', house)
#我们再把抠出来的房子放至原图像的其他区域,再显示操作过后的原始图像img[326:553,500:1092]=house
cv2.imshow('HouseTest2', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

其运行结果如下:

图2 抠出的ROI图像

图3 将ROI图像重新放置回原始图中的运行效果图

        从以上两幅图来看,我们大体上知道了如何来获取一个ROI图像。

        需要注意的是:图像在内存中的存储格式是一个numpy数组,因此,当你给定行列坐标值范围时,一定要把列坐标范围放置在切片操作的第一个参数值上,行坐标值范围为切片操作的第二个参数。这是大家在实际利用numpy数组开展切片操作或其他需要用到行列坐标参与运算时最最容易犯的错误之一。

1.4 图像通道的拆分、合并操作

        当我们需要单独对图像的通道进行操作,比如R、G、B三个通道都有不同的操作时,我们就需要用到通道的拆分。当拆分后的通道被处理结束之后,可能需要将其复原时,又需要用到通道的合并操作。由于我们再三强调过读入一幅图像到内存后,其实质就是读入一个numpy数组,因此,在numpy的基础知识讲解中,如何拆分和合并不同的维度,这里就可以用同样的API来操作,也即利用split()来拆分通道,利用merge()来合并通道,

拆分通道1: b,g,r = cv2.split(m,mv)

m:  图像imgmv:  默认为None

# 分离颜色通道

b, g, r = cv2.split(img)

cv2.imshow('Blue', b)

cv2.imshow('Green', g)

cv2.imshow('Red', r)

拆分通道2:

b=img[:,:,bgr]

# 其他方法

b1 = img[:, :, 0] # 仅取B通道

cv2.imshow('Blue-1', b1)

b2 = cv2.imread('test.jpg')

b2[:, :, 1:3] = 0 # 将0赋值给G、R通道

cv2.imshow('Blue-2', b2)

合并通道 img = cv2.merge([X,Y,Z])

mergeImg = cv2.merge([b, g, r])

cv2.imshow('merge', mergeImg )

mergeImg2 = cv2.merge([h, s, v])

cv2.imshow('merge', mergeImg2 )

import cv2#读入原始图片
img = cv2.imread(r'E:\tmp\maerdaifu.jpg',cv2.IMREAD_UNCHANGED)
r,g,b = cv2.split(img) #请大家注意一下merge函数的参数给定形式,如果不以list  或tuple方式来给定的话,必然会出错
img = cv2.merge([r,g,b])
cv2.imshow('Test', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

其运行结果如下:

图4 通道拆分合并效果图

可以看出,通道经拆分再合并后得到的图像与原始图像并无二致。

#通道的分离与合并以及某个通道值的修改
import cv2 as cv
src=cv.imread('E:\imageload\example.png')
cv.namedWindow('first_image', cv.WINDOW_AUTOSIZE)
cv.imshow('first_image', src)
#三通道分离形成单通道图片
b, g, r =cv.split(src)
cv.imshow("second_blue", b)
cv.imshow("second_green", g)
cv.imshow("second_red", r)
# 其中cv.imshow("second_red", r)可表示为r = cv2.split(src)[2]
#三个单通道合成一个三通道图片
src = cv.merge([b, g, r])
cv.imshow('changed_image', src)#修改多通道里的某个通道的值
src[:, :, 2] = 0
cv.imshow('modify_image', src)cv.waitKey(0)
cv.destroyAllWindows()

5、添加边界(padding)/为图像扩边

cv2.copyMakeBorder(src,top, bottom, left, right,borderType,value)

src: 输入图像

• top, bottom, left, right 对应边界的像素数目。

value: 边界颜色,如果borderType为cv2.BORDER_CONSTANT时,传入的边界颜色值,如[0,255,0]

borderType: 要添加那种类型的边界,类型如下

–cv2.BORDER_CONSTANT 添加有颜色的常数值边界,还需要下一个参数(value)。

– cv2.BORDER_REFLECT边界元素的镜像。比如: fedcba|abcdefgh|hgfedcb

– cv2.BORDER_REFLECT_101 or cv2.BORDER_DEFAULT 跟上面一样,但稍作改动。例如: gfedcb|abcdefgh|gfedcba

– cv2.BORDER_REPLICATE重复最后一个元素。例如: aaaaaa| abcdefgh|hhhhhhh

– cv2.BORDER_WRAP 不知道怎么说了, 就像这样: cdefgh| abcdefgh|abcdefg

import cv2
import numpy as np
from matplotlib import pyplot as pltBLUE = [255, 0, 0]img = cv2.imread('test.jpg')
replicate = cv2.copyMakeBorder(img, 30, 30, 30, 30, cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, 30, 30, 30, 30, cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img, 30, 30, 30, 30, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img, 30, 30, 30, 30, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, 30, 30, 30, 30, cv2.BORDER_CONSTANT, value=BLUE)plt.subplot(231),
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB), 'gray'),   plt.title('ORIGINAL')
plt.subplot(232),
plt.imshow(cv2.cvtColor(replicate,cv2.COLOR_BGR2RGB),'gray'),  plt.title('REPLICATE')
plt.subplot(233), 
plt.imshow(cv2.cvtColor(reflect, cv2.COLOR_BGR2RGB), 'gray'),   plt.title('REFLECT')
plt.subplot(234), 
plt.imshow(cv2.cvtColor(reflect101, cv2.COLOR_BGR2RGB), 'gray'),   plt.title('REFLECT_101')
plt.subplot(235), 
plt.imshow(cv2.cvtColor(wrap, cv2.COLOR_BGR2RGB), 'gray'),    plt.title('WRAP')
plt.subplot(236), 
plt.imshow(cv2.cvtColor(constant, cv2.COLOR_BGR2RGB), 'gray'), plt.title('CONSTANT')
plt.show() 
  • 使用示例:
import cv2 as cv
import matplotlib.pyplot as pltimg2 = cv.imread(r"C:\Users\Administrator\Desktop\dog.jpg")
img = cv.cvtColor(img2,cv.COLOR_BGR2RGB)  #matplotlib的图像为RGB格式
constant = cv.copyMakeBorder(img,20,20,20,20,cv.BORDER_CONSTANT,value=[0,255,0]) #绿色
reflect = cv.copyMakeBorder(img,20,20,20,20,cv.BORDER_REFLECT)
reflect01 = cv.copyMakeBorder(img,20,20,20,20,cv.BORDER_REFLECT_101)
replicate = cv.copyMakeBorder(img,20,20,20,20,cv.BORDER_REPLICATE)
wrap = cv.copyMakeBorder(img,20,20,20,20,cv.BORDER_WRAP)
titles = ["constant","reflect","reflect01","replicate","wrap"]
images = [constant,reflect,reflect01,replicate,wrap]
for i in range(5):plt.subplot(2,3,i+1),plt.imshow(images[i]),plt.title(titles[i])plt.xticks([]),plt.yticks([])
plt.show()

  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/20221.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[有监督学习]2.详细图解正则化

正则化 正则化是防止过拟合的一种方法,与线性回归等算法配合使用。通过向损失函数增加惩罚项的方式对模型施加制约,有望提高模型的泛化能力。 概述 正则化是防止过拟合的方法,用于机器学习模型的训练阶段。过拟合是模型在验证数据上产生的误…

Java文件IO

White graces:个人主页 🙉专栏推荐:Java入门知识🙉 🙉 内容推荐:JUC常见类🙉 🐹今日诗词:东风吹柳日初长,雨馀芳草斜阳🐹 ⛳️点赞 ☀️收藏⭐️关注💬卑微小博主&…

Three.js 研究:4、创建设备底部旋转的科技感圆环

1、实现效果 2、PNG转SVG 2.1、原始物料 使用网站工具https://convertio.co/zh/png-svg/进行PNG转SVG 3、导入SVG至Blender 4、制作旋转动画 4.1、给圆环着色 4.2、修改圆环中心位置 4.3、让圆环旋转起来 参考一下文章 Three.js 研究:1、如何让物体动起来 Thre…

“论SOA在企业集成架构设计中的应用”必过模板,突击2024软考高项论文

考题部分 企业应用集成(Enterprise Application Integration, EAI)是每个企业都必须要面对的实际问题。面向服务的企业应用集成是一种基于面向服务体系结构(Service-OrientedArchitecture,SOA)的新型企业应用集成技术,强调将企业和组织内部的资源和业务功…

VSCode界面Outline只显示类名和函数名,隐藏变量名

参考链接 https://blog.csdn.net/Zjhao666/article/details/120523879https://blog.csdn.net/Williamcsj/article/details/122401996 VSCode中界面左下角的Outline能够方便快速跳转到文件的某个类或函数,但默认同时显示变量,导致找某个函数时很不方便。…

mimkatz获取windows10明文密码

目录 mimkatz获取windows10明文密码原理 lsass.exe进程的作用 mimikatz的工作机制 Windows 10的特殊情况 实验 实验环境 实验工具 实验步骤 首先根据版本选择相应的mimikatz 使用管理员身份运行cmd 修改注册表 ​编辑 重启 重启电脑后打开mimikatz 在cmd切换到mi…

Seq2Seq模型:详述其发展历程、深远影响与结构深度剖析

Seq2Seq(Sequence-to-Sequence)模型是一种深度学习架构,专为处理从一个输入序列到一个输出序列的映射任务设计。这种模型最初应用于机器翻译任务,但因其灵活性和有效性,现已被广泛应用于自然语言处理(NLP&a…

医院该如何应对网络安全?

在线医生咨询受到很多人的关注,互联网医疗行业的未来发展空间巨大,但随着医院信息化建设高速发展 医院积累了大量的患者基本信息、化验结果、电子处方、生产数据和运营信息等数据 这些数据涉及公民隐私、医院运作和发展等多因素,医疗行业办…

【QEMU中文文档】1.关于QEMU

本文由 AI 翻译(ChatGPT-4)完成,并由作者进行人工校对。如有任何问题或建议,欢迎联系我。联系方式:jelin-shoutlook.com。 QEMU 是一款通用的开源机器仿真器和虚拟化器。 QEMU 可以通过几种不同的方式使用。最常见的用…

OrangePi AIpro--新手上路

目录 一、SSH登录二、安装VNC Sevice(经测试Xrdp远程桌面安装不上)2.1安装xface桌面2.2 配置vnc服务2.2.1 设置vnc server6-8位的密码2.2.2 创建vnc文件夹,写入xstartup文件2.2.3 给xstartup文件提高权限2.2.4 在安装产生的vnc文件夹创建xsta…

【Uniapp小程序】自定义导航栏uni-nav-bar滚动渐变色

效果图 新建activityScrollTop.js作为mixins export default {data() {return {navBgColor: "rgba(0,0,0,0)", // 初始背景颜色为完全透明navTextColor: "rgba(0,0,0,1)", // 初始文字颜色};},onPageScroll(e) {// 设置背景const newAlpha Math.min((e.s…

PPP认证两种:PAP和CHAP,两次握手和三次握手

CHAP(Challenge-Handshake Authentication Protocol,质询握手认证协议)的设计理念是增强网络认证过程的安全性。在CHAP的三次握手过程中,不直接传送用户的明文密码,以此来提高安全性,具体步骤如下&#xff…

springboot结合mybatis使用多数据源的方式

背景 最近有一个需求,有两个库需要做同步数据,一个Doris库,一个mysql库,两边的表结构一致,这里不能使用navicat等工具提供的数据传输之类的功能,只能使用代码做同步,springboot配置多数据…

如何设置手机的DNS

DNS 服务器 IP 地址 苹果 华为 小米 OPPO VIVO DNS 服务器 IP 地址 中国大陆部分地区会被运营商屏蔽网络导致无法访问,可修改手机DNS解决。 推荐 阿里的DNS (223.5.5.5)或 114 (114.114.114.114和114.114.115.115) 更多公开DNS参考: 苹果…

ESP32-C3模组上实现蓝牙BLE配网功能(1)

本文内容参考: 《ESP32-C3 物联网工程开发实战》 乐鑫科技 蓝牙的名字由来是怎样的?为什么不叫它“白牙”? 特此致谢! 一、蓝牙知识基础 1. 什么是蓝牙? (1)简介 蓝牙技术是一种无线数据和…

Camunda BPM架构

Camunda BPM既可以单独作为流程引擎服务存在,也能嵌入到其他java应用中。Camunda BPM的核心流程引擎是一个轻量级的模块,可以被Spring管理或者加入到自定义的编程模型中,并且支持线程模型。 1,流程引擎架构 流程引擎由多个组件构成,如下所示: API服务 API服务,允许ja…

蒙自源儿童餐新品上市,引领健康美味新潮流

随着夏日的热烈与儿童节的欢乐氛围到来,蒙自源品牌隆重推出儿童餐新品,以“快乐不分大小,谁还不是个宝宝”为主题,为广大消费者带来一场健康与美味的盛宴。新品上市活动将于5月25日举行,蒙自源将以其独特的产品魅力和创…

最新 HUAWEI DevEco Studio 调试技巧

最新 HUAWEI DevEco Studio 调试技巧 前言 在我们使用 HUAWEI DevEco Studio 编辑器开发鸿蒙应用时,免不了要对我们的应用程序进行代码调试。我们根据实际情况,一般会用到以下三种方式进行代码调试。 肉眼调试法注释排错调试法控制台输出法弹出提示法断…

STM32 入门教程(江科大教材)#笔记2

3-4按键控制LED /** LED.c**/ #include "stm32f10x.h" // Device headervoid LED_Init(void) {/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_I…

关系数据库:关系运算

文章目录 关系运算并(Union)差(Difference)交(Intersection)笛卡尔积(Extended Cartesian Product)投影(projection)选择(Selection)除…