您的位置:首页 > 运维架构

《学习OpenCV》第四章课后题3-b

2015-07-19 17:59 197 查看
题目说明:

在一个独立的窗口中,使用画图函数画一个图表,分别用蓝、绿和红色表示选中区域中每种颜色的像素数量。这是选定区域的颜色直方图。x坐标系表示像素值范围在0-31,32-63,…,223,255;y坐标表示在选定区域中对应像素的数量。对每一个颜色通道(BGR)都进行统计。

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

//鼠标回调函数
void my_mouse_callback(int event,int x, int y, int flag, void* param);

CvRect box = cvRect(0,0,0,0);

bool draw_box = false;
bool high_light = false;
bool b_hist = false;
// 直方图尺寸
CvSize image_size = cvSize( 256, 300);

//画矩形
void drawbox(IplImage* img, CvRect rect)
{
cvRectangle(img,cvPoint(rect.x, rect.y),cvPoint(rect.x + rect.width, rect.y+rect.height),cvScalar(0,0,0));
}

//高亮矩形框的内容
void highlight(IplImage* img, CvRect rect)
{
if (high_light == true)
{
for (int y = rect.y; y<rect.y + rect.height; y++)
{
uchar* ptr = (uchar*)(img->imageData+y*img->widthStep);
for (int x = rect.x; x<rect.x + rect.width; x++)
{
ptr[x*img->nChannels + 1] = 150;

ptr[x*img->nChannels + 2] = 110;

}
}
}
cvShowImage("Box",img);
}

//画各个单通道图像直方图
IplImage * draw_single_hist(IplImage* img,CvScalar value)
{
int size = 256;
float range[] = {0, 255};
float* ranges[] = {range};
// 创建直方图
CvHistogram * hist = cvCreateHist( 1, &size, CV_HIST_ARRAY, ranges, 1);

cvCalcHist( &img, hist, 0, NULL );

float max_value = 0;
cvGetMinMaxHistValue( hist, NULL, &max_value, NULL, NULL );

// 新建一幅3通道的图像
IplImage* dst = cvCreateImage(image_size, IPL_DEPTH_8U, 3 );

cvSet( dst, cvScalarAll(255) );

double bin_width = (double)dst->width/256;
double bin_unith = (double)dst->height/max_value;   // 高度比例

for(int i = 0; i < 256; i++)
{
// 获得矩形左上角和右下角坐标
CvPoint p0 = cvPoint( i + bin_width, dst->height );
CvPoint p1 = cvPoint( (i+1) * bin_width,
dst->height - cvGetReal1D(hist->bins, i) *  bin_unith );
// 画实心矩形
cvRectangle( dst, p0, p1, value, -1, 8, 0 );
}

return dst;
}

//画直方图

