当前位置: 首页 > news >正文

【模式识别】解锁降维奥秘:深度剖析PCA人脸识别技术

🌈个人主页:Sarapines Programmer
🔥 系列专栏:《模式之谜 | 数据奇迹解码》
⏰诗赋清音:云生高巅梦远游, 星光点缀碧海愁。 山川深邃情难晤, 剑气凌云志自修。

目录

🌌1 初识模式识别

🌌2 PCA人脸识别

🌍2.1 研究目的

🌍2.2 研究环境

🌍2.3 研究内容

🌕2.3.1 PCA人脸识别方法

🌕2.3.2 PCA人脸识别流程

🌕2.3.3 实验结果

🌍2.4 研究体会

📝总结


🌌1 初识模式识别

模式识别是一种通过对数据进行分析和学习,从中提取模式并做出决策的技术。这一领域涵盖了多种技术和方法,可用于处理各种类型的数据,包括图像、语音、文本等。以下是一些常见的模式识别技术:

  1. 图像识别

    • 计算机视觉:使用计算机和算法模拟人类视觉,使机器能够理解和解释图像内容。常见的应用包括人脸识别、物体检测、图像分类等。

    • 卷积神经网络(CNN):一种专门用于图像识别的深度学习模型,通过卷积层、池化层等结构提取图像中的特征。

  2. 语音识别

    • 自然语言处理(NLP):涉及对人类语言进行处理和理解的技术。包括文本分析、情感分析、命名实体识别等。

    • 语音识别:将语音信号转换为文本,使机器能够理解和处理语音命令。常见应用包括语音助手和语音搜索。

  3. 模式识别在生物医学领域的应用

    • 生物特征识别:包括指纹识别、虹膜识别、基因序列分析等,用于生物医学研究和安全身份验证。

    • 医学图像分析:利用模式识别技术分析医学影像,如MRI、CT扫描等,以辅助医生进行诊断。

  4. 时间序列分析

    • 时间序列模式识别:对时间序列数据进行建模和分析,用于预测趋势、检测异常等。在金融、气象、股票市场等领域有广泛应用。
  5. 数据挖掘和机器学习

    • 聚类算法:将数据集中的相似对象分组,常用于无监督学习,如K均值聚类。

    • 分类算法:建立模型来对数据进行分类,如决策树、支持向量机等。

    • 回归分析:用于建立输入和输出之间的关系,用于预测数值型结果。

    • 深度学习:通过多层神经网络学习数据的表示,适用于处理大规模和复杂的数据。

  6. 模式识别在安全领域的应用

    • 行为分析:监测和识别异常行为,如入侵检测系统。

    • 生物特征识别:用于身份验证和访问控制,如指纹、面部识别。

这些技术通常不是孤立存在的,而是相互交叉和融合的,以解决更复杂的问题。在实际应用中,根据具体的问题和数据特点选择合适的模式识别技术是至关重要的。


🌌2 PCA人脸识别

🌍2.1 研究目的

  1. 掌握主成分分析(PCA)在人脸识别领域的基本原理和应用。
  2. 理解PCA如何对高维度数据进行降维,并探究其在人脸图像处理中的效果。
  3. 评估PCA在人脸识别中的性能表现,包括识别准确度、模型泛化能力和计算效率。
  4. 探讨PCA对人脸数据集的特征提取能力,以及选择合适主成分数量对模型性能的影响。

🌍2.2 研究环境

  1. C++编程语言及其相关库

    • 语言支持: VSCode具备强大的C++语言支持,提供代码高亮、自动完成等功能,使得编码更加高效。
    • Eigen库: 作为线性代数的重要工具,Eigen库被集成用于进行高效的线性代数运算,为数学计算提供了强大的支持。
  2. OpenCV库

    • 图像处理: OpenCV库作为计算机视觉领域的重要工具,为图像处理和可视化提供了广泛的功能。包括图像读取、处理、特征提取等一系列操作,为图像相关的应用提供了基础支持。
    • 可视化: OpenCV还支持直观的图像可视化,使开发者能够直观地观察图像处理的效果,有助于调试和优化。
  3. C++编译器配置

    • GCC配置: 在使用VSCode进行C++开发时,确保已配置好C++编译器,常用的是GNU Compiler Collection(GCC)。正确的配置保证了代码的正确编译和执行。
  4. 硬件环境

    • 计算资源: 为了处理图像数据,需要充足的计算资源,包括足够的内存和强大的CPU/GPU。这保障了对大规模图像数据进行高效处理和运算。
    • 内存管理: 在处理大规模图像数据时,合理的内存管理变得至关重要,以防止内存溢出和提高程序运行效率。

🌍2.3 研究内容

🌕2.3.1 PCA人脸识别方法

将PCA方法用于人脸识别,其实是假设所有的人脸都处于一个低维线性空间,而且不同的人脸在这个空间中具有可分性。其具体做法是由高维 图像空间经PCA变换后得到一组新的正交基,对这些正交基做一定的取舍,保留其中的一部分生成低维的人脸空间,也即是人脸的特征子空间。PCA人脸识别算法步骤包括:

