《学习OpenCV》练习4-3

直方图的内容在《学习OpenCV》第七章有详细介绍。

#include "cv.h"
#include "highgui.h"
#include "stdio.h"

/*声明要画出的矩形结构体,结构体包含的成员有起始点坐标(x,y),宽(width),高(height)*/
CvRect g_rect;	
/*声明鼠标左键状态全局标志位,若为0则鼠标左键为弹起,若为1则鼠标左键按下*/
bool  g_mouse_flag = 0;

/*声明我的鼠标回调函数*/
void my_callback( int event, int x, int y, int flag, void* param );	
/*声明画出图像高亮部分函数*/
void high_light( IplImage* image, CvRect rect );							
/*声明画出部分指定区域颜色直方图函数*/
void Draw_hist( IplImage* img, CvRect Rect );

/*主函数*/
int main()
{
	IplImage* orginal_image = cvLoadImage( "homework_4-3.jpg" );			//载入源图像
	assert( orginal_image != NULL );										//检测源图像是否载入	
	IplImage* temp_image = cvCreateImage( cvGetSize(orginal_image),
										  orginal_image->depth,
									      orginal_image->nChannels);		//以源图像的尺寸、颜色深度(数据类型)、颜色通道创建一图像
	assert( temp_image != NULL );												
	cvNamedWindow( "homework_4-3" );												
	cvSetMouseCallback( "homework_4-3", my_callback, (void*)temp_image );	//在homework_4-3窗口处为temp_image的鼠标动作注册
	
	while (1)
	{
		IplImage* temp_image= cvCloneImage( orginal_image );				//大循环,temp_image为源图像的克隆,不断更新
		if (g_mouse_flag == true)											//如果鼠标左键被按下
		{								
			high_light( temp_image, g_rect );								//在temp_image中用高亮画出矩形g_rect
			Draw_hist( temp_image, g_rect );								//画出高亮矩形g_rect部分的颜色分布直方图
		}
		else																//如果鼠标没按下,还是照样保持
		{
			high_light( temp_image, g_rect );
			Draw_hist( temp_image, g_rect );
		}
		cvShowImage( "homework_4-3", temp_image );							//把画出高亮矩形了的图像temp_image显示
		if (cvWaitKey(30)==27)												//按ESC键退出
		{
			break;
		}
	}
	cvDestroyAllWindows();

	return 0;
}

//*****************************************************
//鼠标回调函数:根据不同鼠标动作相应不同事件
//event      :鼠标事件类型
//x,y        :事件发生时鼠标相对图像像素位置的坐标值
//flag       :指定事件发生时鼠标左键、右键等的不同状态
//param      :空指针,一般用来指向鼠标作用的图像
//*****************************************************
void my_callback( int event, int x, int y, int flag, void* param )
{
	IplImage* image = (IplImage*)(param);
	switch (event)
	{
		case CV_EVENT_LBUTTONDOWN :					//如果鼠标左键被按下
			g_mouse_flag = true;					//全局变量变为1
			g_rect = cvRect( x, y, 0, 0 );			//以鼠标按下坐标(x,y)为初始点画一个宽为0、长为0的矩形(没有移动)
			break;

		case CV_EVENT_MOUSEMOVE:					//如果鼠标左键按下时鼠标移动
			if (g_mouse_flag==true)
			{
				g_rect.width = x - g_rect.x;		//要画出的矩形的宽为鼠标横坐标减去矩形初始点的横坐标
				g_rect.height = y-g_rect.y;			//要画出的矩形的高为鼠标纵坐标减去矩形初始点的纵坐标
			}			
			break;

		case CV_EVENT_LBUTTONUP :					//如果鼠标左键按下后弹起
			g_mouse_flag=false;						//修改全局变量
			if (g_rect.width < 0)					//如果要画的矩形的宽、高小于零(向左上角方向画)时的处理
			{
				g_rect.x = g_rect.x + g_rect.width;	//交换矩形起始点与终点的坐标
				g_rect.width *= -1;
			}
			if (g_rect.height < 0)
			{
				g_rect.y = g_rect.y + g_rect.height;
				g_rect.height *= -1;
			}
			high_light(image,g_rect);				//矩形起始点、宽、高都得到处理后以高亮显示矩形
			Draw_hist(image,g_rect);				//并画出矩形区域内的颜色分布直方图
			break;
	}
}

