OpenCV学习笔记9-形态学的原理及代码实现

文章目录

  • 1 形态学概述
  • 2 图像全局二值化
  • 3 自适应阈值二值化
  • 4 腐蚀操作
  • 5 获取形态学卷积核
  • 6 膨胀操作
  • 7 开运算
  • 8 闭运算
  • 9 形态学梯度
  • 10 顶帽操作
  • 11 黑帽操作

1 形态学概述

  • 什么是形态学(morphology)
    • 指一系列处理图像形状特征的图像处理技术
    • 形态学的基本思想是利用一种特殊的结构元(本质上就是卷积核)来测量或提取输入图像中相应的形状或特征,以便进一步进行图像分析和目标识别。该卷积核比较特殊,元素基本都是0/1.
    • 这些处理方法基本是对二进制图像进行处理, 即黑白图像
    • 卷积核决定着图像处理后的效果
    • 形态学常用基本操作有:
      • 膨胀和腐蚀
      • 开运算
      • 闭运算
      • 顶帽
      • 黑帽

2 图像全局二值化

  • 二值化: 图像的二值化有利于图像的进一步处理,使图像变得简单,而且数据量减小,能凸显出感兴趣的目标的轮廓。要进行二值图像的处理与分析,首先要把灰度图像二值化,得到二值化图像。

  • 将图像的每个像素变成两种值, 比如0, 255.

  • cv2.threshold(src, thresh, maxval, type[, dst])

    • src: 最好是灰度图

    • thresh: 阈值

    • maxval: 最大值, 最大值不一定是255(用的最多的还是255)

    • type: 操作类型. 常见操作类型如下(常用的是1、4):
      OpenCV学习笔记9-形态学的原理及代码实现_第1张图片
      OpenCV学习笔记9-形态学的原理及代码实现_第2张图片
      通常情况下,我们一般不知道设定怎样的阈值thresh才能得到比较好的二值化效果,只能去尝试。但是如果对于一幅双峰图像(可理解成图像直方图中存在两个峰值),我们指定的阈值应尽量在两个峰之间的峰谷。这时,我们就要多传人一个参数cv2. THRESH_OTSU,并且把阈值设为0,算法就会自动找到最优阈值,并返回。

    • 会返回两个结果, 一个是阈值thresh, 另一个是处理后的图片dst

    import cv2 
    import numpy as np
    
    # 导入图片
    img = cv2.imread('./dog.jpeg')
    
    # 二值化操作是对灰度图像操作, 把dog变成灰度图像
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 注意, threshold会返回两个值, 一个是阈值, 二值化处理后的图片
    thresh, dst = cv2.threshold(gray, 110, 255, cv2.THRESH_BINARY)
    
    print(thresh)
    # 展示
    cv2.imshow('dog', np.hstack((gray, dst)))
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    OpenCV学习笔记9-形态学的原理及代码实现_第3张图片

3 自适应阈值二值化

在前面的部分我们使用是全局阈值,整幅图像采用同一个数作为阈值。但是这种方法并不适应于所有情况,尤其是当同一幅图像上的不同部分的具有不同亮度时。这种情况下我们需要采用自适应阈值。此时的阈值是根据图像上的每一个小区域计算与其对应的阈值。因此在同一幅图像上的不同区域采用的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果,比全局二值化更加灵活一些。

  • cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst])
    • 这种方法需要我们指定六个参数,返回值只有一个。
    • src 最好是灰度图
    • maxValue 最大值, 最大值不一定是255(用的最多的还是255)
    • Adaptive Method- 指定计算阈值的方法。
            – cv2.ADAPTIVE_THRESH_MEAN_C:阈值取自相邻区域的平均值
            – cv2.ADAPTIVE_THRESH_GAUSSIAN_C:阈值取值相邻区域的加权和,权重为一个高斯窗口。(效果更好)
    • type: 操作类型. 常见操作类型如下:
OpenCV学习笔记9-形态学的原理及代码实现_第4张图片

OpenCV学习笔记9-形态学的原理及代码实现_第5张图片
通常情况下,我们一般不知道设定怎样的阈值thresh才能得到比较好的二值化效果,只能去尝试。但是如果对于一幅双峰图像(可理解成图像直方图中存在两个峰值),我们指定的阈值应尽量在两个峰之间的峰谷。这时,我们就要多传人一个参数cv2. THRESH_OTSU,并且把阈值设为0,算法就会自动找到最优阈值,并返回。

  • Block Size - 邻域大小(用来计算阈值的区域大小,即卷积核大小),是一个奇数。
  • C - 这就是是一个常数,阈值就等于的平均值或者加权平均值减去这个常数。
  • dst 输出图像
import cv2 
import numpy as np

# 导入图片
img = cv2.imread('./dog.jpeg')

