数字图像处理4——Python图像形态学处理

1.基于OpenCV进行形态学腐蚀运算

首先使用 OpenCV 的 imread 函数读取图像,然后用cv.IMREAD_GRAYSCALE 参数指定图像应该被转换为灰度图像,运用cv.getStructuringElement 函数用于生成特定形状的结构元素,这里使用 cv.MORPH_RECT 参数来创建一个正方形,再使用刚刚创建的 3x3 正方形结构元素对原始图像 img 进行一次腐蚀操作,腐蚀操作会缩小图像中白色区域的大小,增加黑色区域的大小,再创建一个 15x15 的椭圆形结构元素,与前面创建的正方形结构元素类似,这里使用 cv.MORPH_ELLIPSE 参数来指定椭圆形状,使用 15x15 的椭圆形结构元素对原始图像 img 进行腐蚀操作。

python 复制代码
import numpy as np
import cv2 as cv
from skimage import io,color,util,morphology,filters,measure
from scipy import ndimage
import matplotlib.pyplot as plt
%matplotlib inline
img = cv.imread('./imagedata/blobs.png', cv.IMREAD_GRAYSCALE)

kernel_square = cv.getStructuringElement(cv.MORPH_RECT,(3,3)) 
#kernel_square = np.ones((3,3),np.uint8) 

img_erode1 = cv.erode(img,kernel_square,iterations = 1)
#img_erode1 = cv.morphologyEx(img, cv.MORPH_ERODE, kernel_square)

kernel_ellipse = cv.getStructuringElement(cv.MORPH_ELLIPSE,(15,15)) 
img_erode2 = cv.erode(img,kernel_ellipse)

#显示结果
plt.figure(figsize=(15,7))
plt.gray()

#原图像
plt.subplot(1,3,1); plt.imshow(img)
plt.title('Original image') 
plt.axis('off')
#3*3正方形结构元素腐蚀结果
plt.subplot(1,3,2); plt.imshow(img_erode1)
plt.title('Eroded by 3*3 square')
plt.axis('off') 
#15*15的椭圆形结构元素腐蚀结果
plt.subplot(1,3,3); plt.imshow(img_erode2)
plt.title('Eroded by 15*15 ellipse') 
plt.axis('off')

plt.show()

2.基于Scikit-image进行形态学腐蚀运算

首先使用 skimage 的 io.imread 函数读取图像,然后创建一个 3x3 大小的正方形结构元素,morphology.square 函数用于生成正方形的结构元素,使用前面创建的正方形结构元素对图像 img 进行二值腐蚀操作,二值腐蚀主要用于缩小图像中白色(前景)区域。将腐蚀操作的结果转换为 8 位无符号整数格式(uint8),再创建一个半径为 7 的圆盘形结构元素,morphology.disk 函数生成圆盘形状的结构元素,使用圆盘形结构元素对原始图像进行二值腐蚀操作,同样地,将腐蚀操作的结果转换为 uint8 格式。

python 复制代码
img = io.imread('./imagedata/blobs.png')
# 使用正方形结构元素进行二值腐蚀
selem_sq = morphology.square(3)
imgout1 = morphology.binary_erosion(img, selem_sq)
imgout1 = util.img_as_ubyte(imgout1)

# 使用圆盘结构元素进行二值腐蚀
selem_disk = morphology.disk(7)
imgout2 = morphology.binary_erosion(img, selem_disk)
imgout2 = util.img_as_ubyte(imgout2)
plt.rcParams["font.sans-serif"] =['SimHei']
plt.rcParams["axes.unicode_minus"] =False
# 可视化原图像和腐蚀后的图像
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
ax = axes.ravel()

ax[0].imshow(img, cmap=plt.cm.gray)
ax[0].set_title('原始图像')

ax[1].imshow(imgout1, cmap=plt.cm.gray)
ax[1].set_title('正方形腐蚀')

