在OpenCV中调用函数cvShowImage,如果图像的长或宽超过了屏幕的分辨率,那么将无法查看到全图,这时候就希望有一个滚动条(scroll bar)来帮助浏览,而原生的OpenCV中并没有提供这样的函数。下面这段代码展示了怎么通过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; }