CCD图像检测<四>
作者:一点一滴的Beer 指导教师:Chen Zheng 单位:WHU
五、 图像的校正。
5.1.纵向校正
5.1.1纵向理论校正。
图28:纵向理论校正原理图
以GD-B385型号的CCD为例,每帧图片有320行视频信号。而320行视频信号在我们进行计算机控制时,只选取其中的一部分进行模数转换然后进行计算控制。例如我们实际控制时,只对其中40行进行了AD转换。如果采用等间距采样,则在2m的前瞻视野时,会出现近处20cm就占了40行图像数据中的绝大部分,近处AD行极度稠密,而远处两个AD行之间又极为稀疏。这就造成了外部信息数字化后,远处赛道信息大量的和丢失,而近处信息又大量重复。所以,纵向校正,我们最终转换成了对视频行信号的不等间距采样问题。
我们建立如图1的纵向校正几何模型。B为摄像头视点,C为摄像头底座,A、D分别为摄像头正前方看到的最近和最远距离。然后通过计算,计算出320行视频信号的实际看到的距离之间的对应关系(当然我们先认为视频信号行是等间距地排布在成像面上的)。先通过CRT显示器观测并记录安装完毕的摄像头的如下参数。
代码语言:javascript复制double camHeight = 270;//摄像头高度----BC
double nearSight = 150;//近处视野离摄像头支架距离----AC
double viewLength = 2100;//视野纵向长度--AD
double gView2View = 380;//地视点 和 视点之间 距离--BHi
Gi为DF的320等分点中的第i个点,然后通过三角形的平行线定理和正弦定理等相关边角关系,求出BGi和AD的交点Hi,这样就得到了在AD上的320个点,相当于320行视频行对应的地面前瞻视野。通过编程将320个AH[i]打印出来,然后根据实际距离均匀化的原则从中选出40行视频信号作为采样视频信号。
5.1.2纵向实际校正。
采用校正后的结果进行采样,在对用黑线贴成的由一定大小的正方形组成的网格板进行拍摄,还原的数字图片因镜头有一定程度上的球面失真,仍会造成近处的图像密度更大,这个基本无法利用现有的技术进行理论分析。但是,可以通过对计算结果逐次逼近选择并观测实验效果来达到采样行之间的实际间距大致相同结果。
5.2横向校正
5.2.1横向理论校正。
在小车上配有一个LCD液晶显示屏来显示40行采样结果,测出摄像头采样后的视野:远近视野距离和远近视野宽度。利用简单的几何关系,大致算出每个采样行的视野宽度,然后假设60cm的赛道占了column列,则利用以下主要算法:
代码语言:javascript复制double tanXita = (farWidth - nearWidth)/(2.0*(farSight - nearSight));
……
vision[i] = (((farSight - nearSight)/39) * (39 - i)) * tanXita * 2 nearWidth;
sizeofRow[i] = (vision[i] * column)/60;
可算出对应的视野宽度在校正后应该展开的矩阵数据列数。于是得到一组校正系数sizeofRow[40]。
图29:图像的横向校正原理图
5.2.2横向实际校正。
因为镜头的失真和采样行本身的不等间距,在对网格线进行拍摄时,实际结果仍然不满足要求,通过对校正系数调整,使校正后,网格板纵向黑线应都在校正后图像的竖直方向上,得到的最后校正系数即为工程上和实际比较吻合的系数。
图30:实际校正辅助工具——网格板
5.3校正结果示例分析
图像没有进行校正如右图左,很容易判断成直道,从而小车没能来得及调整速度和转角,无法实现稳定快速进入弯道,甚至会因为误判采取直冲的策略,造成因速度过快而冲出赛道。而右图右校正后的结果就一目了然,很容易通过曲率或者其它计算判断成入弯赛道,从而及时进行自身参数调整,实现稳定快速入弯。
图31:图像的校正结果图
附件代码:
校正系数的计算
纵向采样行计算:
代码语言:javascript复制#include <iostream.h>
#include <iomanip.h>
#include <fstream.h>
#include <stdlib.h>
#include <math.h>
#define row 40
#define column 96
#define PI 3.1415926
//B车的纵向校正参数-------用CRT实际测试得。
double camHeight = 270;//摄像头高度----BC
double nearSight = 150;//近处视野离摄像头支架距离----AC
double viewLength = 2100;//视野纵向长度
double gView2View = 380;//地视点 和 视点之间 距离
double FI[320];
double BI[320];
double IG[320];
double AH[320];
double FG[320];
void WriteData()
{
fstream myfile;
myfile.open("C:\Documents and Settings\Administrator\桌面\视频行-视野.txt",ios::out);
if(!myfile)
{
cout<<"Can't open file!!"<<endl;
exit(0);
}
//向文件写入 视频 行 为实际 景物之间的 对应关系。
for (int i=0;i<320;i )
{
myfile<<"AH["<<setw(3)<<i<<"] = "<<setw(6)<<AH[i]<<endl;
}
myfile<<endl;
myfile.close();
}
void main()
{
for (int i=0;i<320;i )
{
double viewAngle = acos(camHeight/gView2View);//摄像头成像面 倾角---单位是rad
double agleBAC = atan(camHeight/nearSight);
double agleF = PI - viewAngle - agleBAC;
double DB = sqrt(camHeight * camHeight (viewLength nearSight) * (viewLength nearSight));
double AB = sqrt(camHeight * camHeight nearSight * nearSight);
double DF = (sin(agleBAC)/sin(agleF)) * viewLength;
double AF = (sin(viewAngle)/sin(agleF)) * viewLength;
double BF = AF AB ;
FG[i] = (i 1)*DF/320;
FI[i] = (sin(viewAngle)/sin(agleBAC)) * FG[i];
IG[i] = (sin(agleF)/sin(agleBAC)) * FG[i];
BI[i] = BF-FI[i];
AH[i] = AB * IG[i] /BI[i];
cout<<"AH["<<setw(3)<<i<<"] = "<<setw(6)<<AH[i]<<endl;
WriteData();
}
cout<<endl;
}
横向校正参考系数计算:
代码语言:javascript复制#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
#include <fstream.h>//将运算结果写入文件,方便分析中间结果。
//#include "outFile.h"
#define row 40
#define column 120
typedef unsigned char byte;
double vision[40];//视野宽度---CM
double sizeofRow[40];//展开后的列数
void WriteExternArray()
{
fstream myfile;
// myfile.open("D:\Program Files\MATLAB71\work\resultData.txt",ios::out);
myfile.open("C:\Documents and Settings\Administrator\桌面\A理论参考校正系数.txt",ios::out);
if(!myfile)
{
cout<<"Can't open file!!"<<endl;
exit(0);
}
//myfile<<"灰度统计值:"<<endl;
myfile<<"视野宽度:"<<endl;
for (int i=0;i<40;i )
{
myfile<<setw(9)<<vision[i]<<",";
}
myfile<<endl;
myfile<<"展开列数:"<<endl;
for (int i1=0;i1<40;i1 )
{
myfile<<setw(9)<<(int)sizeofRow[i1]<<",";
}
myfile<<endl;
myfile<<"矫正系数:"<<endl;
for (int i2=0;i2<40;i2 )
{
myfile<<setw(9)<<(int)(1000*sizeofRow[i2]/column)<<",";
}
myfile.close();
}
void main()
{
#if 1//梯形计算失真
{
double farSight = 150;//纵向视野 远端
double farWidth = 210;
double nearSight = 0;
double nearWidth = 42;
double tanXita = (farWidth - nearWidth)/(2.0*(farSight - nearSight));
cout<<setw(5)<<"行号"<<setw(16)<<"视野宽度"<<setw(16)<<"展开列数"<<setw(16)<<"矫正系数"<<endl;
cout<<"展开列数:"<<endl;
for (int i=0;i<row;i )
{
//vision[i] = ((170.0/40) * (39 - i)) * tanXita * 2 30;
vision[i] = (((farSight - nearSight)/39) * (39 - i)) * tanXita * 2 nearWidth;
sizeofRow[i] = (vision[i] * column)/60;
// cout<<setw(5)<<i<<setw(16)<<vision[i]<<setw(16)<<sizeofRow[i]<<setw(16)<<(int)(1000*sizeofRow[i]/column)<<endl;
cout<<setw(9)<<(int)sizeofRow[i]<<",";
}
cout<<endl;
WriteExternArray();
}
#endif
}
2009-8-27 书于 武汉大学