ax[2].imshow(imgout2, cmap=plt.cm.gray)
ax[2].set_title('圆盘腐蚀')

for a in ax:
    a.axis('off')

plt.tight_layout()
plt.show()

3.基于OpenCV进行形态学膨胀运算

首先使用 OpenCV 的 imread 函数读取图像,然后创建一个 7x1 的线性(竖直方向)结构元素,这个结构元素是一个由全 1 组成的 numpy 数组,使用 np.uint8 数据类型,使用前面创建的线性结构元素对图像 img 进行膨胀操作,膨胀操作会增加图像中白色区域的大小,减小黑色区域的大小,再创建一个 7x7 的椭圆形结构元素,这里使用 OpenCV 的 getStructuringElement 函数,并指定形状为 cv.MORPH_ELLIPSE,使用椭圆形结构元素对原始图像进行膨胀操作。

python 复制代码
img = cv.imread('./imagedata/blobs.png', 0)
kernel_line = np.ones((7, 1), np.uint8)
img_dilate1 = cv.dilate(img, kernel_line)

# 使用椭圆核进行膨胀
kernel_ellipse = cv.getStructuringElement(cv.MORPH_ELLIPSE, (7, 7))
img_dilate2 = cv.dilate(img, kernel_ellipse)

# 可视化原图像和膨胀后的图像
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
ax = axes.ravel()

ax[0].imshow(img, cmap='gray')
ax[0].set_title('原始图像')

ax[1].imshow(img_dilate1, cmap='gray')
ax[1].set_title('线性核膨胀')

ax[2].imshow(img_dilate2, cmap='gray')
ax[2].set_title('椭圆核膨胀')

for a in ax:
    a.axis('off')

plt.tight_layout()
plt.show()

4.基于Scikit-image进行形态学膨胀运算

首先使用 skimage 的 io.imread 函数读取图像,然后创建一个 7x1 的线性(竖直方向)结构元素,这是一个由全 1 组成的 numpy 数组,使用线性结构元素对图像 img 进行二值膨胀操作,二值膨胀会增加图像中白色(前景)区域的大小,将膨胀操作的结果转换为 8 位无符号整数格式(uint8),再创建一个半径为 3 的圆盘形结构元素,使用圆盘形结构元素对原始图像进行二值膨胀操作,同样地,将膨胀操作的结果转换为 uint8 格式。

python 复制代码
img = io.imread('./imagedata/blobs.png')

# 再次尝试读取和处理图像

# 使用线性结构元素进行二值膨胀
selem_line = np.ones((7, 1), np.uint8)
imgout1 = morphology.binary_dilation(img, selem_line)
imgout1 = util.img_as_ubyte(imgout1)

# 使用圆盘结构元素进行二值膨胀
selem_disk = morphology.disk(3)
imgout2 = morphology.binary_dilation(img, selem_disk)
imgout2 = util.img_as_ubyte(imgout2)

# 可视化原图像和膨胀后的图像
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
ax = axes.ravel()

ax[0].imshow(img, cmap=plt.cm.gray)
ax[0].set_title('原始图像')

ax[1].imshow(imgout1, cmap=plt.cm.gray)
ax[1].set_title('线性膨胀')

ax[2].imshow(imgout2, cmap=plt.cm.gray)
ax[2].set_title('圆盘膨胀')

for a in ax:
    a.axis('off')

plt.tight_layout()
plt.show()

5.基于OpenCV进行开运算和闭运算

首先使用 OpenCV 的 imread 函数以灰度模式读取图像,创建一个 25x25 大小的正方形结构元素,cv.getStructuringElement 函数用于生成矩形(正方形)的结构元素,对图像进行开运算,在 OpenCV 中,morphologyEx 函数与 cv.MORPH_OPEN 参数结合使用,进行腐蚀操作后紧接着进行膨胀操作,用于去除小的白色噪声,对图像进行闭运算,cv.MORPH_CLOSE 用于先膨胀后腐蚀,用于填充物体内部的小黑洞,首先对图像应用开运算,然后在该结果上应用闭运算。