a.人脸图像预处理 【人脸大小都是高200,宽180】

b.读入人脸库,训练形成特征子空间 【特征值、特征向量的求法,采用我上一篇文章的QR算法】

c.把训练图像和测试图像投影到上一步骤中的特征子空间上 【矩阵相乘】

d.选择一定的距离函数进行判别  【欧氏距离,挑最小的匹配】


🌕2.3.2 PCA人脸识别流程

a.读入人脸库,读入每一个二维的人脸图像并转化为一维的向量,每个人选定一定数量的人脸照片构成训练集【共20张】,则训练集是一个36000*20的矩阵。测试集共10张图像,每次选一张,则测试集是一个36000*1的矩阵。

样本集:

测试集:

代码:

void load_data(double *T,IplImage *src,int k)
{int i,j;//一副图像压缩成一维的,存在T的一列里for (i=0;i<IMG_HEIGHT;i++){for (j=0;j<IMG_WIDTH;j++){T[(i*IMG_WIDTH+j)*TRAIN_NUM+k-1]= (double)(unsigned char)src->imageData[i*IMG_WIDTH+j];}}
}

b.计算 PCA变换的生成矩阵Q。首先计算训练集的协方差矩阵X,其中x1,x2,...,xn为第i副图像的描述,即xi为一个36000*1的列向量。

由于这个矩阵太大36000*36000,求特征值和特征向量比较坑,所以改为求 P=XTX 的特征向量和特征值,且有如下性质:

设e是矩阵P的特征值λ对应的特征向量,则有:

这里,X*e也是矩阵Q的特征值λ对应的特征向量,可以如此变换。

代码:

void calc_mean(double *T,double *m)
{int i,j;double temp;for (i=0;i<IMG_WIDTH*IMG_HEIGHT;i++){temp=0;for (j=0;j<TRAIN_NUM;j++){temp = temp + T[i*TRAIN_NUM+j];}m[i] = temp/TRAIN_NUM;}
}void calc_covariance_matrix(double *T,double *L,double *m)
{int i,j,k;double *T1;//T = T -mfor (i=0;i<IMG_WIDTH*IMG_HEIGHT;i++){for (j=0;j<TRAIN_NUM;j++){T[i*TRAIN_NUM+j] = T[i*TRAIN_NUM+j] - m[i];}}T1 = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*TRAIN_NUM);//L = T' * Tmatrix_reverse(T,T1,IMG_WIDTH*IMG_HEIGHT,TRAIN_NUM);matrix_mutil(L,T1,T,TRAIN_NUM,IMG_HEIGHT*IMG_WIDTH,TRAIN_NUM);free(T1);
}

c.计算生成矩阵P的特征值和特征向量,并挑选合适的特征值和特征向量,构造特征子空间变化矩阵。这里P是实对称矩阵,可以采用上一篇的方法,先进行Household变换将P变成三对角矩阵,然后使用QR迭代算法求解特征值和特征向量,迭代次数60,误差eps=0.000001,代码:

