数字图像处理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()
相关推荐
AngelPP3 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年3 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
AI探索者3 小时前
LangGraph StateGraph 实战:状态机聊天机器人构建指南
python
AI探索者3 小时前
LangGraph 入门:构建带记忆功能的天气查询 Agent
python
九狼4 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS4 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区5 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈5 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
FishCoderh5 小时前
Python自动化办公实战:批量重命名文件,告别手动操作
python
躺平大鹅5 小时前
Python函数入门详解(定义+调用+参数)
python