用OpenCV进行传统图像分割

news/2024/11/24 7:23:18/

1. 引言

欢迎回来,我的图像处理爱好者们!本文我们将直接进入传统图像分析的新领域——图像分割,这是指将图像分成若干具有相似性质的区域的过程,从数学角度来看,图像分割是将图像划分成互不相交的区域的过程。
闲话少说,我们直接开始吧!

2. 基于阈值的分割

首先介绍的是基于阈值和基于Otsu的分割方法,这是我们进行分割实验的第一步,我们将了解像这样简单而有效的方法是如何根据图像像素的强度值将图像划分为前景和背景两部分的。

但是我们如何科学地决定分割的阈值呢?这就是Otsu方法派上用场的地方。简单地说,这种巧妙的方法通过计算出最大化类间方差的最佳阈值,使其成为自适应阈值选择的优秀工具。

首先从我们的准备工作开始, 导入我们需要的图像处理库:

# Import libraries
from skimage.io import imread, imshow
import matplotlib.pyplot as plt
import numpy as np
from skimage.color import rgb2gray, rgb2hsv
from skimage.filters import threshold_otsu

加载本节测试图像样例,如下:

# Display the image that we will be playing with
original_image = imread('plants.jpg')
plt.figure(figsize=(20,20))
plt.imshow(original_image)
plt.title('Original Image', fontsize=20, weight='bold')
plt.axis('off')
plt.show()

结果如下:
在这里插入图片描述

3. 固定阈值分割

当我们想要对图像进行二值化时,我们执行两步过程,将图像转换为灰度图,然后设置我们想要的任何阈值(通常为0.50),进而将其转换为二值图像:

# Convert the image to grayscale
gray_image = rgb2gray(original_image)
plt.figure(figsize=(20,20))
plt.imshow(gray_image, cmap='gray')
plt.title('Grayscale Image', fontsize=20, weight='bold')
plt.axis('off')
plt.show()

得到灰度图,结果如下:在这里插入图片描述

选择固定阈值,进行二值化,代码如下:

# Convert the grayscale image to binary image using threshold=0.50
threshold = 0.5
binary_image = gray_image<threshold
plt.figure(figsize=(20,20))
plt.imshow(binary_image, cmap='gray')
plt.title('Binary Image', fontsize=20, weight='bold')
plt.axis('off')
plt.show()

得到二值图效果如下:
在这里插入图片描述

观察上图,可以发现对于前景背景区分度比较明显的图像,通过设置固定的阈值也可以方便的得到我们需要的前景物体。

4. 自适应阈值分割

请注意分析上述图像中原本较亮的部分是如何变黑的,这是因为我们使用了0.50作为阈值。但在Otsu的方法中,我们不必手动设置阈值,我们可以通过调用函数threshold_otsu让Otsu为我们处理这项工作,如下所示:

# Use threshold_otsu to automatically calculate the optimal threshold
threshold = threshold_otsu(gray_image)
print(f"Otsu's Threshold: {threshold:.2f}")
binary_image_otsu  = gray_image < threshold
plt.figure(figsize=(20,20))
plt.imshow(binary_image_otsu, cmap='gray')
plt.title("Binary Image using Otsu's Method", fontsize=20, weight='bold')
plt.axis('off')
plt.show()

结果如下:

Output:
Otsu's Threshold: 0.67

得到二值图的效果如下:
在这里插入图片描述
看到区别了吗?我们不必为了获得更好的二值化图像而手动地对阈值进行试错。多亏了otsu的方法,为我们节省了大量试错时间!

5. 彩色图像分割

假设我们只想在图像中隔离青色的植物,那么是时候采用另一种令人兴奋的技术了——彩色图像分割!这种方法是二值化的扩展,但这里有一个注意项:我们使用颜色信息来分离对象,而不是像素值强度。当图像中感兴趣的对象拥有独特不同的颜色时,该方法特别有用。

按照惯例,我们还是首先导入我们的样例图像,代码如下:

# Display original image
original_image = imread('plants.jpg')
plt.figure(figsize=(20,20))
imshow(original_image)
plt.title('Original Image', fontsize=20, weight='bold')
plt.axis('off')
plt.show()

结果如下:
在这里插入图片描述

6. 基于RGB颜色空间的图像分割

观察上图,为了只隔离茂盛的绿色植物,我们可以执行简单的分割操作。如果绿色通道值大于红色和蓝色通道值,我们可以使用下面的比较运算符来表示像素为绿色,代码如下:

# Read image using skimage
original_image = imread('plants.jpg')# Create subplot of 1x2
fig, ax = plt.subplots(1, 2, figsize=(20, 20))# Plot original image
ax[0].imshow(original_image)
ax[0].set_title('Original Image', fontsize=20, weight='bold')
ax[0].axis('off')# Get red, green, and blue channels
r = original_image[:, :, 0]
g = original_image[:, :, 1]
b = original_image[:, :, 2]# Create a mask for green color
mask = (g > r) & (g > b) # adjust these values depending on what you consider to be 'green'# Create a new image
new_img = original_image.copy()# Apply mask to all channels
new_img[:, :, 0] = new_img[:, :, 0] * mask
new_img[:, :, 1] = new_img[:, :, 1] * mask
new_img[:, :, 2] = new_img[:, :, 2] * mask# Plot the green segmented image
ax[1].imshow(new_img)
ax[1].set_title('Green Segmented Image', fontsize=20, weight='bold')
ax[1].axis('off')# Display the subplot
plt.tight_layout()
plt.show()

结果如下:
在这里插入图片描述

7. 美化效果

观察上述右图,虽然我们可以大致得到我们想要的分割结果,但是仔细观察上图中留下了很多无用的白色标记。实质上白色是红色、绿色和蓝色都达到顶峰的颜色。因此,为了阻止这些不想要的因素,我们可以在代码中添加一个白色掩膜,代码如下:

# Create a mask for white color
white_threshold = 180  # adjust this depending on what you consider to be 'white'
white_mask = (r > white_threshold) & (g > white_threshold) & (b > white_threshold)
# Combine the green and white masks
mask = green_mask & ~white_mask  # ~ is the NOT operator
# Create a new image and apply mask
new_img = original_image.copy()
# Apply mask to all channels
new_img[:,:,0] = new_img[:,:,0] * mask
new_img[:,:,1] = new_img[:,:,1] * mask
new_img[:,:,2] = new_img[:,:,2] * mask# Plot the green segmented image
ax[1].imshow(new_img)
ax[1].set_title('Green Segmented Image', fontsize=20, weight='bold')
ax[1].axis('off');

得到结果如下:
在这里插入图片描述

8. 基于HSV颜色空间的图像分割

如上所述,有时在其他颜色空间(如HSV(色调、饱和度、值))中分割颜色更容易。在HSV颜色空间中,不同的颜色排列在一个圆上(色调),因此挑选特定的颜色可能更容易。

让我们显示原始图像的色调、饱和度和值:

# Read image using skimage
original_image = imread('plants.jpg')# Convert the image to HSV color space
hsv_img = rgb2hsv(original_image)fig, ax = plt.subplots(1, 3, figsize=(20,20))
ax[0].imshow(hsv_img[:,:,0], cmap='hsv')
ax[0].set_title('Hue', fontsize=20)
ax[1].imshow(hsv_img[:,:,1], cmap='hsv')
ax[1].set_title('Saturation', fontsize=20)
ax[2].imshow(hsv_img[:,:,2], cmap='hsv')
ax[2].set_title('Value', fontsize=20);

结果如下:
在这里插入图片描述

9. 基于H色调的图像分割

由于使用上面的图很难看到强度值的差异,所以让我们使用colorbar函数来分析,代码如下:

plt.imshow(hsv_img[:,:,0], cmap='hsv')
plt.colorbar()

结果如下:
在这里插入图片描述
正如你所看到的,橙色介于0到0.05之间,所以让我们这些值作为阈值:

# Read image using skimage
original_image = imread('plants.jpg')# Convert the image to HSV color space
hsv_img = rgb2hsv(original_image)# Create a mask for orange color
# Hue for orange is roughly in the range of 0 - 0.05
# We can play around these values to adapt to our specific color requirement
mask = (hsv_img[:,:,0] > 0) & (hsv_img[:,:,0] < 0.05)# create a new image and apply mask
new_img = original_image.copy()new_img[:,:,0] = new_img[:,:,0] * mask
new_img[:,:,1] = new_img[:,:,1] * mask
new_img[:,:,2] = new_img[:,:,2] * mask# plot the original and segmented images side by side
fig, ax = plt.subplots(1, 2, figsize=(20,10))ax[0].imshow(original_image)
ax[0].set_title('Original Image', fontsize=20, weight='bold')
ax[0].axis('off')ax[1].imshow(new_img)
ax[1].set_title('Orange Segmented Image', fontsize=20, weight='bold')
ax[1].axis('off')plt.show()