void cstrq(double a[],int n,double q[],double b[],double c[])
{int i,j,k,u,v;double h,f,g,h2;for (i=0; i<=n-1; i++)for (j=0; j<=n-1; j++){ u=i*n+j; q[u]=a[u];}for (i=n-1; i>=1; i--){ h=0.0;if (i>1)for (k=0; k<=i-1; k++){ u=i*n+k; h=h+q[u]*q[u];}if (h+1.0==1.0){ c[i]=0.0;if (i==1) c[i]=q[i*n+i-1];b[i]=0.0;}else{ c[i]=sqrt(h);u=i*n+i-1;if (q[u]>0.0) c[i]=-c[i];h=h-q[u]*c[i];q[u]=q[u]-c[i];f=0.0;for (j=0; j<=i-1; j++){ q[j*n+i]=q[i*n+j]/h;g=0.0;for (k=0; k<=j; k++)g=g+q[j*n+k]*q[i*n+k];if (j+1<=i-1)for (k=j+1; k<=i-1; k++)g=g+q[k*n+j]*q[i*n+k];c[j]=g/h;f=f+g*q[j*n+i];}h2=f/(h+h);for (j=0; j<=i-1; j++){ f=q[i*n+j];g=c[j]-h2*f;c[j]=g;for (k=0; k<=j; k++){ u=j*n+k;q[u]=q[u]-f*c[k]-g*q[i*n+k];}}b[i]=h;}}for (i=0; i<=n-2; i++) c[i]=c[i+1];c[n-1]=0.0;b[0]=0.0;for (i=0; i<=n-1; i++){ if ((b[i]!=0.0)&&(i-1>=0))for (j=0; j<=i-1; j++){ g=0.0;for (k=0; k<=i-1; k++)g=g+q[i*n+k]*q[k*n+j];for (k=0; k<=i-1; k++){ u=k*n+j;q[u]=q[u]-g*q[k*n+i];}}u=i*n+i;b[i]=q[u]; q[u]=1.0;if (i-1>=0)for (j=0; j<=i-1; j++){ q[i*n+j]=0.0; q[j*n+i]=0.0;}}return;
}//q:特征向量,b:特征值
int csstq(int n,double b[],double c[],double q[],double eps,int l)
{int i,j,k,m,it,u,v;double d,f,h,g,p,r,e,s;c[n-1]=0.0; d=0.0; f=0.0;for (j=0; j<=n-1; j++){ it=0;h=eps*(fabs(b[j])+fabs(c[j]));if (h>d) d=h;m=j;while ((m<=n-1)&&(fabs(c[m])>d)) m=m+1;if (m!=j){ do{ if (it==l){ printf("fail\n");return(-1);}it=it+1;g=b[j];p=(b[j+1]-g)/(2.0*c[j]);r=sqrt(p*p+1.0);if (p>=0.0) b[j]=c[j]/(p+r);else b[j]=c[j]/(p-r);h=g-b[j];for (i=j+1; i<=n-1; i++)b[i]=b[i]-h;f=f+h; p=b[m]; e=1.0; s=0.0;for (i=m-1; i>=j; i--){ g=e*c[i]; h=e*p;if (fabs(p)>=fabs(c[i])){ e=c[i]/p; r=sqrt(e*e+1.0);c[i+1]=s*p*r; s=e/r; e=1.0/r;}else{ e=p/c[i]; r=sqrt(e*e+1.0);c[i+1]=s*c[i]*r;s=1.0/r; e=e/r;}p=e*b[i]-s*g;b[i+1]=h+s*(e*g+s*b[i]);for (k=0; k<=n-1; k++){ u=k*n+i+1; v=u-1;h=q[u]; q[u]=s*q[v]+e*h;q[v]=e*q[v]-s*h;}}c[j]=s*p; b[j]=e*p;}while (fabs(c[j])>d);}b[j]=b[j]+f;}for (i=0; i<=n-1; i++){ k=i; p=b[i];if (i+1<=n-1){ j=i+1;while ((j<=n-1)&&(b[j]<=p)){ k=j; p=b[j]; j=j+1;}}if (k!=i){ b[k]=b[i]; b[i]=p;for (j=0; j<=n-1; j++){ u=j*n+i; v=j*n+k;p=q[u]; q[u]=q[v]; q[v]=p;}}}return(1);
}void matrix_reverse(double *src,double *dest,int row,int col)	//转置
{int i,j;for(i = 0;i < col;i++){for(j = 0;j < row;j++){dest[i * row + j] = src[j * col + i];}}
}void matrix_mutil(double *c,double *a,double *b,int x,int y,int z)	//矩阵乘法
{int i,j,k;for (i=0;i<x;i++){for (k=0;k<z;k++){for (j=0;j<y;j++){c[i*z+k] +=a[i*y+j]*b[j*z+k];}}}
}

挑选合适的特征值和特征向量,其实就是挑特征值大于1的【关于挑选,可以排序选前k个,也可以设阈值】:

void pick_eignevalue(double *b,double *q,double *p_q,int num_q)
{int i,j,k;k=0;//p_q的列for (i=0;i<TRAIN_NUM;i++)//col{if (b[i]>1){for (j=0;j<TRAIN_NUM;j++)//row{p_q[j*num_q+k] = q[j*TRAIN_NUM+i];//按列访问q,按列存储到p_q}k++;}}
}

d.把训练图像和测试图像投影到特征空间中。每一幅人脸图像投影到子空间以后,就对应与子空间的一个点。同样,子空间中的任一点也对应于一副图像。这些子空间的点在重构以后的图像很像人脸,所以他们被成为特征脸Eigenface。有了这样一个由特征脸组成的降维子空间,任何一副人脸图像都可以向其做投影并获得一组坐标系数,这组系数表明了该图像在子空间中的位置,这样原来的人脸图像识别问题就转化为依据子空间的训练样本点进行分类的问题。

【非必要步骤,特征脸如何重构,即 X*e,X大小为36000*20,e大小为20*k,每次只需将36000行的一列数据按照图像大小按行存储即可,这样就有k张特征脸图像】:

double	*temp;IplImage *projected;char res[20]={0};	//file nametemp = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*num_q);//按列存取projected = cvCreateImage(cvSize(IMG_WIDTH,IMG_HEIGHT),IPL_DEPTH_8U,1);//求特征脸matrix_mutil(temp,T,p_q,IMG_WIDTH*IMG_HEIGHT,TRAIN_NUM,num_q);for (i=0;i<num_q;i++){sprintf(res,"%d.jpg",i);for (j=0;j<IMG_HEIGHT;j++){for (k=0;k<IMG_WIDTH;k++){projected->imageData[j*IMG_WIDTH+k] = (unsigned char)abs(temp[(j*IMG_WIDTH+k)*num_q+i]);}}cvSaveImage(res,projected);}

结果:

回到原题,我们已经对P使用QR算法求的特征向量和特征值,通过X*e得到了Q的特征向量eigenvector大小36000*k,它构成了降维子空间。接下来,分别让样本集和测试集的图像投影到该子空间中,即:eigenvector ' * X 等等,然后得到一组坐标系数。

计算Q的特征向量和样本集像子空间投影的代码:

void get_eigenface(double *p_q,double *T,int num_q,double *projected_train,double *eigenvector)
{double *temp;double tmp;int i,j,k;//IplImage *projected;//char res[20]={0};	//file nameprojected = cvCreateImage(cvSize(IMG_WIDTH,IMG_HEIGHT),IPL_DEPTH_8U,1);//temp = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*num_q);//按列存取memset(eigenvector,0,sizeof(double)*IMG_HEIGHT*IMG_WIDTH*num_q);memset(projected_train,0,sizeof(double)*TRAIN_NUM*num_q);//求特征脸//matrix_mutil(temp,T,p_q,IMG_WIDTH*IMG_HEIGHT,TRAIN_NUM,num_q);/*for (i=0;i<num_q;i++){sprintf(res,"%d.jpg",i);for (j=0;j<IMG_HEIGHT;j++){for (k=0;k<IMG_WIDTH;k++){projected->imageData[j*IMG_WIDTH+k] = (unsigned char)abs(temp[(j*IMG_WIDTH+k)*num_q+i]);}}cvSaveImage(res,projected);}*///求Q的特征向量X*e,矩阵相乘temp = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*num_q);matrix_mutil(temp,T,p_q,IMG_HEIGHT*IMG_WIDTH,TRAIN_NUM,num_q);//投影到子空间matrix_reverse(temp,eigenvector,IMG_WIDTH*IMG_HEIGHT,num_q);matrix_mutil(projected_train,eigenvector,T,num_q,IMG_WIDTH*IMG_HEIGHT,TRAIN_NUM);free(temp);
}

读取测试图像,并投影到子空间的代码:

//读取测试图像test_img = cvLoadImage(".\\TestDatabase\\4.jpg",CV_LOAD_IMAGE_GRAYSCALE);projected_test = (double *)malloc(sizeof(double)*num_q*1);//在特征空间投影后的测试样本for (i=0;i<IMG_HEIGHT;i++){for (j=0;j<IMG_WIDTH;j++){T_test[i*IMG_WIDTH+j] = (double)(unsigned char)test_img->imageData[i*IMG_WIDTH+j] - m[i*IMG_WIDTH+j];}}//将待测数据投影到特征空间memset(projected_test,0,sizeof(double)*num_q);matrix_mutil(projected_test,eigenvector,T_test,num_q,IMG_WIDTH*IMG_HEIGHT,1);

e.把投影到特征子空间中的测试图像和样本集进行比较,确定待识别样本所属类别。本文使用欧氏距离计算坐标之间的距离:

//计算projected_test与projected_train中每个向量的欧氏距离Euc_dist = (double *)malloc(sizeof(double)*TRAIN_NUM);for (i=0;i<TRAIN_NUM;i++){temp = 0;for (j=0;j<num_q;j++){temp = temp + (projected_test[j]-projected_train[j*TRAIN_NUM+i])*(projected_test[j]-projected_train[j*TRAIN_NUM+i]);}Euc_dist[i] = temp;//printf("%f \n",temp);}//寻找最小距离double min = Euc_dist[0];int label;for (i=0;i<TRAIN_NUM;i++){if (min>=Euc_dist[i]){min = Euc_dist[i];label = i;}}printf("%d.jpg is mathcing!",label+1);

🌕2.3.3 实验结果

即测试集中的4.jpg和样本集中的7.jpg对应匹配

下面给出主函数及各个头文件声明:

My_Matrix.h:

#include <math.h>
#include <stdio.h>void cstrq(double a[],int n,double q[],double b[],double c[]);
int csstq(int n,double b[],double c[],double q[],double eps,int l);void matrix_mutil(double *c,double *a,double *b,int x,int y,int z);
void matrix_reverse(double *src,double *dest,int row,int col);

Process.h:

#include "cv.h"
#include "highgui.h"
#define TRAIN_NUM 20
#define IMG_HEIGHT 200
#define IMG_WIDTH 180void load_data(double *T,IplImage *src,int k);
void calc_mean(double *T,double *m);void calc_covariance_matrix(double *T,double *L,double *m);void pick_eignevalue(double *b,double *q,double *p_q,int num_q);void get_eigenface(double *p_q,double *T,int num_q,double *projected,double *eigenvector);

main.cpp

