『youcans 的 OpenCV 例程200篇 - 总目录』
【youcans 的 OpenCV 例程200篇】237. 基于主成分提取的方向校正(OpenCV)
主成分分析(Principal Components Analysis,PCA)是一种基于统计的数据降维方法,又称主元素分析、主分量分析。主成分分析只需要特征值分解,就可以对数据进行压缩、去噪,应用非常广泛。
主成分分析方法得到的主成分变量具有几个特点:(1)每个主成分变量都是原始变量的线性组合;(2)主成分的数目大大少于原始变量的数目;(3)主成分保留了原始变量的绝大多数信息;(4)各主成分变量之间彼此相互独立。
5.4 OpenCV 的主成分分析方法
OpenCV 中提供了主成分分析(Principal Components Analysis,PCA)方法的实现,即 cv::PCA 类。类的声明在 include/opencv2/core.hpp 文件中,类的实现在 modules/core/src/pca.cpp 文件中。
- 成员函数:
- PCA::PCA:默认构造并初始化一个空的 PCA 结构
- PCA::backproject:将数据从 PCA 空间投影回原始空间,重建原始数据
- PCA::operator():对提供的数据执行主成分分析操作
- PCA::project:将输入数据投影到 PCA 特征空间;
- PCA::read:从指定文件读入特征值、特征向量和均值;
- PCA::write:向指定文件写入特征值、特征向量和均值;
- 属性:
- PCA::eigenvalues:协方差矩阵的特征值
- PCA::eigenvectors:协方差矩阵的特征向量
- PCA::mean:均值,投影前减去均值,投影后加上均值
PCA 类使用 Karhunen-Loeve 变换,由协方差矩阵的特征向量计算得到一组向量的正交基。
在 Python 语言中,OpenCV 提供了 PCA 类的接口函数 cv.PCACompute(),cv.PCAProject() 和 cv.PCABackProject()。
函数说明:
cv.PCACompute(data, mean[, eigenvectors=None, maxComponents=0]) → mean, eigenvectors
cv.PCACompute(data, mean, retainedVariance[, eigenvectors=None]) → mean, eigenvectors
cv.PCACompute2(data, mean[, eigenvectors=None, eigenvalues=None, maxComponents=0]) → mean, eigenvectors, eigenvalues
cv.PCACompute2(data, mean, retainedVariance[, eigenvectors=None, eigenvalues=None]) → mean, eigenvectors, eigenvaluescv.PCAProject(data, mean, eigenvectors[, result=None]) → result
cv.PCABackProject(data, mean, eigenvectors[, result=None]) → result
函数 cv.PCACompute 是 PCA::operator 的接口,用于对提供的数据执行主成分分析操作,返回均值、特征向量和特征值。
函数 **cv.PCAProject ** 是 PCA::project 的接口,用于将输入数据按选择的特征向量投影到 PCA 特征空间。
函数 cv.PCABackProject 是 PCA::backproject 的接口,用于将输入数据按选择的特征向量投影从 PCA 空间投影回原始空间,重建原始数据。
参数说明:
-
data:输入数据矩阵,对于 cv.PCACompute 和 PCAProject 是 m×P 原始数据矩阵,对于 PCABackProject 是 m×K 降维数据矩阵 (K≤P)(K \le P)(K≤P)
-
mean:均值,形状为 (1,P),如果该参数的输入为空,则通过输入数据计算均值
-
maxComponents:保留主成分的个数,默认为保留全部主成份
-
retainedVariance:保留的累计方差的百分比,据此确定保留主成分的个数(至少保留 2个主成分)
-
eigenvectors:特征向量,全部特征向量的形状为 (P,P),前 K 个特征向量的形状为 (K,P)
-
eigenvalues:特征值,全部特征向量的形状为 (P,1),前 K 个特征向量的形状为 (K,1)
例程 14.18:特征描述之PCA 方向校正
特征描述应尽可能独立于大小、平移和旋转的变化。使用主成分分析方法,可以对目标进行归一化边界/区域,获得目标的主要方向。
本例对于二维图像,通过 PCA 方法对目标进行方向校正。
(1)通过主成分分析(PCA)获得目标的主方向,将数据投影到主方向及其垂直方向上。
(2)计算目标的均值,第一主方向的角度。
(3) 以目标的均值作为质心(旋转中心),按主方向角度旋转原始图像,得到归一化的目标图像。
# 14.18 基于 PCA 的方向矫正 (OpenCV)img = cv2.imread("../images/airplane01.png", flags=1)height, width = img.shape[:2] # 512 512print(height, width)# src = cv2.resize(img, (300, 300))gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)_, binary = cv2.threshold(gray, 205, 255, cv2.THRESH_BINARY_INV)# 寻找二值化图中的轮廓,检索所有轮廓,输出轮廓的每个像素点contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # OpenCV4~fullCnts = np.zeros(img.shape[:2], np.uint8) # 绘制轮廓函数会修改原始图像fullCnts = cv2.drawContours(fullCnts, contours, -1, (255, 255, 255), thickness=3) # 绘制全部轮廓# 按轮廓的面积排序,绘制面积最大的轮廓cnts = sorted(contours, key=cv2.contourArea, reverse=True) # 所有轮廓按面积排序cnt = cnts[0] # 第 0 个轮廓,面积最大的轮廓,(1445, 1, 2)maxCnt = np.zeros(img.shape[:2], np.uint8) # 初始化最大轮廓图像cv2.drawContours(maxCnt, cnts[0], -1, (255, 255, 255), thickness=3) # 仅绘制最大轮廓 cntprint("len(contours) =", len(contours)) # contours 所有轮廓的数量print("area of max contour: ", cv2.contourArea(cnt)) # 轮廓面积print("perimeter of max contour: {:.1f}".format(cv2.arcLength(cnt, True))) # 轮廓周长# 主成分分析方法提取目标的方向markedCnt = maxCnt.copy()ptsXY = np.squeeze(cnt).astype(np.float64) # 删除维度为1的数组维度,(1445, 1, 2)->(1445, 2)mean, eigenvectors, eigenvalues = cv2.PCACompute2(ptsXY, np.array([])) # (1, 2) (2, 2) (2, 1)print("mean:{}, eigenvalues:{}".format(mean.round(1), eigenvalues[:,0].round(2)))# 绘制第一、第二主成分方向轴center = mean[0, :].astype(int) # 近似作为目标的中心 [266 281]e1xy = eigenvectors[0,:] * eigenvalues[0,0] # 第一主方向轴e2xy = eigenvectors[1,:] * eigenvalues[1,0] # 第二主方向轴p1 = (center + 0.01*e1xy).astype(np.int) # P1:[149 403]p2 = (center + 0.01*e2xy).astype(np.int) # P2:[320 332]theta = np.arctan2(eigenvectors[0,1], eigenvectors[0,0]) * 180/np.pi # 第一主方向角度 133.6cv2.circle(markedCnt, center, 6, 255, -1) # 在PCA中心位置画一个圆圈 RGBcv2.arrowedLine(markedCnt, center, p1, (255, 0, 0), thickness=3, tipLength=0.1) # 从 center 指向 pt1cv2.arrowedLine(markedCnt, center, p2, (255, 0, 0), thickness=3, tipLength=0.2) # 从 center 指向 pt2print("center:{}, P1:{}, P2:{}".format(center, p1, p2))# 根据主方向角度和中心旋转原始图像alignCnt = img.copy()cv2.circle(alignCnt, center, 8, (255,255,255), 2) # 在PCA中心位置画一个圆圈 BGRcv2.arrowedLine(alignCnt, center, p1, (0,0,255), thickness=3, tipLength=0.1) # 从 center 指向 pt1cv2.arrowedLine(alignCnt, center, p2, (0,255,0), thickness=3, tipLength=0.2) # 从 center 指向 pt2x0, y0 = int(center[0]), int(center[1])print("x0={}, y0={}, theta={:.1f}(deg)".format(x0, y0, theta))MAR1 = cv2.getRotationMatrix2D((x0,y0), theta, 1)alignCnt = cv2.warpAffine(alignCnt, MAR1, alignCnt.shape[:2], borderValue=(255,255,255)) # 白色填充# 显示图像plt.figure(figsize=(9, 6))plt.subplot(231), plt.axis('off'), plt.title("Origin")plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))plt.subplot(232), plt.axis('off'), plt.title("Binary")plt.imshow(binary, 'gray')plt.subplot(233), plt.axis('off'), plt.title("Contour")plt.imshow(fullCnts, 'gray')plt.subplot(234), plt.axis('off'), plt.title("Max contour")plt.imshow(maxCnt, 'gray')plt.subplot(235), plt.axis('off'), plt.title("Marked contour")plt.imshow(markedCnt, 'gray')plt.subplot(236), plt.axis('off'), plt.title("Alignment image")plt.imshow(cv2.cvtColor(alignCnt, cv2.COLOR_BGR2RGB))plt.tight_layout()
运行结果:
512 512
len(contours) = 42
area of max contour: 63499.5
perimeter of max contour: 1725.4
mean:[[266.2 281.6]], eigenvalues:[16866.21 7533.31]
center:[266 281], P1:[149 403], P2:[320 332]
x0=266, y0=281, theta=133.6(deg)
【本节完】
版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/125782405)
Copyright 2022 youcans, XUPT
Crated:2022-7-15
234. 特征提取之主成分分析(PCA)
235. 特征提取之主成分分析(sklearn)
236. 特征提取之主成分分析(OpenCV)
237. 基于主成分提取的方向校正(OpenCV.PCA)