OpenCV 利用滚动条在不缩小的情况下显示大型图片

2022-05-07 09:26:12 浏览数 (1)

最近由于项目需要,要在不缩小的情况下显示一张2500*2000大小的图片,找到了一篇博客写的非常好,是邹老师写于2011年的: http://blog.csdn.net/chenyusiyuan/article/details/6565424

我正在试着把它翻译成C 风格,用Mat类型,实现后会再发出来

原贴代码,简单修改并加上了一些注释,在VS2010上运行成功:

代码语言:javascript复制
// Image_ScrollBar.cpp : Defines the entry point for the console application.  
//  
#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)                                                                     //如果小于1 说明原图比窗口小,窗口的宽度将重新赋值
		winWidth = imgWidth barWidth;  
	if(scale_h<1)                                                                     //如果小于1 说明原图比窗口小,窗口的高度将重新赋值
		winHeight = imgHeight barWidth;  

	int showWidth = winWidth, showHeight = winHeight; // 窗口中有效的图像显示区域的宽和高  
	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] : "1.bmp";  
	int width = 1200, height = 800;  
	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;  
}  

0 人点赞