void draw_hist(IplImage* img, CvRect rect)
{

// 设置感兴趣区域
cvSetImageROI( img, rect);
// 为感兴趣区分配空间
IplImage* src_rect = cvCreateImage ( cvSize( rect.width, rect.height ), img->depth, img->nChannels );
// 复制感兴趣数据
cvCopy(img, src_rect );
// 取消设置感兴趣区
cvResetImageROI( img );

// 为单色通道图像分配空间
IplImage* r_img = cvCreateImage( cvGetSize( src_rect),src_rect->depth, 1 );
IplImage* g_img = cvCreateImage( cvGetSize( src_rect),src_rect->depth, 1 );
IplImage* b_img = cvCreateImage( cvGetSize( src_rect),src_rect->depth, 1 );
IplImage* gray_img = cvCreateImage( cvGetSize( src_rect),src_rect->depth, 1 );

// 分离RGB分量
cvSplit( src_rect, r_img, g_img, b_img, NULL);

// 灰度转换
cvCvtColor( src_rect, gray_img, CV_BGR2GRAY);

// 显示每个通道的图像
cvNamedWindow("red",0);
cvNamedWindow("blue",0);
cvNamedWindow("green",0);
cvShowImage( "red", r_img);
cvShowImage( "blue", g_img);
cvShowImage( "green", b_img);

//画每个通道的直方图
IplImage* r_hist = draw_single_hist(r_img,cvScalar(0x00, 0x00, 0xff));
IplImage* g_hist = draw_single_hist(g_img,cvScalar(0x00, 0xff, 0x00));
IplImage* b_hist = draw_single_hist(b_img,cvScalar(0xff, 0x00, 0x00));
IplImage* gray_hist = draw_single_hist(gray_img,cvScalar(0x00, 0x00, 0x00));

// 把四个直方图在一幅图片上显示出来
IplImage* dst = cvCreateImage( cvSize( image_size.width * 2, image_size.height * 2), 8, 3 );
cvSetZero( dst );
// 拷贝红色分量直方图
CvRect r_rect = cvRect( 0, 0, image_size.width, image_size.height);
cvSetImageROI(dst, r_rect);
cvCopy( r_hist, dst);
// 拷贝绿色分量直方图
CvRect g_rect = cvRect(image_size.width, 0, image_size.width, image_size.height );
cvSetImageROI( dst, g_rect);
cvCopy( g_hist, dst);
// 拷贝蓝色分量直方图
CvRect b_rect = cvRect(0, image_size.height, image_size.width, image_size.height );
cvSetImageROI(dst, b_rect);
cvCopy( b_hist, dst );
// 拷贝灰色分量直方图
CvRect gray_rect = cvRect( image_size.width, image_size.height, image_size.width, image_size.height );
cvSetImageROI( dst, gray_rect);
cvCopy( gray_hist, dst);

cvResetImageROI( dst );
//显示最终的图像
cvNamedWindow("hist_rgb",0);
cvShowImage( "hist_rgb", dst);

}

int main(int argc, char** argv)
{
IplImage* image = cvLoadImage("E:/shark.jpg");
assert(image != NULL);

//保留一个原图的副本,便于后续回复原始数据
IplImage* copyImage = cvCreateImage(cvGetSize(image),image->depth,image->nChannels);
cvCopy(image,copyImage);

cvNamedWindow("Box",CV_WINDOW_AUTOSIZE);

cvShowImage("Box", copyImage);

//注册鼠标事件
cvSetMouseCallback("Box",my_mouse_callback,(void*)copyImage);

while (1)
{
//一定要在这里,画图是画在图像的副本上。否则,画出的图是连着的
cvCopy(image,copyImage);

if (draw_box == true)
{
drawbox(copyImage,box);
cvShowImage("Box", copyImage);
}
if (high_light == true)
{
highlight(copyImage, box);
}

if (b_hist == true)
{
draw_hist(image,box);
b_hist = false;//要加上这句,要不循环会使内存泄露
}

if (cvWaitKey(15) == 27)
break;
}

return 0;
}

void my_mouse_callback(int event,int x, int y, int flag, void* param)
{
IplImage* image = (IplImage*) param;
switch (event)
{
case CV_EVENT_LBUTTONDOWN:
high_light = false;
draw_box = true;
b_hist = false;
box = cvRect(x,y,0,0);
break;
case CV_EVENT_MOUSEMOVE:

if (draw_box == true)
{
box.width = x - box.x;
box.height = y - box.y;
}
break;
case CV_EVENT_LBUTTONUP:
draw_box = false;
high_light = true;
b_hist =true;

if(box.width < 0)
{
box.x += box.width;
box.width *= -1;
}
if(box.height < 0)
{
box.y += box.height;
box.height *= -1;
}
break;
}
}


注:qdsclove的问题已解决,解决办法参考LJH0600301217的专栏,但是“LJH0600301217的专栏”的代码运行时会造成内存泄露,更正办法在绘直方图函数后添加语句b_hist = false。

引用:LJH0600301217的专栏、qdsclove

/article/1945403.html

/article/5776309.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: