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

题目说明:
在一个独立的窗口中,使用画图函数画一个图表,分别用蓝、绿和红色表示选中区域中每种颜色的像素数量。这是选定区域的颜色直方图。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
http://blog.csdn.net/ljh0600301217/article/details/8655329
http://www.cnblogs.com/qdsclove/p/3351187.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值