opencv 基础 基础 读取图片与展示 img = cv2.imread('yahboom.jpg', 0) cv2.IMREAD_UNCHANGED：保持原格式不变，-1； cv2.IMREAD_GRAYSCALE：以灰度模式读入图片，可以用0表示； cv2.IMREAD_COLOR：，读入一副彩色图片，可以用1表示； cv2.IMREAD_UNCHANGED：读入一幅图片，并包括其alpha通道，可以用2表示。 cv.imshow('frame', frame) 图片写入 cv2.imwrite('new_img_name', img) 摄像头读取与显示视频 capture=cv.VideoCapture(0) 参数是0，表示打开笔记本的内置摄像头，参数是视频文件路径则打开视频 ret,img = frame.read() 移动与缩放 图片缩放 cv2.resize(InputArray src,OutputArray dst, Size, fx, fy, interpolation) interpolation：插入方式，可选择 INTER_NEAREST（最近邻插值）， INTER_LINEAR（双线性插值（默认设置））， INTER_AREA（使用像素区域关系进行重采样）， INTER_CUBIC（4x4像素邻域的双三次插值）， INTER_LANCZOS4（8x8像素邻域的Lanczos插值） 图片剪切 dst = img[0:100,100:200] 图片平移 cv2.warpAffine(src, M, dsize[,dst[, flags[, borderMode[,borderValue]]]]) , M：变换矩阵, 作为仿射变换矩阵，一般反映平移或旋转的关系，为InputArray类型的2×3的变换矩阵。，只设置前三个参数的情况下，如cv2.warpAffine(img,M,(rows,cols))就可以实现基本的仿射变换效果。 dsize：输出图像的大小 flags：插值方法的组合（int 类型！） borderMode：边界像素模式（int 类型！） borderValue：（重点！）边界填充值; 默认情况下，它为0 matShift = np.float32([[1,0,10],[0,1,10]])# 2*3 dst = cv2.warpAffine(img, matShift, (width,height)) 图片镜像 for i in range(0,height): for j in range(0,width): dst[i,j] = img[i,j] dst[height*2-i-1,j] = img[i,j] 图像处理 图像灰度化处理 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 图像二值化处理 cv2.threshold（src, threshold, maxValue,thresholdType） threshold：当前阈值 maxVal：最大阈值，一般为255 thresholdType：阈值类型，一般有下面几个值， THRESH_BINARY = 0，#大于阈值的像素点的灰度值设定为maxValue(如8位灰度值最大为255)，灰度值小于阈值的像素点的灰度值设定为0。 THRESH_BINARY_INV = 1，#大于阈值的像素点的灰度值设定为0，而小于该阈值的设定为maxValue。 THRESH_TRUNC = 2，#大于阈值的像素点的灰度值设定为0，而小于该阈值的设定为maxValue。 THRESH_TOZERO = 3，#像素点的灰度值小于该阈值的不进行任何改变，而大于该阈值的部分，其灰度值全部变为0。 THRESH_TOZERO_INV = 4 #像素点的灰度值大于该阈值的不进行任何改变，像素点的灰度值小于该阈值的，其灰度值全部变为0。 返回值： retval：与参数thresh一致3 dst： 结果图像 img = cv2.imread('yahboom.jpg') gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret,thresh1=cv2.threshold(gray,180,255,cv2.THRESH_BINARY_INV) 图像边缘检测 Canny边缘检测算法可以分为以下5个步骤： 使用高斯滤波器，以平滑图像，滤除噪声 计算图像中每个像素点的梯度强度和方向 应用非极大值（Non-Maximum Suppression）抑制，以消除边缘检测带来的杂散响应 应用双阈值（Double-Threshold）检测来确定真实的和潜在的边缘 通过抑制孤立的弱边缘最终完成边缘检测 opencv实现步骤: 图像灰度化：gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 高斯过滤（减噪处理）图像：GaussianBlur（src，ksize，sigmaX [，dst [，sigmaY [，borderType]]]）-> dst src：输入的图像，一般是灰度后的图片 ksize：高斯内核大小 sigmaX ：X方向上的高斯核标准偏差 sigmaY ：Y方向上的高斯核标准差 dst：处理后的图像 Canny方法处理得到图像：edges=cv2.Canny( image, threshold1, threshold2[, apertureSize[,L2gradient]]) edges：计算得到的边缘图像 image ：计算得到的边缘图像，一般是高斯处理后得到的图像 threshold1 ：处理过程中的第一个阈值 threshold2 ：处理过程中的第二个阈值 apertureSize ：Sobel 算子的孔径大小 L2gradient ：计算图像梯度幅度（gradient magnitude）的标识默认值为 False。如果为 True，则使用更精确的 L2 范数进行计算（即两个方向的导数的平方和再开方），否则使用 L1 范数（直接将两个方向导数的绝对值相加）。 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) imgG = cv2.GaussianBlur(gray,(3,3),0) dst = cv2.Canny(imgG,50,50) 线段绘制 cv2.line（dst，pt1，pt2，color，thickness=None，lineType=None，shift=None） pt1，pt2：必选参数。线段的坐标点，分别表示起始点和终止点 color：必选参数。用于设置线段的颜色 thickness：可选参数。用于设置线段的宽度 lineType：可选参数。用于设置线段的类型，可选8（8邻接连接线-默认）、4（4邻接连接线）和 cv2.LINE_AA 为抗锯齿 line = cv2.line(img, (50,20), (20,100), (255,0,255), 10) 绘制矩形 cv2.rectangle（img，pt1，pt2，color，thickness=None，lineType=None，shift=None） pt1，pt2：必选参数。矩形的顶点，分别表示顶点与对角顶点，即矩形的左上角与右下角（这两个顶点可以确定一个唯一的矩形），可以理解成是对角线。 color：必选参数。用于设置矩形的颜色 thickness：可选参数。用于设置矩形边的宽度，当值为负数时，表示对矩形进行填充 lineType：可选参数。用于设置线段的类型，可选8（8邻接连接线-默认）、4（4邻接连接线）cv2.LINE_AA 为抗锯齿 rect = cv2.rectangle(img, (50,20), (100,100), (255,0,255), 10) 绘制圆形 cv2.circle(img, center, radius, color[,thickness[,lineType]]) circle = cv2.circle(img, (80,80), 50, (255,0,255), 10) 绘制椭圆 cv2.ellipse(img, center, axes, angle, StartAngle, endAngle, color[,thickness[,lineType]) center：椭圆的中心点，（x，y） axes：指的是短半径和长半径，（x，y） StartAngle：圆弧起始角的角度 endAngle：圆弧终结角的角度 img、color、thickness、lineType可以参考圆的说明 ellipse = cv2.ellipse(img, (80,80), (20,50),0,0, 360,(255,0,255), 5) 绘制多边形 cv2.polylines(img,[pts],isClosed, color[,thickness[,lineType]]) pts：多边形的顶点 isClosed：是否闭合。（True/False） 其他参数参照圆的绘制参数 points = np.array([[120,50], [40,140], [120,70], [110,110], [50,50]],np.int32) polylines = cv2.polylines(img, [points],True,(255,0,255), 5) 绘制文字 cv2.putText(img, str, origin, font, size,color,thickness) origin：左上角坐标(整数)，可以理解成文字是从哪里开始的 cv2.putText(img,'This is Yahboom!',(50,50),cv2.FONT_HERSHEY_SIMPLEX,1,(0,200,0),2) 图片增强 修复图片 dst = cv2.inpaint(src, inpaintMask, inpaintRadius, flags) inpaintMask：二进制掩码，指示要修复的像素。 inpaintRadius：表示修复的半径 flags : 修复算法，主要有INPAINT_NS (Navier-Stokes based method) or INPAINT_TELEA (Fastmarching based method) paint = np.zeros((height,width,1),np.uint8) for i in range(50,100): paint[i,50] = 255 paint[i,50+1] = 255 paint[i,50-1] = 255 for i in range(100,150): paint[150,i] = 255 paint[150+1,i] = 255 paint[150-1,i] = 255 dst_img = cv2.inpaint(dam_img,paint,3,cv2.INPAINT_TELEA) 图片亮度增强 实际上就是遍历每个像素点，给他们加减数值 图片磨皮美白 图片磨皮美白的功能，实现的原理和“1.20 OpenCV图片亮度增强”的原理基本上是一样的，只不过这里我们不需要对r值做处理，只需要按照这个公式，p = p(x)*1.4+ y，其中p(x)表示b通道或者g通道，y表示需要增减的数值，同样的，加了数值后，我们需要对数值做判断。 dst = np.zeros((height,width,3),np.uint8) for i in range(0,height): for j in range(0,width): (b,g,r) = img[i,j] bb = int(b*1.4) + 5 gg = int(g*1.4) + 5 if bb > 255: bb = 255 if gg > 255: gg = 255 dst[i,j] = (bb,gg,r) ROS+opencv应用 ROS 以自己的sensor_msgs/Image消息格式传递图像，需要通过 CvBridge , 才能使用 Opencv. Astra相机, docker 中使用 ros2 launch astra_camera astro_pro_plus.launch.xml 启动相机 ros2 topic list ros2 topic echo /camera/color/image_raw 查看彩色数据, encoding: rgb8 --- header: stamp: sec: 1739503563 nanosec: 480957647 frame_id: camera_color_optical_frame height: 480 width: 640 encoding: rgb8 is_bigendian: 0 step: 1920 data: 20 ros2 topic echo /camera/depth/image_raw, encoding: 16UC1 --- header: stamp: sec: 1739503754 nanosec: 710306216 frame_id: camera_depth_optical_frame height: 480 width: 640 encoding: 16UC1 is_bigendian: 0 step: 1280 data: 0 0 订阅RGB图像话题信息并且显示RGB图像 ros2 run yahboomcar_visual astra_rgb_image 显示彩色摄像头图片。 ros2 run rqt_graph rqt_graph 查看节点通讯图 # /root/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_visual/yahboomcar_visual/astra_rgb_image.py #导入opecv库以及cv_bridge库 import cv2 as cv from cv_bridge import CvBridge # class AstraRGBImage(Node): #创建CvBridge对象 self.bridge = CvBridge() #定义一个订阅者订阅深度相机节点发布的RGB彩色图像话题数据 self.sub_img = self.create_subscription(Image,'/camera/color/image_raw',self.handleTopic,100) #msg转换成图像数据，这里的bgr8是图像编码格式 frame = self.bridge.imgmsg_to_cv2(msg, "bgr8") 订阅Depth图像话题信息并且显示Depth图像 ros2 run yahboomcar_visual astra_depth_image RGB彩色图像显示节点 ros2 run rqt_graph rqt_graph 查看节点通讯图 # /root/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_visual/yahboomcar_visual/astra_depth_image.py #导入opecv库以及cv_bridge库 import cv2 as cv from cv_bridge import CvBridge #创建CvBridge对象 self.bridge = CvBridge() #定义一个订阅者订阅深度相机节点发布的Depth深度图像话题数据 self.sub_img = self.create_subscription(Image,'/camera/depth/image_raw',self.handleTopic,10) #msg转换成图像数据，这里的32FC1是图像编码格式 frame = self.bridge.imgmsg_to_cv2(msg, "32FC1") 订阅图像数据然后发布转换后的图像数据 ros2 run yahboomcar_visual pub_image ros2 run rqt_graph rqt_graph ros2 run rqt_image_view rqt_image_view 用rqt_image_view工具查看图像 # /root/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_visual/yahboomcar_visual/pub_image.py #导入opecv库以及cv_bridge库 import cv2 as cv from cv_bridge import CvBridge #创建CvBridge对象 self.bridge = CvBridge() #定义一个订阅者订阅usb图像话题数据 self.sub_img = self.create_subscription(Image,'/image_raw',self.handleTopic,500) #定义了图像话题数据发布者 self.pub_img = self.create_publisher(Image,'/image',500) #msg转换成图像数据imgmsg_to_cv2，这里的bgr8是图像编码格式 frame = self.bridge.imgmsg_to_cv2(msg, "bgr8") #图像数据转换的图像话题数据(cv2_to_imgmsg)然后发布出去 msg = self.bridge.cv2_to_imgmsg(frame, "bgr8") self.pub_img.publish(msg) 二维码创建与识别 安装包, libzbar-dev 提供二维码和条形码的解码功能; pyzbar 解码二维码和条形码, 依赖于 ZBar 库（libzbar）来实现解码功能; qrcode 用于生成二维码。 python3 -m pip install qrcode pyzbar sudo apt-get install libzbar-dev 二维码生成 # cd /root/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_visual/simple_qrcode/ # python QRcode_Create.py #创建qrcode对象 qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_H, box_size=5, border=4,) #qrcode二维码添加logo my_file = Path(logo_path) if my_file.is_file(): img = add_logo(img, logo_path) #添加数据 qr.add_data(data) # 填充数据 # fill data qr.make(fit=True) # 生成图片 # generate images img = qr.make_image(fill_color="green", back_color="white") 二维码识别 # cd /root/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_visual/simple_qrcode/ # python QRcode_Parsing.py def decodeDisplay(image, font_path): gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) # 需要先把输出的中文字符转换成Unicode编码形式 barcodes = pyzbar.decode(gray) for barcode in barcodes: # 提取二维码的边界框的位置 (x, y, w, h) = barcode.rect # 画出图像中条形码的边界框 cv.rectangle(image, (x, y), (x + w, y + h), (225, 0, 0), 5) encoding = 'UTF-8' # 画出来，就需要先将它转换成字符串 barcodeData = barcode.data.decode(encoding) barcodeType = barcode.type # 绘出图像上数据和类型 pilimg = Image.fromarray(image) # 创建画笔 draw = ImageDraw.Draw(pilimg) # 参数1：字体文件路径，参数2：字体大小 fontStyle = ImageFont.truetype(font_path, size=12, encoding=encoding) # 参数1：打印坐标，参数2：文本，参数3：字体颜色，参数4：字体 draw.text((x, y - 25), str(barcode.data, encoding), fill=(255, 0, 0),font=fontStyle) # PIL图片转cv2 图片 image = cv.cvtColor(np.array(pilimg), cv.COLOR_RGB2BGR) # 向终端打印条形码数据和条形码类型 print("[INFO] Found {} barcode: {}".format(barcodeType, barcodeData)) return image barcodes = pyzbar.decode(gray) 解码并生成解码后的数组 AR视觉 ros2 run rqt_image_view rqt_image_view 查看发布的图片