python 复制代码
img = cv.imread('./imagedata/noisy_rectangle.png', 0)
kernel_square = cv.getStructuringElement(cv.MORPH_RECT, (25, 25))

# 应用开运算和闭运算
img_open = cv.morphologyEx(img, cv.MORPH_OPEN, kernel_square)
img_close = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel_square)

# 先开运算后闭运算
img_oc = cv.morphologyEx(img, cv.MORPH_OPEN, kernel_square)
img_oc = cv.morphologyEx(img_oc, cv.MORPH_CLOSE, kernel_square)

# 可视化原图像和处理后的图像
fig, axes = plt.subplots(1, 4, figsize=(16, 4))
ax = axes.ravel()

ax[0].imshow(img, cmap='gray')
ax[0].set_title('原始图像')

ax[1].imshow(img_open, cmap='gray')
ax[1].set_title('开运算')

ax[2].imshow(img_close, cmap='gray')
ax[2].set_title('闭运算')

ax[3].imshow(img_oc, cmap='gray')
ax[3].set_title('先开后闭')

for a in ax:
    a.axis('off')

plt.tight_layout()
plt.show()

6.基于Scikit-image进行开运算和闭运算

首先使用 skimage 的 io.imread 函数读取图像,然后使用先前定义的正方形结构元素(假设 selem_sq 已经定义)对图像进行二值开运算,开运算是腐蚀后跟膨胀的组合,用于去除小的白色噪声,将开运算的结果转换为 uint8 类型,对图像进行二值闭运算,闭运算是膨胀后跟腐蚀的组合,用于填充物体内部的小黑洞,首先对图像应用开运算,然后在开运算的结果上应用闭运算。

python 复制代码
img = io.imread('./imagedata/noisy_rectangle.png')
imgout1 = morphology.binary_opening(img, selem_sq)
imgout1 = util.img_as_ubyte(imgout1)

# 使用正方形结构元素进行二值闭运算
imgout2 = morphology.binary_closing(img, selem_sq)
imgout2 = util.img_as_ubyte(imgout2)

# 先进行二值开运算,然后进行二值闭运算
imgout3 = morphology.binary_opening(img, selem_sq)
imgout3 = morphology.binary_closing(imgout3, selem_sq)
imgout3 = util.img_as_ubyte(imgout3)

# 可视化原图像和处理后的图像
fig, axes = plt.subplots(1, 4, figsize=(16, 4))
ax = axes.ravel()

ax[0].imshow(img, cmap=plt.cm.gray)
ax[0].set_title('原始图像')

ax[1].imshow(imgout1, cmap=plt.cm.gray)
ax[1].set_title('二值开运算')

ax[2].imshow(imgout2, cmap=plt.cm.gray)
ax[2].set_title('二值闭运算')

ax[3].imshow(imgout3, cmap=plt.cm.gray)
ax[3].set_title('先开后闭')

for a in ax:
    a.axis('off')

plt.tight_layout()
plt.show()

7.边界提取

首先使用 skimage 的 io.imread 函数读取图像,然后创建一个自定义的 3x3 结构元素,其中中心和其上下左右为 1,角落为 0,使用该结构元素对图像进行二值腐蚀操作,腐蚀主要用于缩小图像中白色区域的大小,将腐蚀操作的结果转换为 8 位无符号整数格式(uint8),计算第一种边界:原图像减去腐蚀后的图像。这种方法突出显示了被腐蚀的边缘,使用相同的结构元素对图像进行二值膨胀操作,膨胀增加白色区域的大小,计算第二种边界:膨胀后的图像减去原图像。

python 复制代码
img = io.imread('./imagedata/circles.png')
# 定义结构元素
se = np.array([[0, 1, 0],
               [1, 1, 1],
               [0, 1, 0]], dtype=np.uint8)