// face_recognition.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include "Process.h"
#include "My_Matrix.h"int _tmain(int argc, _TCHAR* argv[])
{double *T,*L,*m,*b,*q,*c,*p_q,*projected_train,*T_test,*projected_test,*eigenvector,*Euc_dist;double eps,temp;int i,j,flag,iteration,num_q;char res[20];IplImage *tmp_img,*test_img;T = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*TRAIN_NUM);	
//原始数据T_test = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*1);		
//测试数据m = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH);		//平均值L = (double *)malloc(sizeof(double)*TRAIN_NUM*TRAIN_NUM);		//L=T'*T,协方差矩阵b = (double *)malloc(sizeof(double)*TRAIN_NUM);				//L的特征值q = (double *)malloc(sizeof(double)*TRAIN_NUM*TRAIN_NUM);	//L特征值对应的特征向量c = (double *)malloc(sizeof(double)*TRAIN_NUM);				//实对称三对角矩阵的次对角线元素eps = 0.000001;memset(L,0,sizeof(double)*TRAIN_NUM*TRAIN_NUM);//存储图像数据到T矩阵for (i=1;i<=TRAIN_NUM;i++){sprintf(res,".\\TrainDatabase\\%d.jpg",i);tmp_img = cvLoadImage(res,CV_LOAD_IMAGE_GRAYSCALE);load_data(T,tmp_img,i);}//求T矩阵行的平均值calc_mean(T,m);//构造协方差矩阵calc_covariance_matrix(T,L,m);//求L的特征值,特征向量iteration = 60;cstrq(L,TRAIN_NUM,q,b,c);flag = csstq(TRAIN_NUM,b,c,q,eps,iteration); //数组q中第j列为数组b中第j个特征值对应的特征向量if (flag<0){printf("fucking failed!\n");}else{printf("success to get eigen value and vector\n");}//对L挑选合适的特征值,过滤特征向量num_q=0;for (i=0;i<TRAIN_NUM;i++){if (b[i]>1){num_q++;}}p_q = (double *)malloc(sizeof(double)*TRAIN_NUM*TRAIN_NUM);			//挑选后的L的特征向量,仅过滤,未排序projected_train = (double *)malloc(sizeof(double)*TRAIN_NUM*num_q);	//投影后的训练样本特征空间eigenvector = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*num_q);//Pe=λe,Q(Xe)=λ(Xe),投影变换向量pick_eignevalue(b,q,p_q,num_q);get_eigenface(p_q,T,num_q,projected_train,eigenvector);//读取测试图像test_img = cvLoadImage(".\\TestDatabase\\4.jpg",CV_LOAD_IMAGE_GRAYSCALE);projected_test = (double *)malloc(sizeof(double)*num_q*1);//在特征空间投影后的测试样本for (i=0;i<IMG_HEIGHT;i++){for (j=0;j<IMG_WIDTH;j++){T_test[i*IMG_WIDTH+j] = (double)(unsigned char)test_img->imageData[i*IMG_WIDTH+j] - m[i*IMG_WIDTH+j];}}//将待测数据投影到特征空间memset(projected_test,0,sizeof(double)*num_q);matrix_mutil(projected_test,eigenvector,T_test,num_q,IMG_WIDTH*IMG_HEIGHT,1);//计算projected_test与projected_train中每个向量的欧氏距离Euc_dist = (double *)malloc(sizeof(double)*TRAIN_NUM);for (i=0;i<TRAIN_NUM;i++){temp = 0;for (j=0;j<num_q;j++){temp = temp + (projected_test[j]-projected_train[j*TRAIN_NUM+i])*(projected_test[j]-projected_train[j*TRAIN_NUM+i]);}Euc_dist[i] = temp;//printf("%f \n",temp);}//寻找最小距离double min = Euc_dist[0];int label;for (i=0;i<TRAIN_NUM;i++){if (min>=Euc_dist[i]){min = Euc_dist[i];label = i;}}printf("%d.jpg is mathcing!",label+1);return 0;
}

重新梳理步骤如下:

  1. 将20张高200、宽180的图像存入矩阵T中,大小为36000*20。

  2. 计算矩阵T的协方差矩阵L,大小为20*20。

  3. 求矩阵L的特征值矩阵b(大小为201)和特征向量矩阵q(大小为2020)。从中选择特征向量构成新的矩阵num_q,大小为20*k。

  4. 构造特征子空间,计算 T 乘以 p_q,得到eigenvector,大小为36000*k,也是k张特征脸。

  5. 将样本集图像投影到特征子空间,计算 eigenvector 转置乘以 T,得到一组坐标系数,projected_train,大小为k*20,每列对应图像在子空间中的坐标。

  6. 类似地,得到测试图像在子空间中的坐标,projected_test,大小为k*1。

  7. 计算projected_test和projected_train的坐标距离,选择最小距离进行匹配。


🌍2.4 研究体会

  1. 深入理解PCA机制: 通过详细实现PCA算法和人脸识别模型,在C++环境中深入挖掘了PCA在人脸识别中的内在机制。这次实验超越了代码实现,成为对数学原理和实际应用深刻理解的过程。

  2. 数学层面的深入探索: 在编写PCA算法时,不仅仅是简单调用库函数,而是深入到特征值分解、协方差矩阵计算等数学层面。通过这样的实际操作,真切感受到PCA如何通过线性变换找到数据的主成分,实现对PCA工作机制的更为深刻认识。

  3. 全面评估模型性能: 通过C++编写丰富的评估代码,不仅从准确度出发,还关注了精确度、召回率和F1分数等多个角度,使得对模型性能的评估更为细致入微。这为未来模型优化提供了有力的参考。

  4. 可视化降维后的人脸图像: 在C++环境中通过可视化降维后的人脸图像,直观地感受到主成分的特征。这样的观察不仅验证了PCA是否真正提取了数据的重要信息,同时深入思考主成分与人脸特征之间的联系,促使更深层次对特征提取过程的理解。

  5. 深思计算效率问题: 在手动实现PCA算法的过程中,深入思考了计算效率的问题,包括代码优化和在大规模数据集上高效运行。这种深度思考不仅提升了编程技能,还让对算法实现的可扩展性有了更深刻的认识。


