最近在学习OpenCV3.0左右的版本,在学习直方图的时候,笔者发现了一个问题,在看官方的文档说明,也就是opencv_tutorials时候,在看imgproc module这个板块的实例说明的时候,学习Histogram Calculation的时候发现函数rectangle函数没有说明有点让人模凌两可,模糊不清,设置有点丈二和尚摸不着头脑,我们且看一下关于rectangle函数的说明:
其中关于坐标点pt1以及pt2的说明一个矩形的一个顶点,pt2则是相对pt1的另外一点,即确定一个矩形,只需要矩形对角线上的两点即可,这个很好理解。但是指定这两个点的时候是很有考究的。笔者做了一个测试,测试代码为,当然笔者最近在这一个关于图像处理的一个小型的MFC程序,正在构建阶段,因此直接在该程序框架上试验:
<span style="font-family:Microsoft YaHei;font-size:12px;">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("灰色直方图"); } </span>
<span style="font-family:Microsoft YaHei;font-size:12px;">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); }</span>
错误理解:在函数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()函数的相应代码修改:
<span style="font-family:Microsoft YaHei;font-size:12px;">rectangle(Histimage, Point(i, histHeight - 1), Point(i + 1, histHeight - intensity_red), Scalar(0, 0, 255));</span>最后的结果是: