图像分割是一种图像处理技术,它将图像划分为具有相似特征的区域。常见的图像分割方法包括阈值分割、边缘分割、区域分割、基于阈值的方法、基于边缘的方法、基于区域的方法、聚类分割、基于图论的方法、基于深度学习的方法。
文章目录
- 1.阈值分割
- 2.边缘分割
- 3.区域分割
- 4.聚类分割
- 5.基于图论的分割
- 6.基于深度学习的分割
1.阈值分割
阈值分割的原理是,图像中的不同区域通常具有不同的灰度值,因此可以通过将图像中的每个像素的灰度值与一个预定义的阈值进行比较,从而将图像分成两个或多个区域,每个区域的像素具有相似的灰度值。
在Python中,可以使用numpy库中的阈值方法来实现阈值分割。以下是一个示例:
import numpy as np
import cv2
# 读取图像
img = cv2.imread('input_image.jpg')
# 将图像转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 应用阈值
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
# 显示结果
cv2.imshow("Result", thresh)
# 等待用户关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
在这个示例中,首先将图像转换为灰度图,然后应用自适应阈值方法,从而将图像分割成两个区域。阈值方法会根据图像的局部特征动态调整阈值,从而实现更好的分割效果。
在Halcon中,可以使用Threshold算子来实现阈值分割。以下是一个示例:
* 读取图像
read_image (Image, 'input_image.jpg')
* 将图像转换为灰度图
rgb1_to_gray (Image, GrayImage)
* 应用阈值
threshold (GrayImage, Region, 5, 255)
* 提取阈值分割后的区域
select_shape (Region, SelectedRegions, 'area', 'and', 3000, 10000)
* 绘制区域
area_center (SelectedRegions, Area, Row, Column)
connection (SelectedRegions, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions1, 'area', 'and', 10000, 1000000)
* 显示结果
dev_display (Image)
dev_display (SelectedRegions1)
2.边缘分割
边缘分割是计算机视觉中的一种常用技术,用于从图像中提取具有显著特征的区域。边缘分割的主要目的是将图像中具有相似特征的像素分组在一起,这些特征通常是亮度、颜色、纹理等方面的变化。在边缘分割中,边缘是一种局部区域,其中像素值在空间上呈现显著的不连续性。
边缘分割的原理:
边缘是图像中灰度值变化最显著的区域。在许多图像中,边缘可以表示为直方图中的一个峰。通过比较相邻像素的灰度值,可以找到这个峰,从而识别出边缘。常见的边缘检测算法包括Sobel算子、Prewitt算子、Roberts算子、Canny算子等。
Python实现边缘分割:
使用OpenCV库实现边缘检测:
import cv2
import numpy as np
# 读取图像
img = cv2.imread('image.jpg')
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使用Sobel算子检测边缘
edges = cv2.Sobel(gray, cv2.CV_32F, 1, 0, ksize=3)
# 将检测到的边缘绘制为图像
img_edge = cv2.convertScaleAbs(edges)
cv2.imshow('Edges', img_edge)
cv2.waitKey(0)
cv2.destroyAllWindows()
使用halcon实现分割。
* 加载图像
read_image (Image, 'image.jpg')
* 创建感兴趣区域
region_gray_xld (Image, Region, 'blue', 'light', 1, -1, 40, 20)
* 选择感兴趣区域并计算梯度方向
select_shape (Region, SelectedRegions, 'area', 'and', 1000, 1000000)
dilation_circle (SelectedRegions, RegionDilation, 5)
* 计算梯度和方向
reduce_domain (Image, RegionDilation, ImageReduced)
gradient_xld (ImageReduced, GradientX, GradientY, 1, 'gd')
direction_xld (GradientX, DirectionX, DirectionY, 'north')
* 连接梯度和方向
edge_circles_xld (GradientX, Circles, 'circle', 4, 3.5, 6, 4)
connection_xld (Circles, Edges)
* 显示边缘
dev_display (Image)
dev_display (Edges)
3.区域分割
区域分割是图像分割中的一个重要步骤,它的基本原理是将图像中的目标对象从背景或其他不需要的部分中分离出来。区域分割的目标是将图像中的不同目标区域从背景中分离出来,以便于对它们进行进一步的处理。
在Python中,我们可以使用opencv库来实现区域分割。以下是一个示例代码,使用均值漂移算法实现区域分割:
import cv2
import numpy as np
def blur(image):
# 创建一个高斯滤波器对象
g = cv2.GaussianBlur(image, (5,5), 0)
return g
def mean_shift(image, ksize, winSize, threshold):
# 创建一个高斯滤波器
gaussBlur = blur(image)
mean = cv2.mean(gaussBlur)
# 计算图像的平均梯度
diff = cv2.diff(gaussBlur, mean)
diff /= np.sqrt(diff.sum(axis=2))
# 计算图像的一阶导数
diff = diff * gaussBlur
# 计算局部梯度的二阶导数
gradient = diff.sum(axis=1)
gradient = gradient[np.where((gradient < threshold) * winSize), :, :]
gradient = gradient[:, np.where((gradient > 0) * winSize), :]
gradient = gradient[:, np.where((gradient < 0) * winSize), :]
gradient = gradient[:, np.where((gradient > threshold) * winSize), :]
# 移动窗口并重复以上步骤
for row in range(-1, 3):
for col in range(-1, 3):
row = int(row * winSize)
col = int(col * winSize)
# 定义滑动窗口
win = cv2.boxFilter(mean[col + row:col + row + winSize, :, :], -1, (winSize, winSize))
win = np.hstack((np.ones(winSize, np.uint8), win))
# 计算局部梯度的二阶导数
gradient_win = cv2.diff(mean, mean[col + row + winSize, :, :])
# 移动滑动窗口并重复以上步骤
gradient_win = np.hstack((np.ones(winSize, np.uint8), gradient_win))
# 计算梯度的平均值
mean = cv2.mean(gradient_win)
# 应用高斯滤波器
window = cv2.boxFilter(mean[:, :, col + row + winSize], -1, (winSize, winSize))
window = np.hstack((np.ones(winSize, np.uint8), window))
# 更新滑动窗口的阈值
threshold = cv2.diff(mean, mean[col + row + winSize, :, :]).argmax()
# 根据阈值移动滑动窗口并计算局部梯度的二阶导数
gradient_win = np.hstack((np.ones(winSize, np.uint8), cv2.diff(mean, mean[col + row + winSize, :, :])))
# 更新滑动窗口的阈值
threshold = cv2.diff(mean[col + row + winSize, :, :]).argmax()
# 移动滑动窗口并重复以上步骤
gradient_win = np.hstack((np.ones(winSize, np.uint8), cv2.diff(mean, mean[col + row + winSize, :, :])))
# 计算梯度的平均值
mean = cv2.mean(gradient_win)
# 应用高斯滤波器
window = cv2.boxFilter(mean[:, :, col + row + winSize], -1, (winSize, winSize))
window = np.hstack((np.ones(winSize, np.uint8), window))
# 更新滑动窗口的阈值
threshold = cv2.diff(mean, mean[col + row + winSize, :, :]).argmax()
# 返回结果
return gradient
# 读取图像
image = cv2.imread('input.jpg')
# 设置区域分割阈值
threshold = 0.3
# 计算图像的一阶导数
diff = mean_shift(image, (5,5), (5,5), threshold)
# 显示一阶导数图
cv2.imshow('mean_shift Gradient', diff)
# 等待用户按键
cv2.waitKey(0)
# 销毁窗口
cv2.destroyAllWindows()
在 HALCON 中,区域分割功能主要由 Helbling, Coecke 和 Schneider 算子实现。这些算子接受一个图像区域、一个阈值和一个方法作为输入参数。通过计算像素值和阈值之间的关系,这些算子会返回一个包含目标像素的图像区域。
以下是使用 Helbling, Coecke 和 Schneider 算子实现区域分割的 HALCON 算子示例:
* 读取图像
read_image(Image, 'input_image.png')
* 创建目标区域
gen_empty_obj(Region)
* 选择目标区域
select_shape(Image, ObjectSelection, 'area', 'and', 1000, 9999)
* 区域分割
apply_coecke_hmean(Region, MeanValue, 'luminosity', 'and', Threshold1, Threshold2)
area_center(Image, Area, Row, Column)
* 对中心区域应用阈值
threshold(Image, Region, Threshold1, Threshold2)
* 在中心区域创建选择
select_shape(Region, CenterSelection, 'area', 'and', Area, 9999)
* 合并选择区域
merge_shape_xld(Region, RegionUnion)
* 显示结果
dev_display(Image)
dev_display(CenterSelection)
dev_display(RegionUnion)
4.聚类分割
聚类是一种无监督学习方法,可以将一组数据点分为若干个类别,使得每个数据点都属于离自己最近的类别。聚类的原理是通过数学距离来度量数据点之间的相似性,然后将相似的数据点归为同一个类别。聚类算法有很多,如K-means、层次聚类、DBSCAN等。
下面以K-means算法为例,分别用Python和HALCON算子实现聚类分割。
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.cluster import KMeans
# 读入数据
df = pd.read_csv('data.csv')
# 缺失值处理
df['is_missing'] = df['value'] == np.nan
# 选择需要的列
columns = ['value']
df = df[columns]
# 划分数据集
X, y = df.iloc[:, :-1].values, df.iloc[:, -1].values
X_train, X_test = X[:int(len(X) * 0.8)], X[int(len(X) * 0.8):]
# 训练KMeans模型
model = KMeans(n_clusters=3)
model.fit(X_train)
# 计算预测结果
predictions = model.predict(X_test)
# 可视化结果
plt.figure(figsize=(6, 6))
for i, prediction in enumerate(predictions):
plt.scatter(X_test[:, 0], X_test[:, 1], c=prediction, alpha=0.5, label='prediction')
plt.xlabel('X1')
plt.ylabel('X2')
plt.legend()
plt.show()
HALCON code:
* 读取图像并缩放
read_image (Image, 'data.png')
get_image_size (Image, Width, Height)
disp_message (WindowHandle, 'Memory Image', 'window', 12, 12, 'black', 'true')
get_image_size (Image, Width, Height)
create_scaled_img (Image, Width / 10, Height / 10, 1, 1, Width, Height)
* 预处理图像
rgb1_to_gray (Image, GrayImage)
threshold (GrayImage, Region, 0, 255)
reduce_domain (GrayImage, Region, ImageReduced)
divide (ImageReduced, ImageDiv, 7)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 定义聚类中心
create_region_clustered (ImageDiv, RegionClusters, 5, 0.5, 0.5)
get_region_clustered (RegionClusters, Cluster, 4, 1, 0.1)
* 获取图像尺寸
dev_get_window_size (WindowHandle, Width, Height)
* 绘制图像
draw_image (Image, 10, 10)
* 绘制聚类中心
draw_region (RegionClusters, 8, 3)
* 绘制预测结果
draw_region (RegionClusters, 8, 2)
从上面的代码示例可以看出,无论是用Python还是HALCON实现聚类分割,都需要先读取图像数据,然后对图像进行预处理,包括阈值分割、图像分割等。接着,选择聚类中心的数量,然后使用聚类算法训练模型,最后用模型预测结果。在Python中,我们用matplotlib库可视化结果,而在HALCON中,我们用disp_continue_message和stop函数暂停并恢复,以便在不同的窗口之间移动。
5.基于图论的分割
基于图论的分割原理是将图像数据看作是由节点(像素)和边(像素之间的连接)组成的图。通常我们将图像看作是一个二值图,其中每个像素具有两个状态,例如黑色和白色。为了将图像分割为前景和背景,我们需要一个分割算法,该算法可以找到这些像素之间的关系并确定前景和背景的边界。
以下是基于图论分割的原理:
- 节点:图像中的每个像素都被视为一个节点。
- 边:像素之间的连接被视为边。如果两个像素在同一区域内并且它们之间的连接被认为是强连接,则将它们视为一个强边。
- 连通分量:图的节点和边可以形成一个连通分量。对于一个二值图,连通分量表示一组具有相同连通性的像素。
- 分割:分割算法需要找到一个方法来划分连通分量,从而将图像划分为前景和背景。
在Python中,可以使用matplotlib库中的imread和imshow函数读取图像,并使用imconnect和imtool工具箱中的connectedComponents函数来计算连通分量。以下是一个简单的例子:
import numpy as np
import matplotlib.pyplot as plt
from imtool import imread
from imtool import imconnect
image_path = 'path/to/your/image.png'
image = imread(image_path)
# 将图像转换为灰度图像
gray_image = imconnect(image)
# 显示原始图像
plt.imshow(image)
plt.show()
# 显示灰度图像
plt.imshow(gray_image)
plt.show()
halcon例子
! 加载图像
read_image (Image, 'path/to/your/image.png')
! 将图像转换为灰度图像
rgb1_to_gray (Image, GrayImage)
! 将图像分割为前景和背景
threshold (GrayImage, Regions, 32, 64)
! 创建一个连通分量矩阵
gen_connected_components (GrayImage, ConnectedComponents)
! 显示原始图像
dev_display (Image)
! 显示分割后的前景和背景图像
dev_display (Regions)
6.基于深度学习的分割
基于深度学习的图像分割是一种流行的图像处理技术,可以自动地将图像划分为具有相似颜色、纹理、形状或区域的子区域。这种技术已经在计算机视觉和图像处理领域取得了显著的进展。
-
原理
基于深度学习的分割方法主要分为两个阶段:特征提取和预测。
特征提取:
在这个阶段,模型从输入图像中提取出与分割任务相关的特征表示。深度学习模型(如卷积神经网络,CNN)通常包含多个层次和感受野,用于捕捉输入图像中不同尺度和空间位置的局部特征。特征提取的目的是将原始图像转换为一组具有空间和语义信息的特征图。
预测:
在特征提取之后,基于学习到的特征表示,分割模型预测图像中每个像素的类别。分割算法通常将像素分配给预定义的类别之一,例如前景(有物体的部分)或背景(无物体的部分)。这个过程通常是端到端训练的,也就是说,分割模型在训练过程中可以同时学习特征提取和像素分类。
-
Python和Halcon算子实现
使用Python和Halcon实现基于深度学习的图像分割的方法因模型和数据集的不同而有所不同。下面分别简要介绍使用卷积神经网络(CNN)和边缘检测算子实现的方法。
(1)Python和Keras实现
首先,使用Keras搭建一个简单的CNN模型。然后,使用提供的图像数据集训练模型,并使用模型进行图像分割。
from keras.applications.densenet import densenet161
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Conv2D, Dropout, Flatten
from keras.optimizers import Adam
# 1. 准备数据集
train_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest'
)
train_generator = train_datagen.flow_from_directory(
'input_images/train',
target_size=(64, 64),
batch_size=32,
class_mode='binary'
)
test_datagen = ImageDataGenerator(rescale=1./255)
test_generator = test_datagen.flow_from_directory(
'input_images/test',
target_size=(64, 64),
batch_size=32,
class_mode='binary'
)
# 2. 构建模型
model = Sequential()
model.add(Dense(64, input_dim=64, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(1, activation='sigmoid'))
# 3. 编译模型
model.compile(optimizer=Adam(lr=0.001), loss='binary_crossentropy', metrics=['accuracy'])
# 4. 训练模型
model.fit(train_generator, epochs=10, validation_data=test_generator, validation_freq=1)
# 5. 预测
pred = model.predict(test_generator)
print("Predicted probability for each pixel:")
for image_index, (images, labels) in enumerate(test_generator):
for i, prediction in enumerate(pred[image_index]):
print("{:<5}{:>4}{:>4}{:>4}".format(images.shape[0], prediction, labels.shape[0], i))
(2)Halcon实现
使用Halcon的Deep Classifier Component(DCM)算子实现基于深度学习的图像分割。首先,使用Halcon加载并准备图像数据集。然后,使用DCM计算模型的特征表示。最后,使用模型对输入图像进行预测。
* 加载图像数据集
read_image (Image, 'input_images/train')
* 将图像转换为HDevelop兼容的格式
convert_image_type (Image, Image, 'uint8')
* 预处理图像
gen_contour_region_xld (Contour, Image, 'contours')
deskew (Image, Image, RotationAngle)
* 分割图像
segment_contours_xld (Contour, ImageSegmented, 'contours')
* 在分割图像上提取轮廓
dev_clear_window ()
dev_display (ImageSegmented)
* 加载DCM模型
read_ocr_class_mlp ('input_images/train/class_mlp', OCRHandle)
* 准备特征图
set_system ('output_image_size', [32, 32])
resize_image (ImageSegmented, Image, [64, 64])
* 使用DCM计算特征表示
region_to_smooth (ImageSegmented, ImageSmooth, 'blobs')
connection (ImageSmooth, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 80000, 100000)
* 使用DCM计算特征表示
connection (SelectedRegions, ConnectedRegions)
filter_circle (ConnectedRegions, FilteredRegions, [3, 3], -1)
* 特征图
gen_feature_extractor_contours_xld (FeatureExtractor, FilteredRegions, 'contours')
* 创建图像
gen_image_rgb (Image, 32, 32, 'gray', 'rgb')
* 加载模型
load_model (OCRHandle, 'input_images/train/class_mlp')
* 预测图像
predict_image (Image, ImagePredicted, OCRHandle)
* 显示预测结果
dev_display (ImagePredicted)
disp_message (Image, 'Image predicted', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()