OpenCv基础(四)

OpenCv基础(四)


六、形态学

  • 指一系列处理图像形状特征的图像处理技术

  • 基本思想是利用一种特殊的结构元(即卷积核)来测量或提取输入图像中相应的形状或特征,以便进一步进行图像分析和目标识别

  • 形态学基本操作:

    • 膨胀和腐蚀

    • 开运算

    • 闭运算

    • 顶帽

    • 黑帽

6.1 图像二值化

  • 上述处理方法基本上是对二值图像进行处理;

  • threshold(src,thresh,maxval,type)二值化处理

    • src:最好是灰度图
    • thresh:阈值
    • maxval:最大值,最大值不一定是255
    • type:操作类型
      • 常见的操作类型: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()
  • 26
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值