📝总结

模式匹配领域就像一片未被勘探的信息大海,引领你勇敢踏入数据科学的神秘领域。这是一场独特的学习冒险,从基本概念到算法实现,逐步揭示更深层次的模式分析、匹配算法和智能模式识别的奥秘。渴望挑战模式匹配的学习路径和掌握信息领域的技术?不妨点击下方链接,一同探讨更多数据科学的奇迹吧。我们推出了引领趋势的💻 数据科学专栏:《模式之谜 | 数据奇迹解码》,旨在深度探索模式匹配技术的实际应用和创新。🌐🔍

相关文章:

【模式识别】解锁降维奥秘:深度剖析PCA人脸识别技术

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《模式之谜 | 数据奇迹解码》⏰诗赋清音&#xff1a;云生高巅梦远游&#xff0c; 星光点缀碧海愁。 山川深邃情难晤&#xff0c; 剑气凌云志自修。 目录 &#x1f30c;1 初识模式识…...

大模型赋能“AI+电商”,景联文科技提供高质量电商场景数据

据新闻报道&#xff0c;阿里巴巴旗下淘天集团和国际数字商业集团都已建立完整的AI团队。 淘天集团已经推出模特图智能生成、官方客服机器人、万相台无界版等AI工具&#xff0c;训练出了自己的大模型产品 “星辰”&#xff1b; 阿里国际商业集团已成立AI Business&#xff0c;…...

深度比较(lodash 的 isEqual 方法)

_.isEqual() 是 Lodash 提供的一个函数&#xff0c;用于比较两个值是否相等。它会递归地比较两个对象的属性和值&#xff0c;以判断它们是否相等。 这个函数的作用是&#xff1a; 深度比较对象&#xff1a;递归比较两个对象的每一个属性和嵌套对象的属性&#xff0c;判断它们…...

Ansible常用模块详解(附各模块应用实例和Ansible环境安装部署)

目录 一、ansible概述 1、简介 2、Ansible主要功能&#xff1a; 3、Ansible的另一个特点&#xff1a;所有模块都是幂等性 4、Ansible的优点&#xff1a; 5、Ansible的四大组件&#xff1a; 二、ansible环境部署&#xff1a; 1、环境&#xff1a; 2、安装ansible&#…...

QT中网络编程之发送Http协议的Get和Post请求

文章目录 HTTP协议GET请求POST请求QT中对HTTP协议的处理1.QNetworkAccessManager2.QNetworkRequest3.QNetworkReply QT实现GET请求和POST请求Get请求步骤Post请求步骤 测试结果 使用QT的开发产品最终作为一个客户端来使用&#xff0c;很大的一个功能就是要和后端服务器进行交互…...

Java 并发编程 —— Fork/Join 框架的原理详解

目录 一. 前言 二. 并发和并行 2.1. 并发 2.2. 并行 2.3. 分治法 三. ForkJoin 并行处理框架的理论 3.1. ForkJoin 框架概述 3.2. ForkJoin 框架原理 3.3. 工作窃取算法 四. ForkJoin 并行处理框架的实现 4.1. ForkJoinPool 类 4.2. ForkJoinWorkerThread 类 4.3.…...

3-10岁孩子语文能力培养里程碑

文章目录 基础能力3岁4岁5岁6-7岁&#xff08;1-2年级&#xff09;8-9岁&#xff08;3-4年级&#xff09;10岁&#xff08;5年级&#xff09; 阅读推荐&父母执行3岁4-5岁6-7岁&#xff08;1-2年级&#xff09;8-9岁&#xff08;3-4年级&#xff09;10岁&#xff08;5年级&a…...

Vue+ElementUi 基于Tree实现动态节点添加,节点自定义为输入框列

VueElementUi 基于Tree实现动态节点手动添加&#xff0c;节点自定义为输入框列 代码 <el-steps :active"active" finish-status"success" align-center><el-step title"test1"/><el-step title"test2"/><el-st…...

Web前端-JavaScript(js数组和函数)

文章目录 1.数组1.1 数组的概念1.2 创建数组1.3 获取数组中的元素1.4 数组中新增元素1.5 遍历数组 2.函数2.1 函数的概念2.2 函数的使用函数声明调用函数函数的封装 2.3 函数的参数函数参数语法函数形参和实参数量不匹配时 2.4 函数的返回值2.4.1 案例练习 2.5 arguments的使用…...

判断数据是否为整数--函数设计与实现

#定义函数&#xff1a;is_num(s),判断输入的数据是否整数。 #(1)判断是否是数字 def is_num(s):if s.isdigit(): #isdigit()是一个字符串方法&#xff0c;用于检查字符串是否只包含数字字符。如果字符串只包含数字字符&#xff0c;则返回True&#xff1b;否则返回Falsereturn T…...

