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 查看发布的图片

发表评论