1.问题分析:
Windows系统显示图像有视口和窗口两个概念,视口就是展现在显示器的区域,窗口就是源图像的位置,窗口一般是加载到windows系统的图片文件。视口一般是CRect定义的,坐标原点位于左上角。而窗口坐标即图片文件坐标在左下角,DrawDIBDraw也就是从左下角开始读数据,所以当视口和窗口的坐标不变的时候,视口中的图像是颠倒的,原因就是图片文件的最下层显示在了视口的最上层。
2.解决方法:
把视口的坐标原点调整到与窗口坐标即图片文件坐标一致,都移到左下角。
3.程序实现:
以下代码红色字体即为调整视口坐标的代码,
A. int iMapMode= pDC->SetMapMode(MM_ANISOTROPIC);
设置模式
B. pDC->SetViewportExt(1,-1);
设置视口范围,前一个参数表示横坐标,后一个参数表示纵坐标,正数表示范围不变,负数表示翻转。这里(1,-1)表示视口坐标范围横坐标不变,纵坐标翻转,由原来的从上向下,变成从下向上。
C. pDC->SetViewportOrg(rcDraw.left,rcDraw.bottom);
设置视口原点坐标,用left和bottom作为原点,也就是把坐标原点移到左下角。
D. DrawDibDraw(hdd,hdc1,0, 0, rcDraw.Width(),rcDraw.Height(), &pBitmapInfo->bmiHeader,data,
0,0,img_draw.cols,img_draw.rows, DDF_SAME_DRAW|DDF_SAME_HDC);
坐标原点还按原来来写,都是0,0。
E. pDC->SetMapMode(iMapMode);
恢复原来模式
F. 源代码
void DrawImage(Mat& img,CRect rcDraw,CDC* pDC,HDRAWDIB hdd)
{
...
//HDRAWDIBhdd = DrawDibOpen();//移到initDlg()函数中,原因是它耗用90%的时间
HDC hdc1 =pDC->GetSafeHdc();
BOOL rst =DrawDibBegin(hdd,hdc1, rcDraw.Width(),rcDraw.Height(),&pBitmapInfo->bmiHeader,img_show.cols,img.rows, DDF_SAME_HDC);
DrawDibRealize(hdd,hdc1, FALSE);
LPVOID data =img_show.data;
intiMapMode = pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetViewportExt(1,-1);
pDC->SetViewportOrg(rcDraw.left,rcDraw.bottom);
DrawDibDraw(hdd,hdc1,0, 0,rcDraw.Width(),rcDraw.Height(),&pBitmapInfo->bmiHeader,data,
0,0, img_show.cols,img_show.rows,DDF_SAME_DRAW|DDF_SAME_HDC);
pDC->SetMapMode(iMapMode);
DrawDibEnd(hdd);
DrawDibClose(hdd);
...
}
4. DrawDIBDraw和StrentchBlt效率比较
单个函数比较,前者较后者几乎提高3倍速度,但DrawDibOpen()函数非常慢,如果把它和DrawDIBDraw放在一个函数内,几乎占用90%的时间,所以这个函数要在外部执行。对于实时系统,连续不断执行DrawDIBDraw时,要把(HDRAWDIB hdd = DrawDibOpen())这句代码移到函数外,只执行一次,把HDRAWDIB参数传进来即可。
参考链接:http://bbs.csdn.net/topics/390168489