//*****************************************************
//区域高亮函数:在指定图像上以高亮显示指定区域
//img        :输入指定图像的指针
//rect       :输入指定矩形结构体
//*****************************************************
void high_light( IplImage* img, CvRect rect )
{
	assert( img != NULL );											//判断是否有图像输入
	int row, col;
	for (row=rect.y; row<rect.y+rect.height; row++)					//for循环,row在指定矩形区域一行一行进行循环
	{
		uchar* ptr=(uchar*)(img->imageData + row*img->widthStep);	//将指针ptr指向图像每一行的首地址
		for (col=rect.x; col<rect.x+rect.width; col++)				//for循环,col在指定矩形区域内一列一列进行循环
		{
			ptr[(col*3+1)]=150;										//高亮处理
			ptr[(col*3+2)]=110;
		}
		if (row >= img->height - 1)
		{
			row = img->height;
	 	}
	}
}

//**************************************************************************
//画颜色分布直方图函数:统计指定图像指定区域的颜色分布,在新窗口画出颜色分布直方图
//img        :输入指定图像的指针
//rect       :输入指定矩形结构体
//**************************************************************************
void Draw_hist( IplImage* img, CvRect Rect )
{
	if (Rect.x<=0||Rect.y<=0||Rect.width<=0||Rect.height<=0)						//判断输入的矩形是否有效
	{
		return;
	}
	cvSetImageROI( img, Rect );														//在输入图像上设置感兴趣区域,即矩形Rect
	IplImage* hsv = cvCreateImage(/*cvSize(Rect.width ,Rect.height)*/cvGetSize(img), 8, 3 );
	IplImage* h_plane = cvCreateImage(/*cvSize(Rect.width ,Rect.height)*/cvGetSize(img), 8, 1 );
	IplImage* s_plane = cvCreateImage( cvSize(Rect.width ,Rect.height), 8, 1 );
	IplImage* v_plane = cvCreateImage( cvSize(Rect.width ,Rect.height), 8, 1 );
	IplImage* planes[] = { h_plane, s_plane };
	int h_bins = 16, s_bins = 8;
	int hist_size[] = {h_bins, s_bins};
	float h_ranges[] = { 0, 180 }; 
	float s_ranges[] = { 0, 255 };
	float* ranges[] = { h_ranges, s_ranges };
	cvCvtColor( img, hsv, CV_BGR2HSV );												//将颜色为RGB的输入图像img转化为HSV
	cvResetImageROI( img );															//释放感兴趣区域
	cvSplit( hsv, h_plane, s_plane, v_plane, 0 );									//将hsv图像分离到四个图像
    CvHistogram* hist = cvCreateHist( 2, hist_size, CV_HIST_ARRAY, ranges, 1 );		//画出颜色分布直方图
	cvCalcHist( planes, hist, 0, 0 );
	float max_value;
	cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 );
	int height = 480;
	int width = (h_bins*s_bins*6);
	IplImage* hist_img = cvCreateImage( cvSize(width,height), 8, 3 );
	cvZero( hist_img );
	IplImage* hsv_color = cvCreateImage( cvSize(1,1), 8, 3 );
	IplImage* rgb_color = cvCreateImage( cvSize(1,1), 8, 3 );
	int bin_w = width / (h_bins*s_bins);
	for(int h=0; h<h_bins; h++)
	{
		for(int s=0; s<s_bins; s++)
		{
			int i = h*s_bins + s;
			/*获得直方图中的统计次数,计算显示在图像中的高度*/
			float bin_val = cvQueryHistValue_2D( hist, h, s );
			int intensity = cvRound( bin_val * height / max_value );
		
			/*获得当前直方图代表的颜色,转换成RGB用于绘制*/
			cvSet2D( hsv_color, 0, 0, cvScalar(h*180.f/h_bins, s*255.f/s_bins, 255, 0));
			cvCvtColor( hsv_color, rgb_color, CV_HSV2BGR );
			CvScalar color = cvGet2D( rgb_color, 0, 0 );
			
			cvRectangle( hist_img, cvPoint(i*bin_w,height),
						 cvPoint((i+1)*bin_w, 
						 height - intensity),
						 color, -1, 8, 0 );
		}
	}
	cvNamedWindow( "H-S Histogram", 1 );
	cvShowImage( "H-S Histogram", hist_img );
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值