opencv_形态学

文章介绍了形态学在图像处理中的应用,包括全局二值化、自适应阈值二值化、腐蚀、膨胀、开运算、闭运算、形态学梯度、顶帽操作和黑帽操作。通过实例展示了如何使用OpenCV库进行这些操作以优化图像处理效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

形态学概述

  • 什么是形态学

    • 指一系列处理图像形状特征的图像处理技术
  • 形态学常用基本操作有:

    • 膨胀和腐蚀
    • 开运算
    • 闭运算
    • 顶帽
    • 黑帽

全局二值化

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

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

    • src 最好是灰度图

    • thresh: 阈值

    • maxval: 最大值, 最大值不一定是255

    • type: 操作类型. 常见操作类型如下:
      在这里插入图片描述

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()
cv2.waitKey(1)

110.0

-1

自适应阈值二值化

在前面的部分我们使用是全局阈值,整幅图像采用同一个数作为阈值。

但是这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不同亮度时。这种情况下我们需要采用自适应阈值。

此时的阈值是根据图像上的每一个小区域计算与其对应的阈值。因此在同一幅图像上的不同区域采用的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。

adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C, dst=None)

这种方法需要我们指定六个参数,返回值只有一个。

  • Adaptive Method : 指定计算阈值的方法。

    • cv2.ADPTIVE_THRESH_MEAN_C :阈值取自相邻区域的平均值
    • cv2.ADPTIVE_THRESH_GAUSSIAN_C :阈值取值相邻区域的加权和,权重为一个高斯窗口。
  • Block Size : 邻域大小(用来计算阈值的区域大小)。

  • C : 这就是是一个常数,阈值就等于的平均值或者加权平均值减去这个常数。

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()
cv2.waitKey(1)

-1

# 更加具有代表性的例子
import cv2 
import numpy as np


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

# 创建窗口调整显示的大小
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 640, 480)

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

# 我们发现适应全局阈值二值化, 对图片光线不好的地方效果不太好
thresh, dst = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY)

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

180.0

# 使用自适应阈值二值化
# 更加具有代表性的例子
import cv2 
import numpy as np


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

# 创建窗口调整显示的大小
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 1080, 720)

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

# 我们发现适应全局阈值二值化, 对图片光线不好的地方效果不太好
dst = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 5, 0)

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

180.0

腐蚀操作

腐蚀操作

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

  • 大部分时候腐蚀操作使用的都是全为1的卷积核.

在这里插入图片描述

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

    • iterations是腐蚀操作的迭代次数, 次数越多, 腐蚀操作执行的次数越多, 腐蚀效果越明显
import cv2
import numpy as np

img = cv2.imread('./msb.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()
cv2.waitKey(1)

-1

import cv2 
import numpy as np


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

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

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

cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)

-1

获取形态学卷积核

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

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

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
print(kernel) # 卷积核为椭圆

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

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

cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)
[[0 0 1 0 0]
 [1 1 1 1 1]
 [1 1 1 1 1]
 [1 1 1 1 1]
 [0 0 1 0 0]]

-1

膨胀操作

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

在这里插入图片描述在这里插入图片描述

  • dilate(img, kernel, iterations=1)
import cv2 
import numpy as np

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

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
print(kernel) # 矩形

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

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

cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)

[[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]]

-1

膨胀和腐蚀简单应用

# 膨胀和腐蚀简单应用 -- 删除细线条
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()
cv2.waitKey(1)

-1

开运算

  • 开运算和闭运算都是腐蚀和膨胀的基本应用.

  • 开运算 = 腐蚀 + 膨胀

  • morphologyEx(img, MORPH_OPEN, kernel)

    • MORPH_OPEN 表示形态学的开运算
    • MORPH_CLOSE 表示形态学的闭运算
    • MORPH_GRADIENT 表示形态学梯度 = 原图 - 腐蚀图
    • MORPH_TOPHAT 表示顶帽操作 = 原图 - 开运算图
    • MORPH_BLACKHAT 表示黑帽操作 = 原图 - 闭运算图
    • kernel 如果噪点比较多, 会选择大一点的kernel, 如果噪点比较小, 可以选择小点的kernel
import cv2 
import numpy as np

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

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
print(kernel) # 矩形核

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

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

cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)

[[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]]

-1

闭运算

  • 闭运算 = 膨胀 + 腐蚀
import cv2 
import numpy as np

# 闭运算 = 膨胀 + 腐蚀

# 闭运算可以去除图形内部的噪声
# imread没有读到东西是不会报错的, 只会返回一个None
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()
cv2.waitKey(1)

-1

形态学梯度

  • 梯度 = 原图 - 腐蚀
  • 腐蚀之后原图边缘变小了, 原图 - 腐蚀 就可以得到腐蚀掉的部分, 即边缘.
# 形态学梯度 = 原图 - 腐蚀
import cv2 
import numpy as np

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

# 矩形核
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()
cv2.waitKey(1)

-1

顶帽操作(tophat)

  • 顶帽 = 原图 - 开运算
  • 开运算的效果是去除图像外的噪点, 原图 - 开运算就得到了去掉的噪点
# 顶帽操作 = 原图  - 开运算 :得到图形外的噪声
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_TOPHAT, kernel, iterations=2)

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

cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)

-1

黑帽操作

  • 黑帽 = 原图 - 闭运算
  • 闭运算可以将图形内部的噪点去掉, 那么原图 - 闭运算的结果就是图形内部的噪点.
# 黑帽操作 = 原图  - 闭运算 得到图形内部的噪声
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_BLACKHAT, kernel, iterations=2)

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

cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)

-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

¥骁勇善战¥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值