结果如下:
在这里插入图片描述
观察上图,我们已经成功地在植物图像中分割出了具有鲜艳色调的橙色植物。

10.总结

哇,我们今天的旅程简直太棒了!我们对图像分割的深入研究无疑为我们如何从图像中提取有意义的信息提供了有效的方法。 希望大家可以通过上述案例,进入到图像处理的神秘领域,感叹相关算法的魅力。


http://www.ppmy.cn/news/708706.html

相关文章

主板24pin接口详图_24Pin接口再见!华擎推出首款ATX12VO标准的Z490主板

Intel的提出ATX12VO电源标准也有一段时间了&#xff0c;不过一直很少有实际的电源或者主板产品出现&#xff01;近日华擎发布首款基于ATX12VO电源规范设计主板Z490 Phantom Gaming 4SR&#xff0c;这应该是零售市场首款支持ATX12VO标准的主板&#xff0c;要么至少是首款支持ATX…

主板24pin接口详图_特殊装机:24pin主板用20pin的供电

特殊装机&#xff1a;24pin主板用20pin的供电 24pin接口用20pin供电&#xff0c;8pin接口用4pin供电 下面这种装机手段在品牌机上非常常见&#xff0c;也是品牌机最常被认为偷工减料的标志&#xff1a;用20pin的供电接24pin的主板供电&#xff0c;用4pin的供电接8pin的CPU供电&…

【单片机毕业设计】篮球计分系统

主要功能&#xff1a; 可以在任何时候对每一节的比赛进行倒数&#xff0c;并且可以在任何时候由于攻击方的犯规而中止比赛;可以记录比赛双方对比的分数;可以在一节后互换场地&#xff0c;对A队和B队的得分进行换位[3];具有24秒倒计时功能&#xff0c;可随时按下按钮重置。如果…

分辨率适配-ipad

简述 游戏中美术应有一个统一的设计分辨率&#xff0c;并将位置可能发生变化的节点根据视口大小设置坐标&#xff0c;即可保证相对位置&#xff0c;当使用FIXED_xxx作为适配方案时固定边相关坐标可不参照视口大小&#xff1b; 应用 local frame_size glview:getFrameSize()…

uni-app - MUMU模拟器模拟 iPad 尺寸开发(分辨率及DPI调整)

前言 如果不在 MUMU 模拟器做一些调整&#xff0c;会导致界面变大。 如果使用 uni-app 开发适配 iPad 平板的 APP&#xff0c;那么可以使用 MUMU模拟器 &#xff0c;通过调整分辨率及 DPI 即可。 解决方案 点击如下图所示按钮&#xff0c;接着点击 设置中心 &#xff1a; 切…

软件测试用例编写规范文档,模板都给你了我看谁还不会写测试用例

目录 前言 一 概述 1.1目的 1.2使用范围 二 测试用例编写原则 2.1系统性 2.2连贯性 2.3全面性 三 测试用例设计方法 3.1 等价类划分法&#xff1a; 3.2 边界值分析法&#xff1a; 3.3 因果图法&#xff1a; 3.4功能图法 3.5错误推测法 四 测试用例编写规范 4.1…

IOS-屏幕分辨率

iPhone 3GS3.5吋320x4801x320x480 163iPhone 4/4s3.5吋320x4802x640x960 330iPhone 5/5s/5c4.0吋320x5682x640x1136 326iPhone 64.7吋375x6672x750x1334 326iPhone 6Plus5.5吋414x7363x1242x22081080x1920401iPhone 6s4.7吋375x6672x750x1334 326iPhone 6sPlus5.5吋414x7363x12…

iPad尺寸详解

因为以前一直做iPhone 突然做pad竟然就不知道尺寸&#xff0c;就搜集了一下供大家参考 界面尺寸 设备 尺寸 分辨率 状态栏高度 导航栏高度 标签栏高度 iPad第三代、第四代 20481536 px 264PPI 40px 88px 98px iPad第一代、第二代 1024768 px 132PPI 20px 44px 49px iPad Mini 1…