基于MFC&OpenCV实现的图像读取拖拽的程序
由于换了不熟悉的键盘布局(Dvorak)打字速度太慢了让我都不想用电脑了..
最近小组需要对软件的显示部分做一些改进,于是折腾了几天的MFC查遍各种资料终于达到要求……然后自己又单独实现了一遍,以后也许可以增加功能
实现的功能
1.可以根据窗口的大小调整图像比例,保证图像不失真(类似OpenGL中的正交图) 2.可以通过鼠标拖拽放大图片 3.可以利用OpenCV
调整图像比例,保证图像不失真
a.读取显示区域矩形大小,选取较短的边(宽或高)同图像相同的边比较,根据这个比率将另一条边缩放 b.利用MFC的双缓冲机制解决闪屏问题 c.显示利用了OpenCV的CvvImage类
OnDraw函数如下:
1 void CPicViewerView::OnDraw(CDC* pDC)
2 {
3 CPicViewerDoc* pDoc = GetDocument();
4 ASSERT_VALID(pDoc);
5 if (pDoc->GetReady())
6 {
7 CDC memDC; //内存绘图设备
8 CBitmap memBitmap; //内存绘图;
9 CBitmap* pOldBmp = NULL;
10 CRect rect;
11 GetClientRect(&rect);
12 memDC.CreateCompatibleDC(pDC);
13 memBitmap.CreateCompatibleBitmap(pDC,rect.right,rect.bottom);
14 pOldBmp = memDC.SelectObject(&memBitmap);
15 CBrush bkBrush( RGB(58,110,165) );
16 memDC.FillRect( &rect, &bkBrush );
17 const IplImage* t_Image = pDoc->GetImage();
18 int imageHeight = t_Image->height;
19 int imageWidth = t_Image->width;
20 if (m_oldInflate==-1) //如果显示rect发生变化,重新调整缩放率
21 {
22 if (rect.Width()>rect.Height())
23 m_inflate = 0.9*rect.Height()/imageHeight;
24 else
25 m_inflate = 0.9*rect.Width()/imageWidth;
26 m_oldInflate = m_inflate;
27 CvSize size; //根据缩放率计算目标图像大小
28 size.height=m_inflate*imageHeight;
29 size.width=m_inflate*imageWidth;
30 IplImage *Image=cvCreateImage(size,IPL_DEPTH_8U,3);
31 cvResize(t_Image,Image,CV_INTER_CUBIC);
32 CvvImage cimg;
33 cimg.CopyOf(Image);
34 //调整显示范围使其居中
35 CRect memShowRect;
36 memShowRect.left=rect.left+(rect.Width()-size.width)/2;
37 memShowRect.top=rect.top+(rect.Height()-size.height)/2;
38 memShowRect.right=rect.right;
39 memShowRect.bottom=rect.bottom;
40 m_memShowRect=memShowRect;
41 //memShowRect=rect;
42 cimg.Show(memDC.GetSafeHdc(),memShowRect.left,memShowRect.top,memShowRect.right,memShowRect.bottom);
43 cvReleaseImage(&Image);
44 }else{
45 m_oldInflate=m_inflate;
46 CvSize size; //根据缩放率计算目标图像大小
47 size.height=m_inflate*imageHeight;
48 size.width=m_inflate*imageWidth;
49 IplImage *Image=cvCreateImage(size,IPL_DEPTH_8U,3);
50 cvResize(t_Image,Image,CV_INTER_CUBIC);
51 CvvImage cimg;
52 cimg.CopyOf(Image);
53 cimg.Show(memDC.GetSafeHdc(),m_memShowRect.left,m_memShowRect.top,size.width,size.height);
54 cvReleaseImage(&Image);
55 }
56 char str[25];
57 sprintf(str, "当前的缩放率为%f" ,m_inflate);
58 memDC.TextOut(rect.right-200,rect.bottom-20,str);
59 pDC->BitBlt(rect.left,rect.top,rect.right,rect.bottom,&memDC,0,0,SRCCOPY);//将内存中画好的图显示在屏幕上
60 memDC.SelectObject(pOldBmp);
61 memDC.DeleteDC();
62 memBitmap.DeleteObject();
63 }
鼠标消息的处理
这部分参考了csdn上的一些做法,值得注意的是本程序在显示初始化时根据图像的大小适配了一个内存显示区域,因此在拖拽时只需要改变这个内存显示区域的相对位置. 另一个需要注意的是 CvvImage::Show(HDC dc, int x, int y, int w, int h, int from_x, int from_y) 这个函数,其中 x,y表示在dc中的位置. w,h表示需要绘制图像的宽高. from_x表示从图像的第from_x列开始显示。 from_y表示从图像的第from_y行开始显示。 鼠标消息的处理函数:
1 void CPicViewerView::OnLButtonDown(UINT nFlags, CPoint point)
2 {
3 if(m_memShowRect.PtInRect(point))
4 {
5 //::SetCursor(LoadCursor());
6 m_bIsPick = TRUE;
7 m_ptPre = point;
8 SetCapture();
9 }
10
11 CView::OnLButtonDown(nFlags, point);
12 }
13
14 void CPicViewerView::OnLButtonUp(UINT nFlags, CPoint point)
15 {
16 m_bIsPick = FALSE;
17 ReleaseCapture();
18
19 CView::OnLButtonUp(nFlags, point);
20 }
21
22 void CPicViewerView::OnMouseMove(UINT nflags,CPoint point)
23 {
24 if(m_bIsPick)
25 {
26 m_memShowRect.top+= point.y-m_ptPre.y;
27 m_memShowRect.bottom+= point.y-m_ptPre.y;
28 m_memShowRect.right+= point.x-m_ptPre.x;
29 m_memShowRect.left+= point.x-m_ptPre.x;
30
31 m_ptPre=point;
32 Invalidate(FALSE);
33 }
34 }
接下来可以增加些高级功能: repo url: Fork