一、前言
逆透视的原理在网上有许多的说明,但是实际可以使用的代码却并不多。
代码并非完全原创,但是这种形式对于初学者会更友好
二、代码说明
1、定义部分
定义输入输出图像尺寸及数组
//输入图片尺寸
#define CAMERA_H 60
#define CAMERA_W 94
//输出图片尺寸
#define OUT_H 60
#define OUT_W 94
uint8 image[CAMERA_H][CAMERA_W]; //原图像
uint8 image_final[OUT_H][OUT_W]; //逆变换图像
double map_square[CAMERA_H][CAMERA_W][2];//现实映射
int map_int[OUT_H][OUT_W][2];//图像映射
2、模型计算部分
此部分用于计算现实与图像之间的映射关系
同一摄像头角度和高度对应的模型完全相同,只需要在主程序开始前计算一次即可
具体的参数调节详见注释
void Calculate(void)//计算逆变换模型 一般放在最早只运算一次 比较费时间 同一摄像头角度以及高度模型完全一样
{
double angle = 0.8;//摄像头俯仰角 必须小于1 摄像头越平值越大
double dep = 3.8;//视点到投影面距离
double prop_j = 1;//上下宽度矫正,大于1
double prop_i = 0;//密度修正系数,大于-1,小于1
double j_large = 1.6;//横向放大倍数
uint8 i_abodon = 7;//上方舍弃的行距离 舍弃行数越多图像前瞻越少,图像也越宽
double hight = 50;//摄像头高度(调节也没有效果,只改变参数坐标)
uint8 i;//图像从上到下行数
uint8 j;//图像从左到右行数
uint8 ii;
//图片坐标
double xg;
double yg;
//原始坐标
double x0;
double y0;
double zt;
double sin_a;
double cos_a;
sin_a = sin(angle);
cos_a = cos(angle);
//初始化摄像头坐标系
for (i=0; i<CAMERA_H; i++)
{
for (j=0; j<CAMERA_W; j++)
{
map_square[i][j][0] = ((float)CAMERA_H/2 - (float)i + 0.5)/10;
map_square[i][j][1] = ((float)j - (float)CAMERA_W/2 + 0.5)/10;
}
}
//横向拉伸(微调)
for (i=0; i<CAMERA_H; i++)
{
for (j=0; j<CAMERA_W; j++)
{
map_square[i][j][1] = map_square[i][j][1] * (1*(CAMERA_H-1-i) + (1/prop_j)*i)/(CAMERA_H-1);
}
}
//逆透视变换……直接套公式
for (i=0; i<CAMERA_H; i++)
{
for (j=0; j<CAMERA_W; j++)
{
xg = map_square[i][j][1];
yg = map_square[i][j][0];
y0 = (yg*dep + hight*cos_a*yg + hight*dep*sin_a)/(dep*cos_a-yg*sin_a);
zt = -y0*sin_a-hight*cos_a;
x0 = xg * (dep-zt) /dep;
map_square[i][j][1] = x0;
map_square[i][j][0] = y0;
}
}
double prop_x;//横坐标缩放比例
prop_x = (OUT_W-1)/(map_square[i_abodon][CAMERA_W-1][1] - map_square[i_abodon][0][1]);
for (i=0; i<CAMERA_H; i++)
{
for (j=0; j<CAMERA_W; j++)
{
map_square[i][j][1] *= prop_x;
map_square[i][j][1] *= j_large;
map_square[i][j][1] = map_square[i][j][1] + OUT_W/2 -0.5*OUT_W/CAMERA_W;
}
}
//前后方向
double move_y;
double prop_y;
move_y = map_square[CAMERA_H-1][0][0];
for (i=0; i<CAMERA_H; i++)
{
for (j=0; j<CAMERA_W; j++)
{
map_square[i][j][0] -= move_y;
}
}
prop_y = (OUT_H-1)/map_square[i_abodon][0][0];
for (i=0; i<CAMERA_H; i++)
{
for (j=0; j<CAMERA_W; j++)
{
map_square[i][j][0] *= prop_y;
map_square[i][j][0] = OUT_H - OUT_H/CAMERA_H - map_square[i][j][0];
}
}
//前后拉伸
double dis_ever[CAMERA_H];
double dis_add[CAMERA_H];
double adjust_y[CAMERA_H];//每一行调整的值
//计算每行代表的宽度(原为1)
for (i=0; i<CAMERA_H; i++)
{
dis_ever[i] = ((1+prop_i)*(CAMERA_H-1-i) + (1-prop_i)*i)/(CAMERA_H-1);
}
dis_add[0] = 0;
for (i=0; i<CAMERA_H; i++)
{
if(i==0)
{
dis_add[i] = 0;
}
else
{
dis_add[i] = dis_add[i-1] + dis_ever[i-1];
}
}
adjust_y[0] = 1;
for (i=1; i<CAMERA_H; i++)
{
adjust_y[i] = dis_add[i]/i;
}
for (i=0; i<CAMERA_H; i++)
{
for (j=0; j<CAMERA_W; j++)
{
map_square[i][j][0] *= adjust_y[i];
}
}
double y_fix;
y_fix = (OUT_H-1)/map_square[CAMERA_H-1][0][0];
for (i=0; i<CAMERA_H; i++)
{
for (j=0; j<CAMERA_W; j++)
{
map_square[i][j][0] *= y_fix;
}
}
//逆映射,开始投入新尺寸的图像
//前后方向
double far;
double far_min;
int near;
for (i=0; i<OUT_H; i++)
{
far_min = OUT_H;
for (ii=0; ii<CAMERA_H; ii++)
{
far = (double)i - (double)(map_square[ii][CAMERA_H/2][0]);
if(far<0)
{
far = -far;
}
if(far<far_min)
{
far_min = far;
near = ii;
}
}
for (j=0; j<OUT_W; j++)
{
map_int[i][j][0] = near;
}
}
//左右方向
int jj;
double left_lim;
double right_lim;
for (i=0; i<OUT_H; i++)
{
//计算每一行要按照哪一行来取
ii = map_int[i][OUT_W/2][0];
left_lim = map_square[ii][0][1];
right_lim = map_square[ii][CAMERA_W-1][1];
for(j=0; j<OUT_W; j++)
{
if(j<left_lim-1 || j>right_lim+1)
{
map_int[i][j][1] = 255;
}
else
{
far_min = CAMERA_W;
for(jj=0; jj<CAMERA_W; jj++)
{
far = (double)j - (double)(map_square[ii][jj][1]);
if(far<0)
{
far = -far;
}
if(far<far_min)
{
far_min = far;
near = jj;
}
}
map_int[i][j][1] = near;
}
}
}
}
3、图像变换部分
基础的图像变换,没有什么难度
void Change(void) //图像变换函数
{
//修改图像
for (i=0; i<OUT_H; i++)
{
for(j=0; j<OUT_W; j++)
{
if(map_int[i][j][1] == 255)
{
image_final[i][j] = 0x77; //灰色
}
else
{
image_final[i][j] = image[map_int[i][j][0]][map_int[i][j][1]];
}
}
}
}
三、总结
逆透视的方法在处理许多特殊元素的时候可以起到意想不到的结果,但是其本身也具有一定的局限性,需要使用者自行抉择。