关于灰度直方图

来源:互联网 发布:c#,json的类子 编辑:程序博客网 时间:2024/06/07 23:44

最近有一个地方需要用到灰度直方图做阈值分析,之前在Halcon里面试过,它有一个滑动条的界面,很方便。无奈找了下,OpenCV里可以计算,但是发现显示折腾了自己一些时间,记录在此。

灰度直方图的横轴表示的0~255的灰度值,纵轴表示落在这个灰度值区间的像素个数。


计算直方图,参考的是毛星云《OpenCV 3编程入门》 第九章P347 及官网教程 http://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html

显示文字方面,用到之前学习的http://blog.csdn.net/aptx704610875/article/details/48915149

可以看到原始的灰度图取四周的边界查看灰度在128左右


在我自己的直方图中大概是这样127~129之间(图有点挫,还有待改善),一排显示灰度不全,字都叠在一起了,所以我分为了上下两排

#include <iostream>#include "opencv2/core/core.hpp"#include "opencv2/highgui/highgui.hpp"#include "opencv2/imgproc/imgproc.hpp"//#include "GoCvHelper.h"using namespace std;using namespace cv;//using namespace GO;#define  VP  vector<cv::Point>  //用VP符号代替 vector<point>void projection4ruler(Mat src, int& down1, int& up2, int direction){Mat tmp = src.clone();vector<int> vdate;if (0 == direction)//if (DIRECTION_X == direction){for (int i = 0; i<tmp.cols; i++){Mat data = tmp.col(i);int itmp = countNonZero(data);//if (itmp > 10)//{////int jjj = 0;//}vdate.push_back(itmp);}} else{for (int i = 0; i < tmp.rows; i++){Mat data = tmp.row(i);int itmp = countNonZero(data);vdate.push_back(itmp);}}//过滤掉所有噪音//寻找第一个下边沿和第二个上边沿down1 = 1;up2 = src.cols - 1;for (int i = 0; i < tmp.cols - 1; i++){if (vdate[i] >= 100 && vdate[i + 1] < 100){down1 = i;break;}}for (int i = down1; i < tmp.cols - 1; i++){if (vdate[i] < 100 && vdate[i + 1] >= 100){up2 = i;return;}}}int main(int argc, char* argv[]){Mat src = imread("D:\\opencv_work\\pylon_opencv_first_demo\\pylon_opencv_first_demo\\pixel2length.jpg");Mat dst;Mat tmp;int up1 = 0;int down2 = 0;vector<Mat> matSplit;cvtColor(src, tmp, COLOR_BGR2Lab);split(tmp, matSplit);dst = matSplit[1];// http://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.htmlint channels = 0;cv::Mat g_hist;int dimension = 1;int histSize = 256;float range[] = { 0, 256};const float *ranges[] = { range };bool uniform = true; bool accumulate = false;//calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate);cv::calcHist(&dst, 1, &channels, cv::Mat(), g_hist, dimension, &histSize, &ranges[0], uniform, accumulate);double gminValue = 0;double gmaxValue = 0;minMaxLoc(g_hist, &gminValue, &gmaxValue, 0, 0);  //  在cv中用的是cvGetMinMaxHistValue// Draw the histograms for G int hist_w = 1800; int hist_h = 480;int bin_w = cvRound((double)hist_w / histSize);Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));/// Normalize the result to [ 0, histImage.rows ]string msg;int fontface = 1;double fontscale = 0.48;int thickness = 1;Size textSize;int baseLine = 0;normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());int texty;for (int i = 1; i < histSize; i++){line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))), Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 200, 0), 2, 8, 0);msg = format("%d", i);textSize = getTextSize(msg, fontface, fontscale, thickness, &baseLine);//Point textOrigin(temp.cols - textSize.width - 20, temp.rows - 2 * baseLine - 10);//Point textOrigin((int)dstImage.cols - 200, (int)dstImage.rows - 50);int oddoreven = i % 2;if (oddoreven){ texty = histImage.rows - 40;} else{ texty = histImage.rows - 55;}Point textOrigin(bin_w*(i - 1), texty);//Point textOrigin(temp.cols - textSize.width - 20, temp.rows - 2 * baseLine - 10);//Point textOrigin(bin_w*(i - 1), histImage.rows -50);putText(histImage, msg, textOrigin, fontface, fontscale, Scalar(250, 250, 250), thickness);}cvNamedWindow("gray histogram", CV_WINDOW_AUTOSIZE);imshow("gray histogram", histImage);Mat outImage1;cv::resize(dst, outImage1, cv::Size(640, 480), cv::INTER_LINEAR);cvNamedWindow("src");imshow("src", outImage1);int dims = 1;MatND dstHist;       // 在cv中用CvHistogram *hist = cvCreateHistcalcHist(&dst, 1, &channels, Mat(), dstHist, dims, &histSize, ranges);    // cv 中是cvCalcHistint scale = 1;Mat dstImage(histSize * scale, histSize, CV_8U, Scalar(0));double minValue = 0;double maxValue = 0;minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);  //  在cv中用的是cvGetMinMaxHistValuestring msg1;int fontface1 = 1;double fontscale1 = 1.0;int thickness1 = 5;Size textSize1;int baseLine1 = 0;//【5】绘制出直方图int hpt = saturate_cast<int>(0.9 * histSize);for (int i = 0; i < 256; i++){float binValue = dstHist.at<float>(i);  //   注意hist中是float类型    而在OpenCV1.0版中用cvQueryHistValue_1Dint realValue = saturate_cast<int>(binValue * hpt / maxValue);rectangle(dstImage, Point(i*scale, histSize - 1), Point((i + 1)*scale - 1, histSize - realValue), Scalar(255));//msg1 = format("(%d)", i);//textSize = getTextSize(msg1, fontface1, fontscale1, thickness1, &baseLine1);////Point textOrigin(temp.cols - textSize.width - 20, temp.rows - 2 * baseLine - 10);////Point textOrigin((int)dstImage.cols - 200, (int)dstImage.rows - 50);//Point textOrigin(i+20, (int)dstImage.rows - 50);//putText(dstImage, msg, textOrigin, fontface, fontscale, Scalar(250, 250, 250), thickness);}cvNamedWindow("Histogram");imshow("Histogram", dstImage);//===============================================================threshold(dst, dst, 100, 255, THRESH_OTSU);threshold(dst, dst, 0, 255, THRESH_BINARY_INV);//以白色为有数据,取反操作//projection4ruler(dst, up1, down2, DIRECTION_X);projection4ruler(dst, up1, down2, 0);line(src, Point(up1, 0), Point(up1, src.rows - 1), Scalar(0, 0, 255), 1);line(src, Point(down2, 0), Point(down2, src.rows - 1), Scalar(0, 0, 255), 1);Mat outImage;cv::resize(src, outImage, cv::Size(640, 480), cv::INTER_LINEAR);cvNamedWindow("final");imshow("final", outImage);cv::waitKey();return 0;}


==============Halcon======================

Halcon拖拽的方式,自动打开image对话框.

关于Operator,可以鼠标右键(或Ctrl + Shift + Enter),输入自己想要的进行搜索


接着在当前图像窗口,右键-Set Parameters


鼠标放在缩略图上,状态栏会显示一些信息,如这里有14个region,但是我们的回形针只有13个,说明还有噪声信息(connected regions图片最左有条红线)。接着利用Feature Histogram去除它。

由于回形针都有相同的area,这里就借助这个特点来做特征分析。

添加几句代码保存,识别的位置与方位信息,然后Ctrl同时选择多个,一起查看。


最后所有的回形针的位置与姿态都识别到了,如下图

=========================2D calibration==================


0 0