原理:正玄变换开始是用于快速的姿态矫正,即从有一定偏转角度的侧面图像变为正面图像。假设待识别的样本为的一张侧面人脸图像,即此人脸具有一定方向的偏转。可以看到图像显示出一边被压缩,另一边被放大的效果。而一张正面人脸则是两边对称的。所以以人脸的中心垂线为界,左边的列坐标取负,右边的列坐标取正,这样根据列坐标的正负不同施行不同的尺度变换,就可以压缩一边的同时扩展另一边,从而变换为正面人脸原始列坐标都是整数变换后不再是整数,此时可以进行插值运算,可求出对应像素点的灰度值。
设样本为S,大小为,平面上网格点为,经过正弦变换后,网格点上新的y值为:
根据上面的式子对图像进行变换,由组成图像上新的网格点。假设新图像在网格点处的灰度值为原图像在(x,y)点的值,由作插值求出图像在网格点上的值。
原图像
原图 左侧旋转10度 左侧旋转15度 左侧旋转20度
原图 右侧旋转10度 右侧旋转15度 右侧旋转20度
/*
write by fangqi su 2014-8-15
*/
#include
using namespace cv;
int main()
{
Mat srcpixel=imread("E:\\海信项目资料\\最全人脸库\\FERET_80_80-人脸数据库\\FERET-002\\01.tif",0);
int width=srcpixel.cols;
int height=srcpixel.rows;
double alfa=-20*CV_PI/180;
double fy=1;
int outWidth=(int)max(((1+sin(alfa))*width-sin(alfa)*(width/2)),((1-sin(alfa))*width+sin(alfa)*(width/2)));
int outHeight=height;
Mat objPixel(outHeight,outWidth,srcpixel.type());
namedWindow("ss");
namedWindow("ss1");
double x=0.0;//变换后的像素坐标
double y=0.0;//变换后的像素纵坐标
double deta=0.85;
for(int j=0;j { y=j/fy; for(int i=0;i { if(x>width/2) { x=deta*(i+sin(alfa)*(outWidth/2))/(1+sin(alfa)); if(x<0) continue; } else { x=deta*(i-sin(alfa)*(outWidth/2))/(1-sin(alfa)); if(x<0) continue; } Point LeftTop,RightBottom,LeftBottom,RightTop; LeftTop.x=(int)x; LeftTop.y=(int)y; if(LeftTop.x>width) { continue; //LeftTop.x=width-1; } RightTop.x=LeftTop.x+1; RightTop.y=LeftTop.y; if(RightTop.x>width) { continue; //RightTop.x=width-1; } LeftBottom.x=LeftTop.x; LeftBottom.y=LeftTop.y+1; RightBottom.x=LeftTop.x+1; RightBottom.y=LeftTop.y+1; if(RightBottom.x>width) { continue; //RightBottom.x=width-1; } uchar clr1,clr2,clr3,clr4; double u,v; u=x-(int)x; v=y-(int)y; //如果坐标在图像的右下角 if((x>=width-1)&&(y>=width-1)) { clr1=srcpixel.at<uchar>(LeftTop.x,LeftTop.y); objPixel.at<uchar>(j,i)=clr1; } //如果坐标在最后一列的外侧 else if((x>=width-1)) { clr1=srcpixel.at<uchar>(LeftTop.x,LeftTop.y); clr3=srcpixel.at<uchar>(LeftBottom.x,LeftBottom.y); objPixel.at<uchar>(j,i)=(uchar)(clr1*(1-v)+clr3*v); } //如果图像在最后一行外侧 else if(y>=height-1) { clr1=srcpixel.at<uchar>(LeftTop.x,LeftTop.y); clr2=srcpixel.at<uchar>(RightTop.x,RightTop.y); objPixel.at<uchar>(j,i)=(uchar)(clr1*(1-u)+clr2*u); } else { clr1=srcpixel.at<uchar>(LeftTop); clr2=srcpixel.at<uchar>(RightTop); clr3=srcpixel.at<uchar>(LeftBottom); clr4=srcpixel.at<uchar>(RightBottom); double f1,f2; f1=clr1*(1-u)+clr2*u; f2=clr3*(1-u)+clr4*u; objPixel.at<uchar>(j,i)=(uchar)(f1*(1-v)+f2*v); } } } imshow("ss",objPixel); imshow("ss1",srcpixel); cvWaitKey(0); }