1 形态学概述
- 什么是形态学(morphology)
- 指一系列处理图像形状特征的图像处理技术
- 形态学的基本思想是利用一种特殊的结构元(本质上就是卷积核)来测量或提取输入图像中相应的形状或特征,以便进一步进行图像分析和目标识别。该卷积核比较特殊,元素基本都是0/1.
- 这些处理方法基本上都是处理二值图像,即黑白图像
- 卷积核决定图像处理的效果
- 形态学中常用的基本运算有:
- 膨胀和腐蚀
- 开放式操作
- 封闭式操作
- 大礼帽
- 黑帽
2 图像全局二值化
- 二值化: 将图像的每个像素变成两种值, 比如0, 255.
- cv2.threshold(src, thresh, maxval, type[, dst])
- src: 最好是灰度图
- thresh: 阈值
- maxval: 最大值, 最大值不一定是255(用的最多的还是255)
- type: 操作类型. 常见操作类型如下(常用的是1、4):
- 会返回两个结果,一个是阈值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()
3 自适应阈值二值化
在上一部分中,我们使用了全局阈值,整幅图像使用与阈值相同的数字。但这种方法并不适用于所有情况,尤其是当同一图像的不同部分具有不同的亮度时。在这种情况下,我们需要使用自适应阈值。此时的阈值是根据图像上的每个小区域计算出相应的阈值。因此,在同一张图像的不同区域使用不同的阈值,这样我们在不同亮度的情况下可以得到更好的结果,比全局二值化更加灵活。
- cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst])
- 这个方法需要我们指定六个参数,并且只有一个返回值。
- src最好是灰度图
- maxValue最大值, 最大值不一定是255(用的最多的还是255)
- Adaptive Method- 指定计算阈值的方法。
– cv2.ADPTIVE_THRESH_MEAN_C :阈值取自相邻区域的平均值
– cv2.ADPTIVE_THRESH_GAUSSIAN_C :阈值取值相邻区域的加权和,权重为一个高斯窗口。(效果更好) - type: 操作类型. 常见操作类型如下:
- 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, 如果卷积核内所有像素点都是白色, 那么锚点即为白色.
- 大部分时候腐蚀操作使用的都是全为1的卷积核.
- 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()
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()
6 膨胀操作
膨胀是腐蚀的相反操作, 基本原理是只要保证卷积核的锚点是非0值, 周边无论是0还是非0值, 都变成非0值.
- 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()
膨胀和腐蚀的简单应用:
# 膨胀和腐蚀简单应用
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()
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()
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()
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()
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()
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目录:OpenCV总目录学习笔记
我是知客的专业新手。写博客文章并不容易。如果你喜欢它,你可以给它一个大拇指!
文章出处登录后可见!
已经登录?立即刷新