openCV -- rectangle函数的使用+统计直方图

1
void rectangle(Mat& img, Point pt1,Point pt2,const Scalar& color, int thickness=1, int lineType=8, int shift=0)

  

img 图像.

pt1 矩形的一个顶点。

pt2 矩形对角线上的另一个顶点

color 线条颜色 (RGB) 或亮度(灰度图像 )(grayscale image)。

thickness 组成矩形的线条的粗细程度。取负值时(如 CV_FILLED)函数绘制填充了色彩的矩形。

line_type 线条的类型。

 

其中关于坐标点pt1以及pt2的说明一个矩形的一个顶点,pt2则是相对pt1的另外一点,即确定一个矩形,只需要矩形对角线上的两点即可,这个很好理解。但是指定这两个点的时候是很有考究的。笔者做了一个测试,测试代码为,当然笔者最近在这一个关于图像处理的一个小型的MFC程序,正在构建阶段,因此直接在该程序框架上试验:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void CMFC_OpenCVtestDlg::OnGrayHist()
{
    // TODO:  在此添加命令处理程序代码
    Mat image(img);
  
    cvtColor(image,image,CV_BGR2GRAY);
    float range[] = { 0, 255 };
    const float *histRange[] = { range };
    MatND dsthist;
    int bins = 256;
    int hist_size[] = { bins };
    int channnels = 0;
    //------------------------------------------------------//
    calcHist(&image, 1, &channnels, Mat(), dsthist, 1, hist_size, histRange, true, false);
    double max_Value, min_Value;
    minMaxLoc(dsthist, &min_Value, &max_Value, 0, 0);
  
    int histHeight = 256;
    Mat Histimage = Mat::zeros(histHeight, bins, CV_8UC3);
    IplImage *pImage;
    for (int i = 0; i < bins; i++)
    {
        float binValue = dsthist.at<float>(i);
        int intensity = cvRound(binValue*histHeight / max_Value);
        rectangle(Histimage, Point(i, histHeight - 1), Point(i + 1, histHeight - intensity), Scalar(255,128,64));
    }
  
    //imshow("Hist",Histimage);
    pImage = &Histimage.operator IplImage();
    DrawToMFC(IDC_PROG, pImage);
    GetDlgItem(IDC_Hist)->SetWindowTextA("灰色直方图");
}<br><br>void CMFC_OpenCVtestDlg::DrawToMFC(int Ctrol_ID, IplImage * pImage)
{
    CDC* pDC = GetDlgItem(Ctrol_ID)->GetDC();
    HDC hDC = pDC->GetSafeHdc();
    CvvImage cimg;
    cimg.CopyOf(pImage);
    CRect rect;
    GetDlgItem(Ctrol_ID)->GetClientRect(&rect);
    cimg.DrawToHDC(hDC, &rect);
    ReleaseDC(pDC);
}
rectangle(Histimage, Point(i, histHeight - 1), Point(i + 1, histHeight - intensity_red), Scalar(0, 0, 255));

其中:img是一个IplImage *类型的变量,这是一个全局变量,主要是因为在OpenCV2.2版本以后,CvvImage类被取消掉了,因此在OpenCV3.0与MFC结合,在picture控件上显示图像时出现了麻烦,因此将CvvImage.cpp以及CvvImage.h拷贝到了工程目录下使用。而CvvImage类的成员函数Copyof(IplImage *pImage)只接受IplImage *类型的变量,因此定义了一个该全局变量(ps:这个真是对程序的说明,不是本文讨论的重点)

  

错误理解:在函数OnGrayHist()中,关于pt1,pt2的设置是:Point(i, histHeight - 1), Point(i + 1, histHeight - intensity);

如果我们将pt1,pt2理解为一个矩形的左上角坐标以及右上角坐标,那么疑问就来了,岂不是每一个直方图的点都在最顶端,画出来的矩形和我们理解的矩形就是倒着的了,笔者也是这么认为的,因此看了良久,决定把代码改了,把pt1,pt2的坐标改为了:Point(i, 0), Point(i + 1, intensity);这样画出来的矩形就应该和我们想象中的一样了,结果却不是这样的:

 

恰恰和我们理解的相反,因此正确的理解应该是这样的:

在计算过程中,intensity是相应的统计点的数量,Height是画图区域的高,在点pt1的横坐标表示的统计点,也就是像素1到256的点,在区域中表示为横坐标,而纵坐标则不是表示的到横坐标的纵向距离,而是到画图区域最高点的距离,因此设置为Height,则等同于到横坐标的纵向距离为0;p2的解释也就更能理解了,i+1表示矩形的宽度为1,

而纵坐标Height-intensity则是该统计点的高度,也就是频数。

因此将pt1和pt2理解为左下角右上角的含义才更为贴切。

为了验证想法否正确,将rectangle()函数的相应代码修改:

 

 

  

 

 

  

posted @   手磨咖啡  阅读(2065)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示