记录一下自己用过的opencv库函数,慢慢填坑
1、I/O
1.1 图片
1.1.1 读取图片
以numpy格式存储,颜色空间为BGR
# cv2.imread(<img_path>)
img1 = cv2.imread('example.jpg')
1.1.2 转换颜色空间类型
# cv2.cvtColor(<img>, <flag>)
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) # BGR -> 灰度图
rgb1 = cv2.cvtColor(gray1, cv2.COLOR_GRAY2BGR) # 灰度图 -> BGR
常见/常用的是以下几种:
cv2.COLOR_BGR2GRAY
:BGR到灰度
cv2.COLOR_GRAY2BGR
:灰度到BGR
cv2.COLOR_BGR2RGB
:BGR到RGB
cv2.COLOR_RGB2BGR
:RGB到BGR
cv2.COLOR_BGR2HSV
:BGR到HSV
cv2.COLOR_HSV2BGR
:HSV到BGR
特别是cv2
与matplotlib
一起使用时,需要将 BGR->RGB
1.1.3 保存图片
可以保存为任意类型的图片,如jpg、png等(其他的我还没用过)
# cv2.imwrite(<example.jpg>, <img>)
cv2.imwrite('saveimg.jpg', img1)
1.1.4 改变图片尺寸
img = cv2.resize(img, (width,height))
1.2 视频
1.2.1 读取视频并处理每一帧图片
video_path = 'XXXX.mp4' # 支持多种视频格式
cap = cv2.VideoCapture(video_path)
fps = int(cap.get(5))
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
while True:
ret,frame = cap.read()
if frame is None:
break
pred = det.detect(img)
a = cv2.waitKey(int(1000/fps))
if ord('q') == a:
cap.release()
break
cap.release()
cv2.destroyAllWindows()
1.2.2 保存视频
path = 'XXXX.avi'
# 输出帧率
fps = 30
# 视频中图像的大小,要与下面写入视频的图像大小一样,否则写入的视频会出错打不开
size = (weight, height)
# 视频编码器格式 mp4——('m', 'p', '4', 'v')
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
# 多通道图像isColor=True,灰度图为False
videowriter = cv2.VideoWriter(path, fourcc, fps, size, isColor=True)
while True:
_, frame = cap.read()
# 写入视频
videowriter.write(frame)
# 释放
videowriter.release()
2、画图
2.1 展示图片
2.1.1 新建窗口
cv2.namedWindow(<Window_Name>, <flag>)
cv2.namedWindow('origin',0)
cv2.resizeWindow('origin', 900,900)
2.1.2 生成带有控制条的图片
# 创建控制条
# cv2.createTrackbar(<控制条名称>,<窗口名称>,<当前值>,<最大值>)
cv2.createTrackbar('minThreshold','edge_detection',50,1000,lambda x: x)
# 通过控制条选择参数
# minThreshold=cv2.getTrackbarPos(<控制条名称>,<窗口名称>)
minThreshold=cv2.getTrackbarPos('minThreshold','edge_detection')
代码实例
import cv2
import numpy as np
cv2.namedWindow('edge_detection',0)
cv2.resizeWindow('edge_detection',500,800)
cv2.createTrackbar('minThreshold','edge_detection',50,1000,lambda x: x)
cv2.createTrackbar('maxThreshold','edge_detection',100,1000,lambda x: x)
img_path = '/home/zxc/catkin_ws/src/camera/scripts/yutong.jpg'
img=cv2.imread(img_path,cv2.IMREAD_GRAYSCALE)
mask=np.zeros_like(img)
mask=cv2.fillPoly(mask,np.array([[[875,534],[919,534],[905,606],[855,606]]]),color=255)
masked_edge_img=cv2.bitwise_and(img,mask)
while True:
minThreshold=cv2.getTrackbarPos('minThreshold','edge_detection')
maxThreshold=cv2.getTrackbarPos('maxThreshold','edge_detection')
edges=cv2.Canny(masked_edge_img,minThreshold,maxThreshold)
cv2.imshow('edge_detection',edges)
cv2.waitKey(10)
以上代码实现了通过手动调整阈值将图像二值化并提取边界特征,可以控制bar来调节阈值。
3、关键点和描述子
关键点:位置、直径大小、方向
描述子:记录关键点周围对其有贡献的像素点的一组向量值,不受仿射变换、光照变换等影响
3.1 Harris角点
具有旋转不变性,但是缩放图片会影响Harris角点检测
dst = cv2.cornerHarris(img_gray, blockSize, ksize, k)
# blocksize:角点检测窗口大小,窗口越大敏感性越高,默认值3
# ksize:sobel算子卷积核大小
# k:权重系数,经验值,一般取0.02~0.04之间,默认值0.04
img = cv2.imread('xxx.jpg')
# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dst = cv2.cornerHarris(gray, blockSize, ksize, k)
img[dst>0.01*dst.max()] = [0,0,255]
cv2.imshow('img',img)
cv2.waitKey(0)
3.2 Shi-Tomasi角点
是Harris的改进,不需要自己设权重系数
cv2.goodFeaturesToTrack(img_gray,maxCorners,)
# maxCorners: 角点的最大数量
# qualityLevel: 角点质量,一般在0.01~0.1之间
# minDistance:角点间最小欧式距离,小于该值会被过滤
# mask:感兴趣区域
# blockSize:检测窗口大小
# useHarrisDetector:是否使用Harris算法,默认为False
# k:Harris检测权重系数
maxCorners = 1000
ql = 0.01
minDistance = 10
corners = cv2.goodFeaturesToTrack(gray,maxCorners,ql,minDistance)
# float32 -> int64
corners = corners.astype(np.int0)
for corner in corners:
x,y = corner.ravel()
cv2.circle(img,(x,y),3,(0,0,255),-1)
cv2.imshow('img',img)
cv2.waitKey(0)
3.3 SIFT关键点检测和描述子计算
具有尺度不变性
# 检测关键点
# sift.detect(img_gray,mask)
sift = cv2.SIFT_create()
kp = sift.detect(gray,None)
sift.drawKeypoints(gray, kp, img)
cv2.imshow('img',img)
# 计算描述子
kp, des = sift.compute(img, kp)
# 同时计算关键点和描述子
kp, des = sift.detectAndCompute(img_gray, mask)
3.4 SURF
加速的SIFT
surf = cv2.xfeatures2d.SURF _create()
# 同时计算关键点和描述子
kp, des = surf.detectAndCompute(img_gray, mask)
3.5 ORB
Oriented FAST and Rotated BRIEF
FAST:特征点的实时检测,但没有方向
BRIEF:一种快速计算的描述子,但对图像旋转不友好
orb = cv2.ORB_create()
# 同时计算关键点和描述子
kp, des = orb.detectAndCompute(img_gray, mask)
# 画关键点
cv2.drawKeypoints(gray, kp, img)
# 先用FAST计算关键点,再计算ORB描述子
fast = cv2.FastFeatureDetector_create()
kp = fast.detect(img_gray, mask)
kp, des = orb.compute(img_gray, kp)
3.6 BFMatcher 暴力匹配
# 创建匹配器
bf = BFMatcher(normType, crossCheck)
# normType:匹配项,NORM_L1,NORM_L2,NORM_HAMMING(ORB用这个)
# crossCheck:交叉验证,图1->图2,图2->图1,比较是否是同一对点,默认为False
# 特征匹配
matches = bf.match(des1,des2)
# 绘制匹配点
img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches, None)
3.7 FLANN 匹配
匹配速度快,但使用邻近近似值,所以精度比暴力匹配差
# 创建匹配器
index_params = dict(algorithm=FLANN_INDEX_KDTREE,trees=5)
# 匹配算法:KDTREE(SIFT用),LSH(ORB用)
search_params = dict(checks=50) # 一般是trees的10倍
flann = cv2.FlannBasedMatcher(index_params, search_params)
# 特征匹配
matches = flann.match(des1,des2)
# 绘制匹配点
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches, None)
# K邻近匹配,BF也可以用该方法
matches = flann.knnMatch(des1, des2, k) # k邻近匹配,一般选2,之后需要进行筛选
good = []
for i, (m,n) in enumerate(matches):
if m.distance < 0.7*n.distance:
good.append(m)
# 绘制匹配点
img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, [good], None)
关键点的属性统一写在这里:
kp:<class KeyPoint>
,包括以下属性:
KeyPoint.pt 坐标(*最常用的)
KeyPoint.size 直径大小
KeyPoint.angle 方向
KeyPoint.response 响应强度
KeyPoint.octave 金字塔组和层数
KeyPoint.class_id 类别标识
匹配对的属性统一写在这里:
match:<class DMatch>
DMatch.queryIdx 第一幅图像中特征点的索引
DMatch.trainIdx 第二幅图像中特征点的索引
DMatch.distance 两个特征点的距离
如果是KNN匹配,则matches是一个包含k个<class DMatch>
的列表
4、坐标变换
4.1、变换矩阵
# 计算多个二维点对或者图像之间的最优仿射变换矩阵2*3
# H是src图像向dst图像变换的矩阵
# 注意这里的pts是包含点坐标的列表,如果是提取的关键点,需要用.pt获取坐标
H, _ = cv2.estimateAffinePartial2D(src_pts,dst_pts, cv2.RANSAC)
# 计算3对二维点对之间的仿射变换矩阵2*3
H = getAffineTransform(src_pts,dst_pts)
# 计算多个二维点对或者图像之间的最优透射变换矩阵3*3
H, _ = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC)
# 计算4对二维点对之间的透射变换矩阵3*3
H = getPerspectiveTransform()
5、特殊功能
5.1 鼠标点击响应
# cv2.setMouseCallback(<windows_name>, <function_name>)
cv2.setMouseCallback("image", on_EVENT_LBUTTONDOWN)
def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
# 左键点击功能
elif event == cv2.EVENT_RBUTTONDOWN:
#右键点击功能
elif event == cv2.EVENT_MBUTTONDOWN:
#滚轮点击功能