OpenCv基础(四)
文章目录
六、形态学
-
指一系列处理图像形状特征的图像处理技术
-
基本思想是利用一种特殊的结构元(即卷积核)来测量或提取输入图像中相应的形状或特征,以便进一步进行图像分析和目标识别
-
形态学基本操作:
-
膨胀和腐蚀
-
开运算
-
闭运算
-
顶帽
-
黑帽
-
6.1 图像二值化
-
上述处理方法基本上是对二值图像进行处理;
-
threshold(src,thresh,maxval,type)
二值化处理src:
最好是灰度图thresh:
阈值maxval:
最大值,最大值不一定是255type:
操作类型- 常见的操作类型:THRESH_BINARY、THRESH_BINARY_INV、THRESH_TRUNC、THRESH_TOZERO、THRESH_TOZERO_INV
import cv2
img = cv2.imread('../my_work/01.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 返回2个值,一个是阈值ret,一个是处理后的图片dst
ret,dst = cv2.threshold(gray,120,255,cv2.THRESH_BINARY)
cv2.imshow('dst',cv2.hconcat((gray,dst)))
cv2.waitKey()
cv2.destroyAllWindows()
adaptiveThreshold(src,maxValue,adaptiveMethod,thresholdType,blockSize,C,dst=None)
自适应阈值二值化adaptiveMethod:
计算阈值的方法cv2.ADPTIVE_THRESH_MEAN_C:
阈值取自相邻区域的平均值cv2.ADPTIVE_THRESH_GAUSSIAN_C:
阈值取自相邻区域的加权和,权重为一个高斯窗口
block size:
领域大小C:
一个常数,阈值等于平均值或加权平均值减去这个常数
- 此时的阈值是根据图像上的每一个小区域计算与其对应的阈值
import cv2
img = cv2.imread('../my_work/01.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 返回2个值,一个是阈值,一个是处理后的图片
dst = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,blockSize=3,C=1.5)
cv2.imshow('dst',cv2.hconcat((gray,dst)))
cv2.waitKey()
cv2.destroyAllWindows()
6.2 腐蚀操作
-
用卷积核扫描图像,但腐蚀操作的卷积核一般都是1,如果卷积核内所有像素点都是白色,那么锚点即为白色
-
erode(src,kernel[,dst[,anchor[,iterations[,borderType[,borderValue]]]]])
iterations:
腐蚀迭代次数,次数越多,腐蚀效果越明显
import cv2
import numpy as np
img = cv2.imread('../my_work/01.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
kernel = np.ones((3,3))
dst = cv2.erode(gray,kernel,iterations=2)
cv2.imshow('dst',cv2.hconcat((gray,dst)))
cv2.waitKey()
cv2.destroyAllWindows()
- 在上述操作中,卷积核要自己定义;
- OpenCv中有获取卷积核的API
getStructuringElement(shape,ksize[,anchor])
shape:
卷积核的形状,不是长宽,是卷积核中1形成的形状MORPH_RECT:
卷积核中的1是矩形,常用MORPH_ELLIPSE:
椭圆MORPH_CROSS:
十字
ksize:
卷积核尺寸
import cv2
img = cv2.imread('../my_work/01.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
print(kernel)
dst = cv2.erode(gray,kernel,iterations=2)
cv2.imshow('dst',cv2.hconcat((gray,dst)))
cv2.waitKey()
cv2.destroyAllWindows()
6.3 膨胀操作
-
与腐蚀操作相反,基本原理是保证卷积核的锚点是非0值,周边无论是0还是非0值,都变成非0值
-
dilate(img,kernel,iterations)
import cv2
img = cv2.imread('../my_work/01.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
print(kernel)
dst = cv2.dilate(gray,kernel,iterations=1)
cv2.imshow('dst',cv2.hconcat((gray,dst)))
cv2.waitKey()
cv2.destroyAllWindows()
6.4 开运算和闭运算
- 开运算=腐蚀之后+膨胀
- 闭运算=膨胀之后+腐蚀
morphologyEx(img,op,kernel...)
op:
MORPH_OPEN:
表示形态学开运算MORPH_CLOSE:
表示形态学闭运算MORPH_GRADIENT:
表示形态学梯度
kernel:
如果噪点比较多,会选择大一点的kernel
import cv2
img = cv2.imread('../my_work/02.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
# 开运算
dst = cv2.morphologyEx(gray,cv2.MORPH_OPEN,kernel,iterations=2)
# 闭运算
dst2 = cv2.morphologyEx(gray,cv2.MORPH_CLOSE,kernel)
cv2.imshow('dst',cv2.hconcat((gray,dst)))
cv2.imshow('dst2',cv2.hconcat((gray,dst2)))
cv2.waitKey()
cv2.destroyAllWindows()
6.5 形态学梯度
-
形态学梯度=膨胀-腐蚀
-
腐蚀之后原图边缘变小了,梯度就可以得到腐蚀掉的部分,即边缘
-
morphologyEx(img,op,kernel...)
op:
MORPH_GRADIENT:
表示形态学梯度
import cv2
img = cv2.imread('../my_work/01.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
dst = cv2.morphologyEx(gray,cv2.MORPH_GRADIENT,kernel,iterations=2)
cv2.imshow('dst',cv2.hconcat((gray,dst)))
cv2.waitKey()
cv2.destroyAllWindows()
6.6 顶帽与黑帽
-
顶帽=原图-开运算
- 开运算效果是去除图像外的噪点,顶帽得到了去掉的噪点
-
黑帽=闭运算-原图
- 闭运算可以将图形内部的噪点去掉,黑帽就是得到图像内部的噪点
import cv2
img = cv2.imread('../my_work/02.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
# 顶帽
dst = cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,kernel,iterations=1)
# 黑帽
dst2 = cv2.morphologyEx(gray,cv2.MORPH_BLACKHAT,kernel,iterations=1)
cv2.imshow('dst',cv2.hconcat((gray,dst)))
cv2.imshow('dst2',cv2.hconcat((gray,dst2)))
cv2.waitKey()
cv2.destroyAllWindows()
七、图像轮廓
-
轮廓:具有相同颜色或灰度的曲线或直线
-
轮廓的作用:图形分析、物体的识别和检测
- 注意:为了检测的准确性,需要先对图像进行二值化或canny操作
-
画轮廓时会修改输入的图像,如果之后要继续用原始图像,应将原始图像预存在其他变量
7.1 查找轮廓
findContours(image,mode,method[,contours[,hierarchy[,offset]]])
mode:
查找轮廓模式RETR_EXTERNAL = 0 :
表示只检测外围轮廓RETR_EXTERNAL = 1 :
检测的轮廓不建立等级关系,表示检测所有轮廓RETR_EXTERNAL = 2 :
每层最多两级,从小到大,从里到外RETR_EXTERNAL = 3 :
按照树型存储轮廓,从小到大,从右向左
mothod
:轮廓近似方法,也叫ApproximationMode
CHAIN_APPROX_NONE:
保存所有轮廓上的点CHAIN_APPROX_SIMPLE:
只保存角点,比如四边形,只保留四边形的4个角,存储信息少,比较常用
- 返回contours和hierarchy,即轮廓和层级
import cv2
img = cv2.imread('../my_work/02.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 二值化
ret,binary = cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
# 返回轮廓与层级
contours,hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# 打印轮廓,contours是元组
print(type(contours))
print(contours)
cv2.waitKey()
cv2.destroyAllWindows()
7.2 绘制轮廓
drawContours(image,contours,contourldx,color[,thickness[,lineType[,hierarchy[,maxLevel[,offset]]]]])
image:
要绘制在哪个图像上contours:
轮廓点contourldx:
要绘制的轮廓的编号,-1表示绘制所有轮廓color:
轮廓的颜色(0,0,255)表示红色thickness:
线宽,-1表示全部填充
import cv2
import numpy as np
img = cv2.imread('../my_work/01.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 二值化
ret,binary = cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
# 返回轮廓与层级
contours,hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img_copy = img.copy()
# 绘制轮廓
cv2.drawContours(img_copy,contours,-1,(0,0,255),2)
cv2.imshow('dst',img_copy)
cv2.waitKey()
cv2.destroyAllWindows()
7.3 轮廓的面积与周长
- 轮廓面积是指每个轮廓所有像素点围成区域的面积,单位为像素
contourArea(contour):
轮廓面积contour:
为某个轮廓,例如contours[0]、contours[1]………
arcLength(curve,closed):
轮廓周长curve:
即轮廓closed:
是否是闭合的轮廓
import cv2
img = cv2.imread('../my_work/01.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 二值化
ret,binary = cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
# 返回轮廓与层级
contours,hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img_copy = img.copy()
cv2.drawContours(img_copy,contours,-1,(0,0,255),2)
# 计算面积
area = cv2.contourArea(contours[0])
print(area)
# 计算周长
perimeter = cv2.arcLength(contours[0],closed=True)
print(perimeter)
cv2.imshow('dst',img_copy)
cv2.waitKey()
cv2.destroyAllWindows()
7.4 多边形逼近与凸包
-
findContours
后的轮廓信息contours可能过于复杂不平滑,可以用approxPolyDP
函数对该多边形曲线近似 -
approxPolyDP
函数就是用多边形去逼近轮廓,采用DP算法- DP算法原理:不断找多边形最远的点加入形成新的多边形,直到最短距离小于指定精度
approxPolyDP(curve,epsilon,closed[,approxCurve])
curve:
要近似的轮廓,例如contours[0]、contours[1]………epsilon:
即DP算法使用的阈值closed:
轮廓是否闭合
-
凸包是指简单的将原有轮廓完全包含
-
convexHull(points[,hull[,clockwise[,returnPoints]]])
points:
即轮廓clockwise:
顺时针绘制
import cv2
img = cv2.imread('../my_work/01.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 二值化
ret,binary = cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
# 返回轮廓与层级
contours,hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img_copy = img.copy()
# 绘制轮廓
cv2.drawContours(img_copy,contours,-1,(0,0,255),2)
# 多边形近似轮廓
approx = cv2.approxPolyDP(contours[0],20,True)
cv2.drawContours(img_copy,[approx],0,(0,255,0),2)
# 凸包
hull = cv2.convexHull(contours[0])
cv2.drawContours(img_copy,[hull],0,(255,0,0),2)
cv2.imshow('dst',img_copy)
cv2.waitKey()
cv2.destroyAllWindows()
7.5 外接矩形
- 外接矩形分为最小外接矩形与最大外接矩形
minAreaRect(points)
,最小外接矩形points
即为轮廓- 返回一个一个Rotated Rect旋转的矩形,矩形的中心点,矩形的长宽,矩阵的旋转角度
- 利用
cv2.boxPoints()
计算旋转矩阵的4个坐标点(x,y),(w,h)
boundingRect(points)
,最大外接矩形- 返回(x,y),(w,h)
import cv2
import numpy as np
img = cv2.imread('../my_work/01.png')
# 灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 二值化
ret,binary = cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
# 返回轮廓与层级
contours,hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img_copy = img.copy()
# rect是一个Rotated Rect旋转的矩形,矩形的中心点,矩形的长宽,矩阵的旋转角度
rect = cv2.minAreaRect(contours[0])
print(rect)
# 其实就是帮我们把旋转矩阵的4个坐标点计算出来
box = cv2.boxPoints(rect)
box =np.round(box).astype(int) # 四舍五入
print(box)
# 绘制最小外接矩形
cv2.drawContours(img_copy,[box],0,(0,255,0),2)
# 最大外接矩形,返回(x,y),(w,h)
x,y,w,h = cv2.boundingRect(contours[0])
cv2.rectangle(img_copy,(x,y),(x+w,y+h),(0,0,255),2)
cv2.imshow('dst',img_copy)
cv2.waitKey()
cv2.destroyAllWindows()