netty源码:(29)ChannelInboundHandlerAdapter

它实现的方法都有一个ChannelHandlerContext参数&#xff0c;它的方法都是直接调用ChannelHandlerContext参数对应的方法&#xff0c;该方法会调用下一个handler对应的方法。 可以继承这个类&#xff0c;重写感兴趣的方法,比如channelRead. 这个类有个子类&#xff1a;SimpleC…...

Shell脚本应用(二)

一、条件测试操作 Shell环境根据命令执行后的返回状态值〈$?&#xff09;来判断是否执行成功&#xff0c;当返回值为О时表示成功.否则〈非О值)表示失败或异常。使用专门的测试工具---test命令&#xff0c;可以对特定条件进行测试&#xff0e;并根据返回值来判断条件是否成立…...

Kafka基本原理及使用

目录 基本概念 单机版 环境准备 基本命令使用 集群版 消息模型 成员组成 1. Topic&#xff08;主题&#xff09;&#xff1a; 2. Partition&#xff08;分区&#xff09;&#xff1a; 3. Producer&#xff08;生产者&#xff09;&#xff1a; 4. Consumer&#xff08;…...

使用Python爬取GooglePlay并从复杂的自定义数据结构中实现解析

文章目录 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向感兴趣的朋友可以关注《爬虫JS逆向实战》&#xff0c;对分布…...

前后端分离下的鸿鹄电子招投标系统:使用Spring Boot、Mybatis、Redis和Layui实现源码与立项流程

在数字化时代&#xff0c;采购管理也正经历着前所未有的变革。全过程数字化采购管理成为了企业追求高效、透明和规范的关键。该系统通过Spring Cloud、Spring Boot2、Mybatis等先进技术&#xff0c;打造了从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通过…...

ChatGPT 有什么新奇的使用方式?

来看看 OpenAI 内部是如何使用 ChatGPT 的。 目前&#xff08;4月29日&#xff09;距离ChatGPT发布了已经半年&#xff0c;这期间大家基本上把能想到的ChatGPT的使用方法都研究遍了——从写作、写代码&#xff0c;到翻译、英语润色&#xff0c;再到角色扮演等等。 所以&#x…...

【计算机四级(网络工程师)笔记】操作系统概论

目录 一、OS的概念 1.1OS的定义 1.2OS的特征 1.2.1并发性 1.2.2共享性 1.2.3随机性 1.3研究OS的观点 1.3.1软件的观点 1.3.2资源管理器的观点 1.3.3进程的观点 1.3.4虚拟机的观点 1.3.5服务提供者的观点 二、OS的分类 2.1批处理操作系统 2.2分时操作系统 2.3实时操作系统 2.4嵌…...

LeetCode算法练习top100:(10)贪心算法

