(8

您所在的位置:网站首页 汇聚型边界特征是什么 (8

(8

2024-07-12 23:51| 来源: 网络整理| 查看: 265

8.4  形状特征

形状特征是用于描述图像或物体形状的特征,它们可以用于图像分析、目标检测、图像识别和计算机视觉等领域。形状特征提取的目标是从图像中提取出能够描述物体形状的信息,以便对物体进行识别、分类或测量。常用的形状特征提取方法有:边界描述子、预处理后的轮廓特征、模型拟合方法、形状上的变换。

8.4.1  边界描述子

边界描述子是一种常用的形状特征提取方法,它通过对物体的边界进行分析和描述,从中提取出能够描述形状的特征。下面我将详细介绍边界描述子的原理,并给出两个实用且稍微复杂的例子。边界描述子的实现过程如下所示:

获取物体的边界:首先需要获取物体的边界,可以通过边缘检测算法(如Canny边缘检测)或轮廓检测算法(如OpenCV中的findContours函数)来获得物体的边界。归一化边界:对于获取的边界点集,将其进行归一化处理,使得边界的起点为坐标原点,同时进行平移和缩放操作,使得边界点分布在一个固定的区域内。提取边界描述子:对归一化后的边界点集进行特征提取。常见的边界描述子包括:傅里叶描述子(Fourier Descriptors):将归一化的边界点集进行傅里叶变换,提取频域特征。傅里叶描述子可以用于对边界形状的旋转、缩放和平移具有不变性。形状上下文(Shape Context):通过计算边界点与其他点之间的相对位置关系,构建形状上下文描述子。形状上下文描述子可以用于对边界形状的旋转和尺度具有不变性。应用边界描述子:提取的边界描述子可以用于形状匹配、物体识别和分类等任务。

在现实应用中,可以通过如下两种方法实现边界描述子在形状特征提取中的应用。

(1)使用傅里叶描述子进行形状匹配

假设我们有一组图像中的物体边界,我们想要在新的图像中识别相似形状的物体,那么:

对于每个图像的物体边界,应用边缘检测算法获取边界点集。对边界点集进行归一化处理。对归一化后的边界点集计算傅里叶描述子。在新的图像中,提取物体边界并进行归一化处理。对新图像的归一化边界点集计算傅里叶描述子。对比新图像的傅里叶描述子与之前图像的傅里叶描述子,使用相似度度量方法(如欧氏距离)进行形状匹配。

例如下面是一个使用Python语言实现傅里叶描述子形状匹配的简单例子。

实例8-8:实现傅里叶描述子形状匹配

源码路径:daima\8\foliye.py

import cv2 import numpy as np def calculate_fourier_descriptor(image): # 提取轮廓 contours, _ = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) contour = contours[0] # 假设只有一个轮廓 # 计算傅里叶描述子 contour_complex = np.empty(contour.shape[:-1], dtype=complex) contour_complex.real = contour[:, 0, 0] contour_complex.imag = contour[:, 0, 1] fourier_descriptor = np.fft.fft(contour_complex) return fourier_descriptor # 读取数据库图像和查询图像 database_image = cv2.imread('database.jpg', cv2.IMREAD_GRAYSCALE) query_image = cv2.imread('query.jpg', cv2.IMREAD_GRAYSCALE) # 预处理图像(二值化等) _, database_image = cv2.threshold(database_image, 127, 255, cv2.THRESH_BINARY) _, query_image = cv2.threshold(query_image, 127, 255, cv2.THRESH_BINARY) # 计算数据库图像和查询图像的傅里叶描述子 database_descriptor = calculate_fourier_descriptor(database_image) query_descriptor = calculate_fourier_descriptor(query_image) # 计算傅里叶描述子之间的距离 distance = np.linalg.norm(database_descriptor - query_descriptor) print("Distance:", distance)

在上述代码中,请确保已准备好两幅图像作为数据库图像和查询图像,并将其命名为 database.jpg 和 query.jpg。此代码将计算数据库图像和查询图像的傅里叶描述子,并计算描述子之间的欧氏距离作为形状匹配的度量。请注意,此示例仍然假设图像中只有一个轮廓,您可能需要根据实际情况进行调整。

(2)使用形状上下文描述子进行手势识别

假设我们有一组手势的图像,我们想要对新的手势图像进行识别,那么:

对于每个手势图像,应用边缘检测算法获取边界点集。对边界点集进行归一化处理。对归一化后的边界点集计算形状上下文描述子。在新的手势图像中,提取边界并进行归一化处理。对新图像的归一化边界点集计算形状上下文描述子。对比新图像的形状上下文描述子与之前手势图像的描述子,使用相似度度量方法(如相关系数)进行手势识别。

例如下面是一个使用HOG特征和支持向量机(Support Vector Machine, SVM)实现手势识别的例子。

实例8-9:使用HOG特征和支持向量机实现手势识别

源码路径:daima\8\xing.py

import cv2 import numpy as np from sklearn.svm import SVC from skimage.feature import hog from skimage import data, exposure # 加载手势图像数据集 gesture_images = [] gesture_labels = [] for i in range(1, 6): image = cv2.imread(f'gesture_{i}.jpg', cv2.IMREAD_GRAYSCALE) gesture_images.append(image) gesture_labels.append(i) # 提取手势图像的HOG特征 gesture_hogs = [] for image in gesture_images: # 计算HOG特征 hog_features, hog_image = hog(image, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(2, 2), visualize=True) # 对HOG图像进行直方图均衡化,增强可视化效果 hog_image = exposure.rescale_intensity(hog_image, in_range=(0, 10)) gesture_hogs.append(hog_features) # 创建SVM分类器 svm = SVC() # 使用HOG特征训练分类器 svm.fit(gesture_hogs, gesture_labels) # 加载待识别手势图像 test_image = cv2.imread('test_gesture.jpg', cv2.IMREAD_GRAYSCALE) # 提取待识别手势图像的HOG特征 test_hog = hog(test_image, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(2, 2)) # 使用SVM分类器进行手势识别 predicted_label = svm.predict([test_hog]) print("Predicted Label:", predicted_label[0])

在上述代码中使用库skimage的hog函数来提取手势图像的HOG特征。然后,使用这些特征和对应的标签训练了一个支持向量机(SVM)分类器。接下来,加载待识别的手势图像,提取其HOG特征,并使用SVM分类器进行手势识别,得到预测标签。请确保您准备了手势图像数据集,并将手势图像命名为 gesture_1.jpg、gesture_2.jpg 等,并将待识别的手势图像命名为 test_gesture.jpg。此代码将根据HOG特征进行手势识别,并输出预测的手势标签。

通过边界描述子的提取和匹配,我们可以实现对具有相似形状的物体或手势进行识别和分类。这些例子展示了边界描述子在形状特征提取中的应用,具有实用性、有趣性和一定的复杂性。

8.4.2  预处理后的轮廓特征

预处理后的轮廓特征是一种常用的图像特征提取方法,它通过对图像进行预处理和轮廓提取,然后分析轮廓的形状、大小、方向等特征来描述图像的形状和结构。预处理后的轮廓特征基于对物体边界进行预处理,以减少噪声和不相关信息。常用的方法有:

(1)链码(Chain Code):是一种用于形状描述和特征提取的方法,它将轮廓视为一系列相邻的像素点的有序序列,通过记录像素点之间的连接顺序来表示轮廓的形状。链码方法具有简洁、紧凑的表示形式,适用于描述闭合轮廓的形状特征。将边界转换为链码,描述连续的边界点之间的连接关系。例如下面是一个使用轮廓近似方法(cv2.approxPolyDP)实现链码特征提取的例子。

实例8-10:使用轮廓近似方法(cv2.approxPolyDP)实现链码特征提取

源码路径:daima\8\lian.py

import cv2 import math # 读取图像并转为灰度图像 image = cv2.imread('888.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 二值化处理 _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 查找轮廓 contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 获取最长轮廓 longest_contour = max(contours, key=len) # 使用链码获取形状特征 epsilon = 0.02 * cv2.arcLength(longest_contour, True) chain_code = cv2.approxPolyDP(longest_contour, epsilon, True) # 计算距离直方图 max_distance = 0 distance_histogram = [0] * 16 for i in range(len(chain_code) - 1): dx = chain_code[i + 1][0][0] - chain_code[i][0][0] dy = chain_code[i + 1][0][1] - chain_code[i][0][1] distance = int(math.sqrt(dx ** 2 + dy ** 2) * 15 / max_distance) if max_distance != 0 else 0 distance_histogram[distance] += 1 # 打印距离直方图 for i, count in enumerate(distance_histogram): print(f'Distance {i}: {count}') # 显示轮廓和特征提取结果 cv2.drawContours(image, [longest_contour], 0, (0, 0, 255), 2) cv2.imshow('Contour', image) cv2.waitKey(0) cv2.destroyAllWindows()

在上述代码中,首先读取图像并将其转换为灰度图像,对灰度图像进行二值化处理,通过阈值将图像转换为黑白两色。然后使用cv2.findContours函数找到图像中的轮廓,根据轮廓的面积排序,选择最大的轮廓作为感兴趣的轮廓。接下来,使用cv2.approxPolyDP函数对感兴趣的轮廓进行多边形逼近,得到轮廓的链码表示。最后,计算链码中每个相邻点的距离,并统计距离的分布,并绘制距离分布直方图,展示轮廓的形状特征。执行效果如图8-3所示。

图8-3  执行效果

(2)形状上下文(Shape Context):是一种常用的形状特征提取方法,它通过描述物体轮廓上的点与其他点之间的关系来表示形状信息。形状上下文方法基于以下两个关键思想:

形状点的位置不足以完整描述形状,需要考虑其与其他点的相对位置关系。形状上下文特征用来描述形状点与其他点之间的相对距离和角度。

形状上下文的提取步骤如下所示:

选择一组形状点(例如轮廓上的点)作为参考点集。计算每个参考点与其他点之间的相对距离和角度。将这些距离和角度信息组成一个向量,形成形状上下文特征。

在Python中可以使用库Mahotas库实现形状特征提取功能,它提供了一个名为mahotas.features.zernike_moments的函数,用于计算Zernike矩特征。例如下面的代码演示了这一用法。

实例8-11:使用库Mahotas库实现形状特征提取

源码路径:daima\8\shangxia.py

import cv2 import numpy as np import mahotas.features # 读取图像 image = cv2.imread('shape.jpg', cv2.IMREAD_GRAYSCALE) # 二值化图像 _, threshold = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY) # 寻找轮廓 contours, _ = cv2.findContours(threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 提取第一个轮廓 contour = contours[0] # 计算Zernike矩特征 zernike_moments = mahotas.features.zernike_moments(contour, radius=21) # 打印特征向量 print(zernike_moments)

在上述代码中,使用OpenCV库读取图像,然后进行二值化处理。接下来,使用OpenCV的findContours函数找到图像中的轮廓,并选择第一个轮廓。最后,使用Mahotas库的zernike_moments函数计算轮廓的Zernike矩特征。

8.4.3  模型拟合方法

模型拟合方法假设物体的形状可以由特定的数学模型来表示,然后通过对模型参数进行拟合来提取形状特征。常用的方法有:

(1)椭圆拟合(Ellipse Fitting):将物体边界拟合为椭圆,并提取椭圆参数作为形状特征。当使用椭圆拟合进行图像特征提取时,通常的步骤如下:

读取图像并进行预处理,例如灰度化、二值化等操作。检测图像中的轮廓,可以使用图像处理库(如OpenCV)中的函数进行轮廓检测。对每个轮廓应用椭圆拟合算法,以获得拟合的椭圆参数。根据椭圆参数提取特征,例如椭圆的中心坐标、长轴长度、短轴长度、旋转角度等。

例如下面是一个使用库OpenCV进行椭圆拟合的例子。

实例8-13:使用库OpenCV进行椭圆拟合

源码路径:daima\8\tuo.py

import cv2 import numpy as np # 读取图像并进行预处理 image = cv2.imread('image.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) _, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 轮廓检测 contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 对每个轮廓应用椭圆拟合 ellipses = [] for contour in contours: if len(contour) >= 5: ellipse = cv2.fitEllipse(contour) ellipses.append(ellipse) # 提取特征 for ellipse in ellipses: center, axes, angle = ellipse x, y = map(int, center) major_axis, minor_axis = map(int, axes) rotation_angle = int(angle) # 在图像上绘制椭圆 cv2.ellipse(image, ellipse, (0, 255, 0), 2) # 打印特征信息 print("椭圆中心坐标:", (x, y)) print("长轴长度:", major_axis) print("短轴长度:", minor_axis) print("旋转角度:", rotation_angle) # 显示结果图像 cv2.imshow("Ellipse Fitting", image) cv2.waitKey(0) cv2.destroyAllWindows()

在上述代码中,首先读取图像并进行预处理,然后使用cv2.findContours函数检测图像中的轮廓。接下来,对每个轮廓应用cv2.fitEllipse函数进行椭圆拟合,获取拟合的椭圆参数。最后,根据椭圆参数提取特征并在图像上绘制椭圆。执行效果如图8-4所示。

图8-4  执行效果

请注意,该例子仅演示了基本的椭圆拟合和特征提取过程。根据实际需求,您可能需要根据拟合结果进行更复杂的特征提取和分析。

(2)直线拟合(Line Fitting):将物体边界拟合为直线段,并提取直线参数作为形状特征。当使用直线拟合进行图像特征提取时,基本实现步骤如下:

读取图像并进行预处理,例如灰度化、二值化等操作。检测图像中的边缘,可以使用边缘检测算法(如Canny边缘检测)。根据边缘图像,检测图像中的直线段。对检测到的直线段应用直线拟合算法,以获得拟合的直线参数。根据直线参数提取特征,例如直线的斜率、截距等。

例如下面是一个使用OpenCV库实现直线拟合的例子。

实例8-14:使用OpenCV库实现直线拟合

源码路径:daima\8\zhi.py

import cv2 import numpy as np # 读取图像并进行预处理 image = cv2.imread('image.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) edges = cv2.Canny(gray, 50, 150) # 检测直线段 lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=100, minLineLength=100, maxLineGap=10) # 绘制检测到的直线 for line in lines: x1, y1, x2, y2 = line[0] cv2.line(image, (x1, y1), (x2, y2), (0, 255, 0), 2) # 提取特征 for line in lines: x1, y1, x2, y2 = line[0] # 计算直线斜率和截距 slope = (y2 - y1) / (x2 - x1) intercept = y1 - slope * x1 # 打印特征信息 print("直线斜率:", slope) print("直线截距:", intercept) # 显示结果图像 cv2.imshow("Line Fitting", image) cv2.waitKey(0) cv2.destroyAllWindows()

在上述代码中,首先读取图像并进行预处理,然后使用Canny边缘检测算法获取图像的边缘图像。接下来,使用cv2.HoughLinesP函数检测图像中的直线段。然后,根据检测到的直线段在图像上绘制直线。最后,根据直线参数提取特征,例如直线的斜率和截距。执行效果如图8-5所示。

图8-5  执行效果

8.4.4  形状上的变换

形状上的变换方法通过将形状进行变换,如缩放、旋转和平移等,来提取形状特征。常用的方法有:

(1)尺度不变特征变换(Scale-Invariant Feature Transform,SIFT):通过对形状进行尺度空间的变换,提取尺度不变的形状特征。尺度不变特征变换是一种用于图像特征提取的算法,它可以在不同尺度、旋转和光照条件下检测和描述图像中的关键点。SIFT算法具有良好的尺度不变性和旋转不变性,因此在目标识别、图像匹配和三维重建等领域得到广泛应用。SIFT算法的主要步骤如下:

尺度空间构建:通过使用高斯差分函数对图像进行多次平滑和差分操作,构建尺度空间。关键点检测:在尺度空间中寻找极值点,作为关键点候选。关键点定位:通过在尺度空间的极值点周围进行精确定位,排除低对比度和边缘响应不明显的关键点。方向分配:为每个关键点分配主方向,用于后续的旋转不变性。关键点描述:基于关键点周围的图像区域计算特征向量,形成关键点的描述子。特征匹配:通过计算描述子之间的相似性,实现关键点的匹配。

例如下面是使用库OpenCV实现SIFT算法的例子。

实例8-15:使用库OpenCV实现SIFT算法

源码路径:daima\8\chidu.py

import cv2 # 读取图像 image = cv2.imread('image.jpg') # 创建SIFT对象 sift = cv2.SIFT_create() # 检测关键点和计算描述子 keypoints, descriptors = sift.detectAndCompute(image, None) # 绘制关键点 image_with_keypoints = cv2.drawKeypoints(image, keypoints, None) # 显示结果图像 cv2.imshow("SIFT Features", image_with_keypoints) cv2.waitKey(0) cv2.destroyAllWindows()

本实例展示了如何使用SIFT算法提取图像的关键点和描述子,并将关键点绘制在图像上。SIFT算法具有较强的尺度不变性和旋转不变性,因此提取的特征可以在不同尺度和旋转条件下进行匹配和识别。在上述代码中,首先读取图像,并使用cv2.SIFT_create()创建SIFT对象。然后,使用sift.detectAndCompute()方法检测关键点并计算描述子。接下来,使用cv2.drawKeypoints()函数将关键点绘制在图像上。最后,显示结果图像。执行效果如图8-6所示。

图8-6  执行效果

注意:SIFT算法是一种经典的特征提取方法,但由于其涉及到专利问题,OpenCV的最新版本中可能没有SIFT算法。您可以使用之前的版本,或者考虑其他开源实现的SIFT算法,如VLFeat库等。

(2)主成分分析(Principal Component Analysis,PCA):通过对形状进行主成分分析,提取主要的形状特征。主成分分析是一种常用的降维技术,也可以用于图像形状特征提取。PCA可以通过线性变换将原始数据转换为新的坐标系,使得数据在新坐标系下具有最大的方差。在图像形状特征提取中,PCA可以帮助我们找到最具代表性的形状特征,从而实现形状的描述和分类。使用PCA进行形状特征提取的基本步骤如下:

数据准备:将形状数据表示为一组特征向量或特征点集合的形式。每个特征向量或特征点表示形状的一部分。特征标准化:对特征进行标准化处理,使其具有相同的尺度和范围。可以使用均值移除和缩放等方法来实现标准化。协方差矩阵计算:计算特征的协方差矩阵,表示不同特征之间的相关性。特征值分解:对协方差矩阵进行特征值分解,得到特征值和特征向量。特征选择:选择具有最大特征值的特征向量,这些特征向量对应的特征是数据中最具代表性的形状特征。特征投影:将原始数据投影到选定的特征向量上,得到新的特征表示,即形状特征。

例如下面是一个使用库Scikit-learn实现PCA形状特征提取的例子。

实例8-16:使用库Scikit-learn实现PCA形状特征提取

源码路径:daima\8\zhu.py

import numpy as np from sklearn.decomposition import PCA # 假设有一个形状数据集,表示为特征向量的集合 shape_data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) # 创建PCA对象 pca = PCA(n_components=2) # 执行PCA降维 shape_features = pca.fit_transform(shape_data) # 输出降维后的形状特征 print(shape_features)

在上述代码中,首先准备了一个形状数据集,表示为一个特征向量的集合。然后,创建了一个PCA对象,并指定要保留的主成分数量为2。接下来,使用fit_transform()方法执行PCA降维操作,并将原始形状数据集转换为降维后的形状特征表示。最后,打印输出降维后的形状特征。执行后会输出:

[[ 7.79422863  0.        ]  [ 2.59807621  0.        ]  [-2.59807621  0.        ]  [-7.79422863 -0.        ]]

本实例展示了如何使用PCA进行形状特征提取。通过选择适当的主成分数量,我们可以获得最具代表性的形状特征,从而实现形状的描述和分类。

注意:PCA是一种常见的降维技术,也可以用于形状特征提取。除了上述示例中的简单数据集,PCA还可以应用于更复杂的形状数据,例如图像的轮廓或特征点集合。在实际应用中,您可以根据具体的问题和数据类型选择适当的形状表示方法和PCA参数设置。

注意:本节介绍的以上方法只是一些常用的形状特征提取方法,在实际应用中还可以根据具体任务和数据特点选择适合的方法。形状特征的选择和提取需要结合具体的应用场景和需求,并考虑图像的噪声、变形、光照等因素。

未完待续


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3