http://blog.csdn.net/chenyusiyuan/article/details/6565424
很久沒發博客了,趁著近期項目需要,再和大家分享一個小程序,即在OpenCV窗口中創建水平、豎直滾動條來瀏覽大型圖像。如果我們所要顯示的圖像像素較高,例如1440*900的,而顯示器只有 1280*800的分辨率,那麼通過cvNamedWindow創建的最大窗口也只能看到部分圖像,其余的因為超出窗口大小看不到了,也沒有滾動條用來滾動觀察其余圖像,這樣,就不方便我們通過窗口對圖像進行交互操作。通常滾動條是在MFC界面上建立的,這方面的例程很多,例如http://www.opencv.org.cn/forum/viewtopic.php?f=1&t=8349 ;也有使用OpenCV的Trackbar的例子,但Trackbar只有水平滾動、沒有垂直方式,而且是按1為步長,使用時不方便、也佔用了不少窗口空間。下面這段例程展示了怎樣通過 cvSetMouseCallback, cvRect, cvRectangleR, cvResize 等一系列OpenCV函數來創建方便、可隨意定制的滾動條。
- // Image_ScrollBar.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- #include <opencv2/highgui/highgui.hpp>
- #include <opencv2/imgproc/imgproc_c.h>
- #include <iostream>
- #include <vector>
- using namespace std;
- double mx = 0, my = 0;
- int dx = 0, dy = 0, horizBar_x = 0, vertiBar_y = 0;
- bool clickVertiBar = false, clickHorizBar = false, needScroll = false;
- CvRect rect_bar_horiz, rect_bar_verti;
- void help()
- {
- printf(
- "/n"
- "This program demonstrated the use of the cvSetMouseCallback /n"
- "for viewing large image with scroll bar in a small window/n"
- "created by OpenCV highgui model. (chenyusiyuan, 2011-06-24)/n"
- "Call:/n"
- "./Image_ScrollBar [<img_filename default im.jpg> <window_width default 1400> <window_height default 700>]/n/n"
- );
- }
- void mouse_callback( int event, int x, int y, int flags, void* param )
- {
- if (needScroll)
- {
- switch( event )
- {
- case CV_EVENT_LBUTTONDOWN:
- mx = x, my = y;
- dx = 0, dy = 0;
- // 按下左鍵時光標定位在水平滾動條區域內
- if (x >= rect_bar_horiz.x && x <= rect_bar_horiz.x+rect_bar_horiz.width
- && y >= rect_bar_horiz.y && y<= rect_bar_horiz.y+rect_bar_horiz.height)
- {
- clickHorizBar = true;
- }
- // 按下左鍵時光標定位在垂直滾動條區域內
- if (x >= rect_bar_verti.x && x <= rect_bar_verti.x+rect_bar_verti.width
- && y >= rect_bar_verti.y && y<= rect_bar_verti.y+rect_bar_verti.height)
- {
- clickVertiBar = true;
- }
- break;
- case CV_EVENT_MOUSEMOVE:
- if (clickHorizBar)
- {
- dx = fabs(x-mx) > 1 ? (int)(x-mx) : 0;
- dy = 0;
- }
- if (clickVertiBar)
- {
- dx = 0;
- dy = fabs(y-my) > 1 ? (int)(y-my) : 0;
- }
- mx = x, my = y;
- break;
- case CV_EVENT_LBUTTONUP:
- mx = x, my = y;
- dx = 0, dy = 0;
- clickHorizBar = false;
- clickVertiBar = false;
- break;
- default:
- dx = 0, dy = 0;
- break;
- }
- }
- }
- void myShowImageScroll(char* title, IplImage* src_img,
- int winWidth = 1400, int winHeight = 700) // 顯示窗口大小默認為 1400×700
- {
- IplImage* dst_img;
- CvRect rect_dst, // 窗口中有效的圖像顯示區域
- rect_src; // 窗口圖像對應於源圖像中的區域
- int imgWidth = src_img->width,
- imgHeight = src_img->height,
- barWidth = 25; // 滾動條的寬度(像素)
- double scale_w = (double)imgWidth/(double)winWidth, // 源圖像與窗口的寬度比值
- scale_h = (double)imgHeight/(double)winHeight; // 源圖像與窗口的高度比值
- if(scale_w<1)
- winWidth = imgWidth+barWidth;
- if(scale_h<1)
- winHeight = imgHeight+barWidth;
- int showWidth = winWidth, showHeight = winHeight; // rect_dst 的寬和高
- int src_x = 0, src_y = 0; // 源圖像中 rect_src 的左上角位置
- int horizBar_width = 0, horizBar_height = 0,
- vertiBar_width = 0, vertiBar_height = 0;
- needScroll = scale_w>1.0 || scale_h>1.0 ? TRUE : FALSE;
- // 若圖像大於設定的窗口大小,則顯示滾動條
- if(needScroll)
- {
- dst_img = cvCreateImage(cvSize(winWidth, winHeight),src_img->depth, src_img->nChannels);
- cvZero(dst_img);
- // 源圖像寬度大於窗口寬度,則顯示水平滾動條
- if(scale_w > 1.0)
- {
- showHeight = winHeight - barWidth;
- horizBar_width = (int)((double)winWidth/scale_w);
- horizBar_height = winHeight-showHeight;
- horizBar_x = min(
- max(0,horizBar_x+dx),
- winWidth-horizBar_width);
- rect_bar_horiz = cvRect(
- horizBar_x,
- showHeight+1,
- horizBar_width,
- horizBar_height);
- // 顯示水平滾動條
- cvRectangleR(dst_img, rect_bar_horiz, cvScalarAll(255), -1);
- }
- // 源圖像高度大於窗口高度,則顯示垂直滾動條
- if(scale_h > 1.0)
- {
- showWidth = winWidth - barWidth;
- vertiBar_width = winWidth-showWidth;
- vertiBar_height = (int)((double)winHeight/scale_h);
- vertiBar_y = min(
- max(0,vertiBar_y+dy),
- winHeight-vertiBar_height);
- rect_bar_verti = cvRect(
- showWidth+1,
- vertiBar_y,
- vertiBar_width,
- vertiBar_height);
- // 顯示垂直滾動條
- cvRectangleR(dst_img, rect_bar_verti, cvScalarAll(255), -1);
- }
- showWidth = min(showWidth,imgWidth);
- showHeight = min(showHeight,imgHeight);
- // 設置窗口顯示區的 ROI
- rect_dst = cvRect(0, 0, showWidth, showHeight);
- cvSetImageROI(dst_img, rect_dst);
- // 設置源圖像的 ROI
- src_x = (int)((double)horizBar_x*scale_w);
- src_y = (int)((double)vertiBar_y*scale_h);
- src_x = min(src_x, imgWidth-showWidth);
- src_y = min(src_y, imgHeight-showHeight);
- rect_src = cvRect(src_x, src_y, showWidth, showHeight);
- cvSetImageROI(src_img, rect_src);
- // 將源圖像內容復制到窗口顯示區
- cvCopy(src_img, dst_img);
- cvResetImageROI(dst_img);
- cvResetImageROI(src_img);
- // 顯示圖像和滾動條
- cvShowImage(title,dst_img);
- cvReleaseImage(&dst_img);
- }
- // 源圖像小於設定窗口,則直接顯示圖像,無滾動條
- else
- {
- cvShowImage(title, src_img);
- }
- }
- int main(int argc, char** argv)
- {
- help();
- const char* filename = argc > 1 ? argv[1] : "im.jpg";
- int width = 1400, height = 700;
- if (4==argc)
- {
- sscanf( argv[2], "%u", &width );
- sscanf( argv[3], "%u", &height );
- }
- cvNamedWindow("Image Scroll Bar", 1);
- cvSetMouseCallback("Image Scroll Bar", mouse_callback);
- IplImage* image = cvLoadImage( filename, CV_LOAD_IMAGE_COLOR );
- if( !image )
- {
- fprintf( stderr, "Can not load %s and/or %s/n"
- "Usage: Image_ScrollBar [<img_filename default im.jpg>]/n",
- filename );
- exit(-1);
- }
- while(1)
- {
- myShowImageScroll("Image Scroll Bar", image, width, height);
- int KEY = cvWaitKey(10);
- if( (char) KEY == 27 )
- break;
- }
- cvDestroyWindow("Image Scroll Bar");
- return 0;
- }
程序還只是實現了比較初步的功能,只能通過鼠標拖曳滾動條來瀏覽圖像,不能通過鼠標中鍵滾輪實現上下滾動,這個主要是 cvSetMouseCallback 裡的 Event 不包括滾輪滑動事件,有空再探索下解決辦法。歡迎大家一起交流討論。