# 二值化操作是对灰度图像操作, 把dog变成灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 自适应阈值二值化只有一个返回值,
dst = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 19, 0)

# 展示
cv2.imshow('dog', np.hstack((gray, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

4 腐蚀操作

  • 腐蚀操作也是用卷积核扫描图像, 只不过腐蚀操作的卷积核元素一般都是1, 如果卷积核内所有像素点都是白色, 那么锚点即为白色.

    OpenCV学习笔记9-形态学的原理及代码实现_第6张图片
  • 大部分时候腐蚀操作使用的都是全为1的卷积核.

    OpenCV学习笔记9-形态学的原理及代码实现_第7张图片

  • cv2.erode(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])

    • src 是原图
    • kernel 是卷积核的大小,元组形式
    • dst 输出图像
    • anchor 锚点,是可选参数,默认是(-1,-1)
    • iterations 是腐蚀操作的迭代次数, 次数越多, 腐蚀操作执行的次数越多, 腐蚀效果越明显
    • borderType 边界类型
    • borderValue 边缘值
import cv2 
import numpy as np

# 导入图片
img = cv2.imread('./j.png')

# 定义核
kernel = np.ones((3,3), np.uint8)
dst = cv2.erode(img, kernel, iterations=2)

cv2.imshow('img', np.hstack((img, dst)))

cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV学习笔记9-形态学的原理及代码实现_第8张图片

5 获取形态学卷积核

  • opencv提供了获取卷积核的api.不需要我们手工创建卷积核.
  • cv2.getStructuringElement(shape, ksize[, anchor])
    • shape是指卷积核的形状, 注意不是指长宽, 是指卷积核中1形成的形状.
      • MORPH_RECT 卷积核中的1是矩形, 常用.
      • MORPH_ELLIPSE 卷积核中的1椭圆
      • MORPH_CROSS 卷积核中的1十字
    • ksize 卷积核的大小,元组形式
import cv2
import numpy as np

img = cv2.imread('./j.png')

# 获取形态学卷积核
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))

# 腐蚀操作
dst = cv2.erode(img, kernel, iterations=2)

cv2.imshow('img', np.hstack((img, dst)))

cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV学习笔记9-形态学的原理及代码实现_第9张图片

6 膨胀操作

膨胀是腐蚀的相反操作, 基本原理是只要保证卷积核的锚点非0值, 周边无论是0还是非0值, 都变成非0值.

OpenCV学习笔记9-形态学的原理及代码实现_第10张图片
  • cv2.dilate(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
    • src 是原图像
    • kernel 是卷积核的大小,元组形式
    • dst 输出图像
    • anchor 是锚点
    • iterations 是膨胀操作的迭代次数, 次数越多, 膨胀操作执行的次数越多, 膨胀效果越明显
    • borderType 边界类型
    • borderValue 边缘值
import cv2
import numpy as np

img = cv2.imread('./j.png')

# 获取形态学卷积核
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))

# 膨胀操作
dst = cv2.dilate(img, kernel, iterations=2)

cv2.imshow('img', np.hstack((img, dst)))

cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV学习笔记9-形态学的原理及代码实现_第11张图片

膨胀和腐蚀的简单应用:

# 膨胀和腐蚀简单应用
import cv2 
import numpy as np


# 导入图片
img = cv2.imread('./msb.png')

# 定义核
kernel = np.ones((5, 5), np.uint8)

# 先腐蚀
dst = cv2.erode(img, kernel, iterations=1)

# 再膨胀
dst = cv2.dilate(dst, kernel, iterations=1)

cv2.imshow('img', np.hstack((img, dst)))

cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV学习笔记9-形态学的原理及代码实现_第12张图片

7 开运算

  • 开运算和闭运算都是腐蚀和膨胀的基本应用.
  • 开运算 = 腐蚀 + 膨胀(先腐蚀再膨胀)
  • 适用于消除图像外部的噪声
  • cv2.morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
    • src 是原图
    • op 操作类型(operations),开运算是cv2.MORPH_OPEN
    • kernel 是卷积核的大小,元组形式。如果噪点比较多, 会选择大一点的kernel, 如果噪点比较小, 可以选择小点的kernel
    • dst 是输出图像
    • anchor 是锚点
    • iterations 是操作的迭代次数, 次数越多, 操作执行的次数越多, 效果越明显
    • borderType 边界类型
    • borderValue 边缘值
import cv2
import numpy as np

# 开运算 = 腐蚀  + 膨胀
# 开运算提供了另一种去除噪声的思路.
img = cv2.imread('./dotj.png')

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

# 直接调用opencv提供的开运算api
dst = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel, iterations=2)

cv2.imshow('img', np.hstack((img, dst)))

