现在的位置: 首页 > 综合 > 正文

opencv中创建滚动条浏览大图

2018年02月03日 ⁄ 综合 ⁄ 共 4330字 ⁄ 字号 评论关闭

在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;
}

抱歉!评论已关闭.