在机器视觉中,特征提取是从目标图像中提取有用的视觉信息以供后续处理和识别的过程。
以下是图像处理中常见的一些特征提取技术:
-
边缘检测:边缘检测是一种常见的图像特征提取技术,它可以检测图像中的局部边缘信息。常用的边缘检测算子包括Roberts算子、Prewitt算子、Sobel算子和Canny算子等。
可参考:机器视觉初步6-1:基于梯度的图像分割 -
Harris角点检测:Harris角点检测是一种基于局部二阶导数的特征检测技术,它可以检测图像中的角点特征。角点是图像中具有较大能量的特征点,在图像匹配、姿态估计等领域具有广泛的应用。
-
SIFT(尺度不变特征变换):SIFT是一种流行的图像特征提取技术,它可以检测图像中的尺度、旋转、亮度等变化下的特征点。SIFT具有较强的尺度不变性,因此在图像匹配、计算机视觉等领域具有广泛的应用。
-
SURF(加速稳健特征变换):SURF是一种基于FAST(快速近似角点检测)和ORB(ORiented FAST and Rotated BRIEF)的特征提取技术,它在SIFT的基础上加速了特征检测的速度,并提高了特征的鲁棒性。
-
Faster R-CNN(快速区域卷积神经网络):Faster R-CNN是一种基于卷积神经网络的目标检测技术,它通过训练一个卷积神经网络来同时实现特征提取和目标检测。Faster R-CNN具有较快的检测速度,并且在目标检测领域表现优秀。
接下来我们从技术层面逐个介绍。
1.角点检测
角点检测(Corner Detection):角点是图像中亮度发生明显变化的地方,它们具有良好的旋转不变性。Harris角点检测算子可以用来检测图像中的角点。Halcon中的算子为:cornerHarris()。
用python实现:
import cv2
import numpy as np
def corner_detection(image_path):
gray = cv2.cvtColor(image_path, cv2.COLOR_BGR2GRAY)
# Harris角点检测
corners, _ = cv2.cornerHarris(gray, 2, 3, 0.04)
# Sobel 边缘检测
sobel_x = cv2.Sobel(gray, cv2.CV_32F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(gray, cv2.CV_32F, 0, 1, ksize=3)
# Prewitt 边缘检测
prewitt_x = cv2.Sobel(gray, cv2.CV_32F, 1, 0, ksize=3)
prewitt_y = cv2.Sobel(gray, cv2.CV_32F, 0, 1, ksize=3)
# convert sobel x, sobel y, prewitt x and prewitt y to float
sobel_x = cv2.convertScaleAbs(sobel_x)
sobel_y = cv2.convertScaleAbs(sobel_y)
prewitt_x = cv2.convertScaleAbs(prewitt_x)
prewitt_y = cv2.convertScaleAbs(prewitt_y)
# merge sobel x and sobel y and prewitt x and prewitt y
combined = np.concatenate((sobel_x, sobel_y), axis=0)
combined = np.concatenate((prewitt_x, prewitt_y), axis=0)
# merge and reduce combined
combined = np.amax(combined)
# filter out zeros
combined = np.where(combined == 0, 0, combined)
# Detect corners using cv2.cornerSubPix method
corners = cv2.cornerSubPix(gray, (5, 5), (-1, -1), cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 11, 2)
return combined, corners
image_path = "path/to/your/image.jpg"
combined, corners = corner_detection(image_path)
cv2.imshow("corners", combined)
cv2.waitKey(0)
cv2.destroyAllWindows()
用C++实现
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
void detectCorners(Mat& image) {
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
int cornersNum = 0;
Mat corners;
cornerSubPix(gray, corners, Size(-1, -1), Size(-1, -1), TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 10, 0.1), 3, 4);
printf("Corners found: %d\n", cornersNum);
}
int main() {
Mat image = imread("path/to/your/image.jpg");
if (image.empty()) {
std::cout << "Could not load image..." << std::endl;
return -1;
}
detectCorners(image);
imshow("Corner Detection Result", image);
waitKey(0);
return 0;
}
2.纹理特征提取
纹理特征提取(Texture Feature Extraction):纹理是图像中与光照、形状、大小无关的特征,用于描述图像的复杂性。
Laplacian算子、Gabor滤波器等算子可以用来提取纹理特征。(数学原理较复杂,之后深究)
Python实现:
import cv2
import numpy as np
from skimage import morphology
# 读取图像
img = cv2.imread('input.jpg')
# 将图像转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使用Laplacian算子对图像进行边缘检测
edges = cv2.Canny(gray, 50, 150)
# 计算二阶导数
diff_x = cv2.diff(edges, edges)
diff_y = cv2.diff(edges, edges)
# 计算梯度幅值和方向
gradient_magnitude, gradient_orientation = cv2.Sobel(diff_y, cv2.CV_64F, 1, 0, ksize=3)
# 计算各向异性扩散
gradient_ac = cv2.kaze_uniform(gradient_magnitude)
# 计算标准化直方图
normalized_hist = cv2.calcHist([gradient_magnitude], [0], None, [256], [0, 256])
normalized_hist = 255 * np.log10(normalized_hist)
# 计算L1范数、L2范数和L_inf范数
norm1 = cv2.norm(diff_x, cv2.NORM_L1, dtype=cv2.CV_64F)
norm2 = cv2.norm(diff_x, cv2.NORM_L2, dtype=cv2.CV_64F)
norm_inf = cv2.norm(gradient_magnitude, cv2.NORM_INF, dtype=cv2.CV_64F)
# 计算L1范数比值
L1_ratio = norm1 / norm2
# 计算L2范数比值
L2_ratio = norm1 / norm_inf
# 计算L_inf范数比值
L_inf_ratio = norm_inf / norm1
# 使用HSV颜色空间提取各向同性纹理特征
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 计算各向同性纹理指数
erosion = cv2.erode(hsv, None, iterations=2)
dilation = cv2.dilate(erosion, None, iterations=2)
texture = cv2.convexHull(dilation)
texture_signature = cv2.GaussianBlur(texture, (9, 9), 0)
# 计算各向同性纹理指数比值
rate = L1_ratio * L2_ratio / L_inf_ratio
# 将结果显示在窗口中
cv2.imshow('Texture Feature Extracted', gray)
cv2.imshow('L1 Ratio', rate)
cv2.imshow('L2 Ratio', rate)
cv2.imshow('L_inf Ratio', rate)
cv2.waitKey(0)
cv2.destroyAllWindows()
这个脚本首先读取一张图像,将其转换为灰度图像,然后使用Canny算子检测边缘。接着,计算图像的二阶导数,并使用各向同性扩散算法1计算直方图。对直方图进行归一化处理,计算L1范数2、 L2范数和L_inf范数,并计算它们的比值。最后,使用HSV颜色空间3提取各向同性纹理特征,并计算各向同性纹理指数比值。
3.特征描述符匹配
3.1 Harris角点描述符
Harris角点描述符用于检测图像中的角点。角点是图像中具有较大梯度值的区域,这使得图像边缘或曲线等平滑区域对描述符的贡献较小。Harris角点检测的基本原理是通过计算图像中每个像素点的局部自相关函数的峰值,来检测角点。
import cv2
import numpy as np
def cornerHarris(image):
# 归一化
image = cv2.normalize(image, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U, 0)
# 计算Harris角点响应函数
M = cv2.getRotationMatrix2D((image.shape[1] / 2, image.shape[0] / 2), 0.6, 1)
# 设置检测角点数量
k = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=5)
# 计算图像自相关函数
corners = cv2.cornerHarris(k, 2, 3)
# 角点响应值阈值
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.01)
# 匹配并绘制角点
drawn_corners = cv2.drawChessboardCorners(image, (rows, cols), corners, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
return cv2.cvtColor(np.uint8(drawn_corners), cv2.COLOR_BGR2GRAY), corners
halcon实现
* 导入图像
dev_update_window ('off')
dev_close_window ()
read_image (Image, 'holly.jpg')
* 提取Harris角点响应函数
cornerHarris := cornerHarris_Gaussian(Image, 0.01, 0.04)
* 角点响应值阈值
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
* 绘制角点
draw_chessboard_corners (WindowHandle, 9, 3, [], [], [], [], RowSmallest, ColumnSmallest, RadiusSmallest, RadiusLargest, 1, 0, 3)
3.2 SIFT(尺度不变特征变换)描述符
SIFT(尺度不变特征变换)描述符是一种用于检测和描述图像中关键点(特征)的方法。SIFT描述符可以检测尺度变化、旋转和光照变化等不变性。它的主要思想是在尺度空间中寻找极值点,并将这些极值点转换为关键点。
Python实现
import cv2
import numpy as np
def sift_detection(image):
# 归一化
image = cv2.normalize(image, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U, 0)
# 获取尺度空间
scale_ranges = cv2.convertScaleAbs(np.uint8(np.array([cv2.minMaxLoc(image, 0)[1] for _ in range(3)])))
# 选择尺度和方向
scale_x = scale_ranges[0]
scale_y = scale_ranges[1]
direction = (scale_ranges[2] - scale_ranges[1]) / (scale_ranges[0] - scale_ranges[1])
# 计算尺度空间
scaled_image = cv2.pyrDown(image)
for i in range(10):
scaled_image = cv2.pyrDown(scaled_image * 2 + cv2.GaussianBlur(scaled_image, (11, 11), 0))
# 在尺度空间中搜索极值点
keypoints, descriptors = cv2.sift(scaled_image, feature_params=None, loc_params=None, contrast_threshold=0.6, n_features=200)
return keypoints, descriptors
halcon实现
dev_update_window ('off')
dev_close_window ()
read_image (Image, 'holly.jpg')
* 提取尺度空间
gen_contrast_image (Image, Image, 70, 255, 10)
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
* 计算尺度空间
gen_contrast_image (Image, Image, -70, 255, 10)
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
* 在尺度空间中搜索极值点
gen_keypoints_std_threshold_3x3 (Keypoints, 10, 0.1, 9, 'nearest_neighbor')
* 描述符
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
gen_contour_xld (Keypoints, Contours, 'reverse', 1)
convert_contour_xld_to_polygon (Contours, Polygons)
contour_descriptor (Polygons, TransposedKeypoints, 'COUNTERCLOCKWISE', 1, 'uniform_scale')
return Keypoints, TransposedKeypoints
3.3 SURF(加速稳健特征)描述符
SURF(加速稳健特征)描述符是一种高效的尺度不变特征变换(SIFT)描述符,它通过引入Hessian矩阵的方向因子来加速计算。
Python实现
import cv2
import numpy as np
def surf_detection(image):
# 归一化
image = cv2.normalize(image, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U, 0)
# 获取尺度空间
scale_ranges = cv2.convertScaleAbs(np.uint8(np.array([cv2.minMaxLoc(image, 0)[1] for _ in range(3)])))
# 选择尺度和方向
scale_x = scale_ranges[0]
scale_y = scale_ranges[1]
direction = (scale_ranges[2] - scale_ranges[1]) / (scale_ranges[0] - scale_ranges[1])
# 计算尺度空间
surf_image = cv2.pyrDown(image)
for i in range(10):
surf_image = cv2.pyrDown(surf_image * 2 + cv2.GaussianBlur(surf_image, (11, 11), 0))
# 在尺度空间中搜索极值点
surf_keypoints, surf_descriptors = cv2.surfDetector(surf_image, SurfFeatureParams(200, 25), False)
return surf_keypoints, surf_descriptors
halcon实现
dev_update_window ('off')
dev_close_window ()
read_image (Image, 'holly.jpg')
* 提取尺度空间
gen_contrast_image (Image, Image, 70, 255, 10)
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
* 计算尺度空间
gen_contrast_image (Image, Image, -70, 255, 10)
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
* 在尺度空间中搜索极值点
gen_keypoints_std_threshold_3x3 (Keypoints, 10, 0.1, 9, 'nearest_neighbor')
* 描述符
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
gen_contour_xld (Keypoints, Contours, 'reverse', 1)
convert_contour_xld_to_polygon (Contours, Polygons)
contour_descriptor (Polygons, TransposedKeypoints, 'COUNTERCLOCKWISE', 1, 'uniform_scale')
return Keypoints, TransposedKeypoints
4.基于深度学习的特征提取
基于深度学习的特征提取(Deep Learning-based Feature Extraction):深度学习可以自动学习图像中的高层语义特征。常用的深度学习模型包括卷积神经网络(CNN)、生成对抗网络(GAN)等。Python中常用的深度学习框架包括TensorFlow和PyTorch。
深度学习中常用的特征提取算法包括卷积神经网络(CNN)和循环神经网络(RNN)。这里有一个使用CNN提取手写数字识别任务特征的例子:
假设我们需要使用CNN提取手写数字识别任务的特征,可以使用MNIST数据集。数据集包含了大量手写数字的图像和对应的标签。我们可以构建一个简单的CNN模型,如下所示:
import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Conv2D, MaxPooling2D
# 加载并预处理数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape((60000, 28, 28, 1)) # 转换为适合卷积神经网络的形状
x_test = x_test.reshape((10000, 28, 28, 1))
x_train = x_train.astype('float32') # 转换为浮点数
x_test = x_test.astype('float32')
x_train /= 255 # 归一化
x_test /= 255
# 定义模型
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
# 编译模型
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
# 训练模型
model.fit(x_train, y_train, epochs=10, validation_data=(x_test, y_test))
假设我们要处理的图像是一组水果的照片,我们的目标是将这些水果分类为苹果、香蕉、橙子等。我们可以使用以下代码来构建一个卷积神经网络模型:
- 数据预处理:首先,我们需要对图像数据进行预处理,包括对图像进行归一化、调整图像尺寸、填充等。此外,我们还需要将标签数据(苹果、香蕉、橙子等)转换为数字标签。
- 构建卷积神经网络模型:我们可以使用以下代码构建一个更复杂的卷积神经网络模型:
import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
from tensorflow.keras.layers import GlobalAveragePooling2D, Dropout
from tensorflow.keras.optimizers import Adam
# 加载并预处理数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape((60000, 28, 28, 1)) # 转换为适合卷积神经网络的形状
x_test = x_test.reshape((10000, 28, 28, 1))
x_train = x_train.astype('float32') # 转换为浮点数
x_test = x_test.astype('float32')
x_train /= 255 # 归一化
x_test /= 255
# 定义模型
model = Sequential()
model.add(Conv2D(64, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(GlobalAveragePooling2D())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(3, activation='softmax'))
# 编译模型
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
# 训练模型
model.fit(x_train, y_train, epochs=10, validation_data=(x_test, y_test))
同性扩散算法是一种用于图像分割的非空穴算法,由李周芳和曹秀武于2020年提出。
同性扩散算法的基本原理是基于同性相互排斥的原理,即同性个体之间有强烈的相互排斥,会倾向于在空间中寻找一种平衡的状态,这种状态会在不同的同性个体之间传递,形成一个扩散过程。在这个过程中,同性个体会不断地调整自己的位置,直到达到一种稳定的状态。
同性扩散算法采用了一种基于染色体的编码方式,将图像中的每个像素都表示成一个染色体,其中包含了该像素的颜色信息和位置信息。然后,算法通过生成一系列新的染色体,不断地将同性个体之间的排斥力传递下去,直到达到一个稳定的状态。
同性扩散算法具有较好的稳定性和鲁棒性,适用于多种图像分割任务,如基于边缘的图像分割、基于纹理的图像分割等。同时,由于同性扩散算法在分割过程中不需要计算梯度信息,因此其计算速度也相对较快。
同性扩散算法包括以下几个步骤:
1 初始化:在图像中随机选取一些像素点作为种子点,作为同性扩散算法的起始点。然后,将这些种子点作为同性个体,根据同性个体之间的距离,计算相互排斥的力度。
2 生成新的染色体:根据同性个体之间的排斥力度,生成一系列新的染色体。这些染色体包含了同性个体的位置和排斥力度。
3 扩散染色体:将生成的新染色体按照同性个体之间的距离,逐一传递到同性个体之间,使得排斥力度不断增强。同时,将排斥力度最小的染色体作为稳定的染色体。
4 更新种子点:将稳定的染色体中的种子点替换为同性个体,并重复步骤1和2,直到没有新的染色体可以生成。
5 结果输出:将稳定的染色体中的像素点作为图像的分割结果,输出给用户。
同性扩散算法的优点是计算速度快、鲁棒性好、稳定性高,适用于多种图像分割任务,如基于边缘的图像分割、基于纹理的图像分割等。同时,由于同性扩散算法在分割过程中不需要计算梯度信息,因此其计算速度也相对较快。 ↩︎范数是一种线性代数的概念,用于度量一个向量空间中的每个向量的大小,即度量向量的长度。在向量空间中,每个向量都可以用范数来表示。范数可以有不同的定义方式,但以下是最常见的三种:
1 L1范数(绝对范数):也被称为曼哈顿范数,用向量的各个元素的绝对值之和表示,即||x||1 = ∑|x_i|。L1范数可以使得向量中元素为非零值的个数最多为1。
2 L2范数(欧几里得范数):也被称为海明范数,用向量的各个元素平方和的平方根表示,即||x||2 = √(x_1^2 + x_2^2 + … + x_n^2)。L2范数可以使得向量中元素的平方和最小。
3 Lp范数(p-范数):也被称为列维森范数,用向量的各个元素的p次方和的1/p次方表示,即||x||p = (1/p) ∑(x_i^p)。Lp范数可以使得向量中元素的p次方和最小。
在机器学习和统计中,范数通常用于距离度量和矩阵分析。例如,范数可以用于计算两个向量之间的相似度,也可以用于优化问题中的目标函数。范数还可以应用于稀疏编码和奇异值分解等领域。 ↩︎HSV(Hue,Saturation,Value)颜色空间是一种常用的颜色表示方式,它将颜色分为三个部分:色调(Hue)、饱和度(Saturation)和明度(Value)。
1 色调(Hue):色调是指颜色的基本方向,通常表示为红色、绿色或蓝色。在HSV颜色空间中,色调通常以角度表示,范围从0度(红色)到360度(蓝色)。
2 饱和度(Saturation):饱和度是指颜色的纯度,表示颜色的鲜艳程度。在HSV颜色空间中,饱和度通常用一个0到100的值表示,其中0表示完全灰色,100表示完全饱和。
3 明度(Value):明度是指颜色的明暗程度,表示颜色在黑色和白色之间的差异。在HSV颜色空间中,明度通常用一个0到100的值表示,其中0表示完全黑色,100表示完全白色。
HSV颜色空间在图像处理、计算机视觉等领域有广泛的应用。例如,在图像编辑、颜色选择、肤色检测等任务中,HSV颜色空间可以帮助我们更好地理解和分析颜色数据。 ↩︎