OpenCV中的图像基本操作--B站视频教程笔记(六)

在学习B站教学视频的时候记录的笔记

OpenCV+TensorFlow】迪哥带你做项目!深度学习+计算机视觉实战 纯实战教学 技能点加满


6.1 Canny边缘检测

  • 1)使用高斯滤波器,以平滑图像,滤除噪声。

  • 2)计算图像中每个像素点的梯度强度和方向。

  • 3)应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。

  • 4)应用双阈值(Double-Threshold)检测来确定真是的和潜在的边缘。

  • 5)通过抑制鼓励的弱边缘最终完成边缘检测。

1 :高斯滤波器

 过程参考之前的滤波计算过程。 

2:梯度和方向

使用的算子是Sobel算子

 3:非极大值抑制

假设在人脸识别的时候出现了ABC 3个结果,确定性各不相同。那么在保留确定性最大的A,放弃相对小的BC就是非极大值抑制。如图:

4:双阈值检测

  • 对于A点的梯度值大于maxVal就会认为A是边界。

  • 对于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.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图像轮廓

cv2.findContours(img,mode,method)

img : 待测试图像

mode : 轮廓检索模式

  • RETR_EXTERNAL:只检索最外面的轮廓;

  • RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;

  • RETR_CCOMP : 检索所有的轮廓,并将它们的组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;

  • RETR_TREE: 检索所有的轮廓,并重构嵌套轮廓的整个层次;(最为常用)

method:轮廓逼近方法

  • CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有的其他方法输出多边形(顶点的序列)

  • CHAIN_APPROX_SIMPLE:压缩水平的,垂直和斜的部分,也就是,函数只保留他们的终点部分。

 左侧图像为CHAIN_APPROX_NONE,描述会4条边界,为了进一步减少描述信息的内容。

右侧图像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.drawContours(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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值