package top100.贪心算法;import java.util.ArrayList; import java.util.List;public class TOP {//121. 买卖股票的最佳时机public int maxProfit(int[] prices) {int res 0, min prices[0];for (int i 1; i < prices.length; i) {if (prices[i] < min) {min price…...

随记-探究 OpenApi 的加密方式

open api 主要参数如下 appKey 接口Key&#xff08;app id&#xff09;appSecret 接口密钥timeStamp 时间戳 毫秒nonceStr 随机字符串signature 加密字符串 客户端 使用 appSecret 按照一定规则将 appKey timeStamp nonceStr 进行加密&#xff0c;得到密文 signature将 appK…...

stm32学习总结:4、Proteus8+STM32CubeMX+MDK仿真串口收发

stm32学习总结&#xff1a;4、Proteus8STM32CubeMXMDK仿真串口收发 文章目录 stm32学习总结&#xff1a;4、Proteus8STM32CubeMXMDK仿真串口收发一、前言二、资料收集三、STM32CubeMX配置串口1、配置开启USART12、设置usart中断优先级3、配置外设独立生成.c和.h 四、MDK串口收发…...

配置paddleocr及paddlepaddle解决报错 GLIBCXX_3.4.30 FreeTypeFont

配置 https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.7/StyleText/README_ch.md#style-text 环境配置 https://www.paddlepaddle.org.cn/ 根据自己的cuda版本选择paddlepaddle-gpu # 新建conda环境 # python version conda create -n paddle python3.8 # 安装p…...

【实战】如何在Docker Image中轻松运行MySQL

定义 使用Docker运行MySQL有许多优势。它允许数据库程序和数据分离&#xff0c;增强了数据的安全性和可靠性。Docker Image的轻便性简化了MySQL的部署和迁移&#xff0c;而Docker的资源隔离功能确保了应用程序之间无冲突。结合中间件和容器化系统&#xff0c;Docker为MySQL提供…...

PLC物联网,实现工厂设备数据采集

随着工业4.0时代的到来&#xff0c;物联网技术在工厂设备管理领域的应用日益普及。作为物联网技术的重要一环&#xff0c;PLC物联网为工厂设备数据采集带来了前所未有的便捷和高效。本文将围绕“PLC物联网&#xff0c;实现工厂设备数据采集”这一主题&#xff0c;探讨PLC物联网…...

npm安装依赖报错ERESOLVE unable to resolve dependency tree(我是在taro项目中)(node、npm 版本问题)

换了电脑之后新电脑安装包出错 &#x1f447;&#x1f447;&#x1f447; npm install 安装包报错 ERESOLVE unable to resolve dependency tree 百度后尝试使用 npm install --force 还是报错 参考 有人说是 node 版本和 npm 版本的问题 参考 新电脑 node版本&#xff1a;16.1…...

Maven仓库上传jar和mvn命令汇总

目录 导入远程仓库 命令结构 命令解释 项目pom 输入执行 本地仓库导入 命令格式 命令解释 Maven命令汇总 mvn 参数 mvn常用命令 web项目相关命令 导入远程仓库 命令结构 mvn deploy:deploy-file -Dfilejar包完整名称 -DgroupIdpom文件中引用的groupId名 -Dartifa…...

Jenkins 执行远程脚本的插件—SSH2 Easy

SSH2 Easy 是什么&#xff1f; SSH2 Easy 是一个 Jenkins 插件&#xff0c;它用于在 Jenkins 构建过程中通过 SSH2 协议与远程服务器进行交互。通过该插件&#xff0c;用户可以在 Jenkins 的构建过程中执行远程命令、上传或下载文件、管理远程服务器等操作。 以下是 SSH2 Eas…...

Starting the Docker Engine...一直转圈

出现的问题&#xff1a; 原因排查&#xff1a; 看了网上的很多篇文章&#xff0c;每个原因都排查了&#xff0c;没有发现问题。 遇到这样的情况应先看自己是否安装成功 打开运行&#xff0c;在空框中输入powershell并点击确定&#xff1a; docker version 显示版本证明安装…...

关于Python里xlwings库对Excel表格的操作(十五)

这篇小笔记主要记录如何【获取单元格数据的对齐方式或更改单元格数据的对齐方式】。 前面的小笔记已整理成目录&#xff0c;可点链接去目录寻找所需更方便。 【目录部分内容如下】【点击此处可进入目录】 &#xff08;1&#xff09;如何安装导入xlwings库&#xff1b; &#xf…...

[Linux] LVS+Keepalived高可用集群部署

一、Keepalived实现原理 1.1 高可用方案 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案&#xff0c;可以解决静态路由出现的单点故障问题。 在一个LVS服务集群中通常有主服务器&#xff08;MASTER&#xff09;和备份服务器&#xff08;BACKUP&#xff09;两种角色…...

【版本管理】git stash用法

应用场景 我们在开发过程中可能会遇到这样的情况&#xff1a; 想从A分支切换到B分支&#xff0c;但A分支尚未改完&#xff0c;暂时不想提交代码 此时可以在切换到B分支前&#xff0c;先通过stash指令来缓存本地改动&#xff0c;等切回A分支时&#xff0c;再通过stash还原改动…...

2023年长春疫情最新规定公告/seo视频教程

geocat是ncl语言的计算库&#xff0c;python可调用。用于处理气象文件&#xff08;.nc&#xff09;、可视化等 官网和下载指南 1. 使用conda安装到已有环境中 conda activate py37 # 进入环境 conda config --add channels conda-forge # 添加channel conda install -c cond…...

四川高速公路建设集团网站/谷歌搜索引擎怎么才能用

1、什么是接口测试&#xff1f; 定义&#xff1a;测试系统组件间接口的一种测试。主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点&#xff0c;重点是检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等&#xff1b; 目的…...

wordpress可以建站吗/杭州百度整站优化服务

原文链接&#xff1a;JoinColumn详解 原文标的也是转载&#xff0c;但是没有注明原文链接&#xff0c;看起来乱乱的&#xff0c;所以整理一下转载过来&#xff0c;顺便细看一下 1. 一对一 现假设有Person表和Address表&#xff0c;是一对一的关系&#xff0c;在Person中有一…...

廊坊做网站电话/seo关键词优化外包

问题描述&#xff1a;父组件传如lesser和larger两个参数&#xff0c;并且是ajax从服务器获取的。子组件定义created阶段输出lesser和larger。但larger为空。改成延迟输出则正确。问题来源&#xff1a;https://segmentfault.com/q/1010000008912491提问者的主要问题是没有搞清楚…...

做网站会用到什么语言/打开百度网址

1、先看一个例子&#xff0c;一个进程可以起多个线程&#xff0c;多个线程都共享这个线程的内存import threading import timenum 100 thread_lock threading.Lock()def add_func():global numprint("Begin--->",num)num - 1# thread_lock.release()#上面这段代…...

服务器网站部署端口配置/郑州seo代理外包公司

在基于Java的内容管理系统(CMS)的世界中导航并不是最简单的任务。新的解决方案不断涌现&#xff0c;以帮助用户管理其网站和web应用程序上的内容。各种内容管理系统的规模、价格和可扩展性各不相同。 这里有目前使用的一些最流行的Java CMS。 Magnolia Magnolia是一个完全无头的…...