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()