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