# 应用二值腐蚀
img_erode = morphology.binary_erosion(img, se)
img_erode = util.img_as_ubyte(img_erode)

# 计算第一种边界(原图像减去腐蚀后的图像)
img_Boundary1 = img - img_erode

# 应用二值膨胀
img_dilate = morphology.binary_dilation(img, se)
img_dilate = util.img_as_ubyte(img_dilate)

# 计算第二种边界(膨胀后的图像减去原图像)
img_Boundary2 = img_dilate - img

# 可视化原图像和边界提取结果
fig, axes = plt.subplots(1, 4, figsize=(16, 4))
ax = axes.ravel()

ax[0].imshow(img, cmap=plt.cm.gray)
ax[0].set_title('原始图像')

ax[1].imshow(img_erode, cmap=plt.cm.gray)
ax[1].set_title('二值腐蚀')

ax[2].imshow(img_Boundary1, cmap=plt.cm.gray)
ax[2].set_title('边界1 (原图 - 腐蚀)')

ax[3].imshow(img_Boundary2, cmap=plt.cm.gray)
ax[3].set_title('边界2 (膨胀 - 原图)')

for a in ax:
    a.axis('off')

plt.tight_layout()
plt.show()

8.区域孔洞填充

首先读取图像,然后使用 skimage 的 threshold_otsu 方法计算 Otsu 阈值,这是一种自动确定二值化阈值的方法,再将图像二值化,大于阈值的像素设置为 True,小于等于阈值的像素设置为 False,使用 scipy 的 binary_fill_holes 方法填充二值图像中的孔洞。这个方法识别并填充封闭空间中的孔洞,将填充后的二值图像转换为 uint8 类型,使其更适合显示和进一步处理。

python 复制代码
img = io.imread('./imagedata/coins.jpg')
# 应用 Otsu 阈值
thresh = filters.threshold_otsu(img)
img_bw = img > thresh

# 填充二值图像中的孔洞
img_fill = ndimage.binary_fill_holes(img_bw)
# 将结果数据类型转换为 uint8 型
img_fill = util.img_as_ubyte(img_fill)

# 可视化原图像、二值化图像和填充后的图像
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
ax = axes.ravel()

ax[0].imshow(img, cmap=plt.cm.gray)
ax[0].set_title('原始图像')

ax[1].imshow(img_bw, cmap=plt.cm.gray)
ax[1].set_title('Otsu 二值化')

ax[2].imshow(img_fill, cmap=plt.cm.gray)
ax[2].set_title('填充孔洞')

for a in ax:
    a.axis('off')

plt.tight_layout()
plt.show()
相关推荐
奔跑中的小象6 小时前
统信UOS + 天数AI卡部署SGLang服务手册
人工智能·uos·sglang·天数智芯
DevSecOps选型指南6 小时前
中国版Mythos,为何是悬镜安全灵脉CodeAI?
人工智能·安全
Shockang6 小时前
LangGraph 状态机实战
人工智能
DLYSB_6 小时前
存储运维实战:基于 Ceph Event 监听与 Python 适配器的分布式存储健康度物理声光响应架构
运维·ceph·python·报警灯
刹那芳华19926 小时前
循环神经网络的从零开始实现(RNN)
人工智能·rnn·深度学习
阿童木写作7 小时前
跨境图片翻译工具多合一,批量图片视频字幕翻译加智能抠图
人工智能·python·音视频·语音识别
科技之门7 小时前
AI3D从建模到贴图、绑骨和动画的完整流程怎么做?V2Fun完整工作流指南
人工智能·3d·贴图
宇宙第一小趴菜7 小时前
二、机器学习的应用领域和发展史
人工智能·机器学习
前端开发江鸟7 小时前
我写过 MCP Server,却一直以为 MCP 只有 Tool
人工智能
天国梦7 小时前
自习室智能化升级避坑指南:天学网AI智习室方案实测与选型建议
大数据·人工智能