cv2.waitKey(0)
cv2.destroyAllWindows()
OpenCV学习笔记9-形态学的原理及代码实现_第13张图片

8 闭运算

  • 闭运算 = 膨胀 + 腐蚀(先膨胀再腐蚀)
  • 适用于消除图像内部的噪声
  • cv2.morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
    • src 是原图
    • op 操作类型(operations),开运算是cv2.MORPH_CLOSE
    • kernel 是卷积核的大小,元组形式。如果噪点比较多, 会选择大一点的kernel, 如果噪点比较小, 可以选择小点的kernel
    • dst 是输出图像
    • anchor 是锚点
    • iterations 是操作的迭代次数, 次数越多, 操作执行的次数越多, 效果越明显
    • borderType 边界类型
    • borderValue 边缘值
import cv2
import numpy as np

# 闭运算= 膨胀 + 腐蚀
# 闭运算可以去除图形内部的噪声
img = cv2.imread('./dotinj.png')

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

# 调用opencv提供的api
dst = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel, iterations=2)

cv2.imshow('img', np.hstack((img, dst)))

cv2.waitKey(0)
cv2.destroyAllWindows()
OpenCV学习笔记9-形态学的原理及代码实现_第14张图片

9 形态学梯度

  • 梯度 = 原图 - 腐蚀
  • 腐蚀之后原图边缘变小了, 原图 - 腐蚀 就可以得到腐蚀掉的部分, 即边缘.
  • cv2.morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
    • src 是原图
    • op 操作类型(operations),开运算是cv2.MORPH_GRADIENT
    • kernel 是卷积核的大小,元组形式。如果噪点比较多, 会选择大一点的kernel, 如果噪点比较小, 可以选择小点的kernel
    • dst 是输出图像
    • anchor 是锚点
    • iterations 是操作的迭代次数, 次数越多, 操作执行的次数越多, 效果越明显
    • borderType 边界类型
    • borderValue 边缘值
# 形态学梯度 = 原图 - 腐蚀
import cv2
import numpy as np

img = cv2.imread('./j.png')

# 注意调节kernel大小以获得更清晰的边缘
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))

# 调用opencv提供的api
dst = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel, iterations=1)

cv2.imshow('img', np.hstack((img, dst)))

cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV学习笔记9-形态学的原理及代码实现_第15张图片

10 顶帽操作

  • 顶帽 = 原图 - 开运算
  • 开运算的效果是去除图像外的噪声, 原图 - 开运算就得到了去掉的噪声.
  • morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
    • src 是原图
    • op 操作类型(operations),开运算是cv2.MORPH_TOPHAT
    • kernel 是卷积核的大小,元组形式。如果噪点比较多, 会选择大一点的kernel, 如果噪点比较小, 可以选择小点的kernel
    • dst 是输出图像
    • anchor 是锚点
    • iterations 是操作的迭代次数, 次数越多, 操作执行的次数越多, 效果越明显
    • borderType 边界类型
    • borderValue 边缘值
# 顶帽操作 = 原图  - 开运算 得到图形外的噪声
import cv2 
import numpy as np

img = cv2.imread('./dotj.png')

# 注意调整kernel以保留小图形
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

# 调用opencv提供的api
dst = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel, iterations=2)

cv2.imshow('img', np.hstack((img, dst)))

cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV学习笔记9-形态学的原理及代码实现_第16张图片

11 黑帽操作

  • 黑帽 = 原图 - 闭运算
  • 闭运算可以将图形内部的噪声去掉, 那么原图 - 闭运算的结果就是图形内部的噪声.
  • cv2.morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
    • src 是原图
    • op 操作类型(operations),开运算是cv2.MORPH_BLACKHAT
    • kernel 是卷积核的大小,元组形式。如果噪点比较多, 会选择大一点的kernel, 如果噪点比较小, 可以选择小点的kernel
    • dst 是输出图像
    • anchor 是锚点
    • iterations 是操作的迭代次数, 次数越多, 操作执行的次数越多, 效果越明显
    • borderType 边界类型
    • borderValue 边缘值
# 黑帽操作 = 原图  - 闭运算 得到图形内部的噪声
import cv2 
import numpy as np

img = cv2.imread('./dotinj.png')

# 注意调节kernel大小以获得更清晰的边缘
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

# 调用opencv提供的api
dst = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel, iterations=2)

cv2.imshow('img', np.hstack((img, dst)))

cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV学习笔记9-形态学的原理及代码实现_第17张图片

附OpenCV目录:OpenCV总目录学习笔记

智科专业小白,写博文不容易,如果喜欢的话可以点个赞哦!请添加图片描述

你可能感兴趣的:(机器视觉,计算机视觉,python,opencv,人工智能,jupyter)