学习B站教学视频时记录的笔记
OpenCV TensorFlow】迪哥带你去做项目!深度学习! 计算机视觉实战 纯实战教学 技能点加满
6.1 Canny边缘检测
-
1)使用高斯滤波器平滑图像,过滤噪音。
-
2)计算图像中每个像素点的梯度强度和方向。
-
3)应用非极大值(Non-Maximum Suppression)抑制边缘检测引起的杂散响应。
-
4)应用双阈值(Double-Threshold)检测来确定真是的和潜在的边缘。
-
5)边缘检测最终通过抑制鼓励的弱边缘完成。
过程参考以前的滤波计算过程。
使用的算子是Sobel算子
假设人脸识别时出现了假设ABC 三个结果三个结果而异。然后保留最大的确定性A,放弃相对较小的BC是非极大值抑制。如图所示:
-
A点的梯度值大于A点maxValA是边界。
-
对于D小于minVal然后放弃D点。(图中没有画出来,可以想象D位于minVal红线以下)
-
对于BC当点小于maxVal且大于minVal比如C点。然后分析具体情况。如果C点可以连接到A点,则保留。如果是B,不能连接A,就放弃。
minVal设置越小,条件越低,通过筛选的点越多。
maxVal设置越大,条件越低,通过筛选的点越多。
#Canny img = cv2.imread('H:\Peronal\lena.jpg',cv2.IMREAD_GRAYSCALE) v1 = cv2.Canny(img,80,150) v2 = cv2.Canny(img,50,100) res = np.hstack((v1,v2)) cv2.imshow('res',res) cv2.waitKey(0) cv2.destroyAllWindows()
左侧是80-150 右侧是50-100
以car.jpg例如,代码如下:
#Canny img = cv2.imread('H:\Peronal\car.png',cv2.IMREAD_GRAYSCALE) v1 = cv2.Canny(img,130,250) v2 = cv2.Canny(img,50,100) res = np.hstack((v1,v2)) cv2.imshow('res',res) cv2.waitKey(0) cv2.destroyAllWindows()
区别还是很明显的,左边130-250,右边50-100,右边边界明显更大。
6.2 图像金字塔
-
高斯金字塔
-
拉普拉斯金字塔
图像可以处理成不同尺寸的图像。
layer0 : 800x800
layer1 : 400x400
layer2 : 200x200
layer3: 100x100
layer4 : 50x50
在后续处理过程中,每层都可以提取特征,每层的特征提取结果很可能不同。
6.2.1 高斯金字塔
制作金字塔的方法:
在示意图上理解向下采样是向上的过程。
首先创建卷积核,然后过滤图像,最后去除所有偶数线和列。
在示意图上理解向上采样是向下的过程。
向上采样过程:
1将图像在每个方向扩展到原来的两倍,新行列以0填充。
2 使用相同的内核(乘以4)和放大的图像卷积获得近似值。
代码如下:
# 高斯金字塔 img = cv2.imread('H:\Peronal\AM.png') cv2.imshow('img',img) img.shape up = cv2.pyrUp(img) cv2.imshow('up',up) up.shape down = cv2.pyrDown(img) cv2.imshow('down',down) cv2.waitKey(0) cv2.destroyAllWindows() down.shape
左边是原始图像,中间是上采样,右边是下采样。尺寸的变化很明显。
注:上采样,下采样可连续执行多次。
img = cv2.imread('H:\Peronal\AM.png') up = cv2.pyrUp(img) down = cv2.pyrDown(up) res = np.hstack((img,down)) cv2.imshow('res',res) cv2.waitKey(0) cv2.destroyAllWindows()
连续采样后,虽然尺寸相同,但清晰度大大降低。
6.2.拉普拉斯金字塔
与高斯金字塔类似,拉普拉斯金字塔也是多层的,每层都是通过相同的公式计算出来的。公式如下:
Gi 为输入图像(img)
代码如下:
down = cv2.pyrDown(img) down_up = cv2.pyrUp(down) l_1 = img-down_up cv2.imshow('l_1',l_1) cv2.waitKey(0) cv2.destroyAllWindows()
6.3图像轮廓
img : 待测试图像
mode : 轮廓检索模式
-
RETR_EXTERNAL:只检索外轮廓;
-
RETR_LIST:检索所有轮廓,并将其保存在链表中;
-
RETR_CCOMP : 对所有轮廓进行检索,并将其组织成两层:顶层分的外界,第二层是空界;
-
RETR_TREE: 检索所有轮廓,重构嵌套轮廓的整个层次;(最常用)
method:轮廓接近法
-
CHAIN_APPROX_NONE:以Freeman链码输出轮廓,所有其他方法输出多边形(顶点序列)
-
CHAIN_APPROX_SIMPLE:垂直和倾斜的压缩部分,即函数只保留其终点部分。
左侧图像为CHAIN_APPROX_NONE,为了进一步减少描述信息的内容,描述会有四个边界。
右侧图像CHAIN_APPROX_SIMPLE只保留了4个角点。
轮廓检测步骤:
1)使用二值图像以提高准确性。
img= cv2.imread('H:\Peronal\contours.png') gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) cv_show(thresh,'thresh')
注意:cv2.threshold 高级版本返回2个值(4.5.5返回2),低级版返回3个值。
图像、轮廓、轮廓索引、颜色模式、线条厚度
#注意需要copy,否则原图会变 draw_img = img.copy() res = cv2.rawContours(draw_img,contours,-1,(0,0,255),2)
cv_show(res,'res')
cv2.drawContours(img,contours,index,color,thinkness)
-
img:参数是指明在哪幅图像上绘制轮廓;image为三通道才能显示轮廓
-
contours:参数是轮廓本身,在Python中是一个list;
-
index:参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。后面的参数很简单。
-
color:绘制轮廓的笔刷颜色
-
thinkness:表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。
当index=0时,为左下方三角形的内圈。如图:
index=1时,为左下方三角形的外圈。如图:
cv2.contourArea(contour)
首先选定要计算的边界,然后获取面积数值,代码如图:
cnt = contours[0]
cv2.contourArea(cnt)
cv2.arcLength(cnt,bool)
-
cnt 边界
-
bool: 是否为闭合边界,True为闭合
首先选定要计算的边界,然后获取面积数值,代码如图:
cnt = contours[0]
cv2.arcLength(cnt,True)
假设求弧线AB的近似,首先取弧线AB上一点C使得C到直线AB距离最大,距离值为d。当d<阈值T的时候直线AB就是弧线AB的近似。
如果d>T,则画辅助线连接AC在弧线AC上找D使得D到直线AC的距离最大,距离为e。如果e<T完成弧线AC的近似求解。重复上述步骤,直至全部弧线近似求解全部完成。
代码如下:
img= cv2.imread('H:\Peronal\contours2.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
#新版本返回2个值
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
draw_img = img.copy()
res = cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)
cv_show(res,'res')
近似函数cv2.approxPolyDP(cnt,epsilon,bool)
-
cnt 轮廓
-
epsilon 距离阈值(通常是周长的百分比)
-
bool 是否是封闭轮廓
epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
draw_img = img.copy()
res = cv2.drawContours(draw_img,[approx],-1,(0,0,255),2)
cv_show(res,'res')
注意:
阈值设置的越小,轮廓越接近轮廓实际形状。
阈值设置的越大,减少计算量,满足确定轮廓大致行形状即可。
进一步,可以用这种方式做轮廓的外接形状,如:外接矩形,外接圆,外接椭圆等等。
cv2.boundingRect(cnt)
-
cnt 轮廓
img= cv2.imread('H:\Peronal\contours.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv_show(img,'img')
计算轮廓与外接矩形面壁比
area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area
print('轮廓面积与外接矩形面积比',extent)
轮廓面积与外接矩形面积比 0.5154317244724715