1、Halcon加载图片到MFC实际上,Halcon加载图片到MFC和直接加载图片到MFC有很大的区别。Halcon加载图片到MFC的实际流程是这样的:1.Halcon在MFC窗口上面打开一个Halcon窗口。Halcon生成的窗口依附在MFC上,看起来就像MFC窗口的一部分。open_window(10,10,1024,768,(Hlong)showwin,"visible","",&CPPExpDefaultWindow);
showwin是MFC窗口的handle.
2.在Halcon窗口上面显示图片。 disp_obj(Image CPPExpDefaultWindow);
看起来就像在MFC上显示一样。
2、Halcon摄像机标定流程
摄像机分两种,一种是面扫描摄像机(Area Scan Camera),一种是线扫描摄像机(Line Scan Camera)。准确来说,叫摄像机系统比较正确。两者的区别:面扫描摄像系统是指可以通过单纯曝光取得面积影像,而线扫描摄像机,必须利用运动速度才能取得影像。两种不同的摄像系统由于成像的过程有区别,所以标定的过程也有区别,这里仅讨论面扫描摄像系统。流程如下:
1、初始摄像机参数:startCamPar:=[f,k,Sx,Sy,Cx,Cy,NumCol,NumRow]
f:焦距;k:初始为0.0;Sx:两个相邻像素点的水平距离;Sy:两个相邻像素点的垂直距离;Cx、Cy:图像中心点的位置;NumCol NumRow:图像长和宽
2、caltab_points读取标定板描述文件里面描述的点到X[],Y[],z[],描述文件由gen_caltab生成。
3、fin_caltab找到标定板的位置4、find_marks_and_pose 输出标定点的位置和外参startpose5、camera_calibration输出内参和所有外部参数3、Halcon-Canny算法
Canny算子:使用累计直方图计算两个阀值。凡是大于高阀值的一定是边缘;凡是小于低阀值的一定不是边缘;如果检测结果大于低阀值但又小于高阀值,那就要看这个像素的邻接像素中有没有超过高阀值的边缘像素:如果有的话那么它就是边缘了,否则他就不是边缘;
Halcon里面:edges_sub_pix(Image:Edges:Filter,Alpha,Low,High:)提供了这个方法。alpha:参数指定值越小,平滑越强大,会减少边缘细节。(canny刚好相反,值越大,边缘细节越少)。Low:低阀值;High:高阀值。例如:read_image(Image,'test.bmp')edges_sub_pix(Image,Edges,'canny',0.5,20,40)
4、解决Halcon不支持的视频设备
一、使用ARFrameGrabber类读取数据,具体操作如下:
1、安装DirectX SDK,注意要下载directx 9.0b 版本。打开SDK安装目录(一般在C:\DXSDK\Samples\C++\DirectShow\BaseClasses),编译BaseClasses.dsw工程,将Debug中的strmbasd.lib文件和Release中的STRMBASE.lib文件拷到C:\DXSDK\Lib目录下; 在VC的工程中加入如下库文件和包含文件: 在vc.net下选择“工具”“选项”,在左边的目录下选择“项目”“VC++目录”在右上角的筐里选择“库文件”将C:\DXSDK\Lib加入库文件中;再选择“包含文件”,将
C:\DXSDK\Include
C:\DXSDK\Samples\C++\Common\Include
C:\DXSDK\Samples\C++\DirectShow\BaseClasses
加入其中;注意:有必要将上述目录移到最上方,以免在编译时发生访问库的冲突!
项目设置添加Strmbasd.lib
2、安装并正确设置opencv,可参照opencv教程
3、复制ARFrameGrabber.h和ARFrameGrabber.cpp到工程目录下。
工程包含ARFrameGrabber.h,在程序中定义ARFrameGrabber对象。注意这里定义的对象只能是静态的全局变量(static ARFrameGrabber frameGrabber)
核心代码如下:
frameGrabber.GrabByteFrame();//抓一帧
BYTE *myBuffer = frameGrabber.GetByteBuffer();//取出图像缓存数据
int width = frameGrabber.GetWidth();
int height = frameGrabber.GetHeight(); //得出宽和高
int stride = (width * sizeof( RGBTRIPLE ) + 3) & -4;
cvInitImageHeader( &ds_frame, cvSize(width, height), 8, 3,IPL_ORIGIN_BL, 4 );
ds_frame.widthStep = stride;
cvSetData( &ds_frame, myBuffer, stride );
frame = &ds_frame;
cvSaveImage("f.bmp", frame);//把图像写入文件
//Halcon部分
Hobject myImage;
read_image(&myImage,"f.bmp");//读出文件
HImage Image = HImage(myImage);//转换为HImage类型
Image.Display(*m_pHWinFG);//在m_pHWinFG窗口显示
最终这个解决方案是放弃Halcon自带的FrameGrabber,利用SDK的ARFrameGrabber来采集图像,最后再和Halcon连接。一开始天真的我以为这样可以解决问题,又遇到更棘手的问题。SDK抓出来的BYTE送进去Halcon进行处理后的图像严重失真,估计是接口不一样。最后我走投无路了,想出了一个自认为卑鄙的办法。那就是再引入opencv,利用opencv把SDK抓的图保存为bmp文件(选用bmp主要是因为它格式简单,不用花太多的时间编码),再用Halcon读取bmp文件。最终才解决这个问题。但这个方案还是不好,毕竟它是通过读写硬盘文件来交换数据,如果需要高速运行的时候,会遇到速度瓶颈。但我只要50ms抓一帧图像,这方案还能适应这种速度。