- 本文为@源码人原创文章,转载请注明出处
- 文章链接:https://blog.csdn.net/q_z_r_s
简介
图像是由不同数值(颜色) 的像素构成的, 像素值在整幅图像中的分布情况是该图像的一个重要属性。图像由像素构成, 每个像素有不同的数值。 例如, 在单通道灰度图像中, 每个像素都有一个0(黑色) ~255(白色) 的数值。 对于每个灰度, 都有不同数量的像素分布在图像内, 具体取决于图片内容。直方图是一个简单的表格, 表示一个图像(有时是一组图像) 中具有某个值的像素的数量。 因此灰度图像的直方图有256个项目, 也叫箱子(bin) 。 0号箱子提供值为0的像素的数量, 1号箱子提供值为1的像素的数量, 等等。 很明显, 如果把直方图的所有箱子进行累加,得到的结果就是像素的总数。 你也可以把直方图归一化, 即所有箱子的累加和等于1。 这时每个箱子的数值表示对应的像素数量占总数的百分比。
准备工作
先搞一张图片用来做试验,如下:
如何实现
先定义计算直方图的类:
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
class calcHistogram {
public:
calcHistogram();
calcHistogram(bool uniform, bool accumulate, int histSize);
~calcHistogram(){}
void getHistogram(Mat& img, Mat& Histogram);
void getHistogramImage(Mat& image, Mat& histImage);
void setHistSize(int hsize);
void setHistRange(float from, float to);
private:
bool uniform;
bool accumulate;
int histSize;
float range[2];
};
接下来就是在cpp文件中实现这些方法:
#include "calcHistogram.hpp"
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
calcHistogram::calcHistogram(bool uniform, bool accumulate, int hsize):uniform(uniform),accumulate(accumulate) {
if (hsize<0 || hsize >256) {
cout << "invalid parameter! \n use default parameter!" << endl;
this->histSize = 256;
}
else
this->histSize = hsize;
}
calcHistogram::calcHistogram():uniform(true),accumulate(false),histSize(256) {
range[0] = 0;
range[1] = 256;
}
void calcHistogram::setHistSize(int hsize) {
if (hsize<0 || hsize >256) {
cout << "invalid parameter! \n use default parameter!" << endl;
histSize = 256;
}else
histSize = hsize;
}
void calcHistogram::setHistRange(float from, float to) {
if (from >= to || to <=0) {
cout << "invalid parameter! \n use default parameter!" << endl;
range[0] = 0;
range[1] = 256;
}else {
range[0] = from;
range[1] = to;
}
}
void calcHistogram::getHistogram(Mat& img, Mat& Histogram) {
int channels[] = {0};
const float* ranges[] = { range };//const不加的话报错
calcHist(&img, 1, channels, Mat(), Histogram, 1, &histSize, ranges, true, false );
}
void calcHistogram::getHistogramImage(Mat& image, Mat& histImage) {
Mat hist;
getHistogram(image, hist);
//找到直方图中的最大值和最小值
float max=0, min=0;
for (int i=0; i<hist.rows; i++) {
for (int j=0; j<hist.cols; j++) {
if (max<hist.at<float>(i,j)) {
max = hist.at<float>(i,j);
} else if (min>hist.at<float>(i,j)){
min = hist.at<float>(i,j);
}
}
}
histImage.create(hist.rows, hist.rows, CV_8U);
histImage = 255;
int hpt = static_cast<int>(0.8*hist.rows);
for (int bin=0; bin<hist.rows; bin++) {
float binVal = hist.at<float>(bin);
if (binVal>0) {
int h = static_cast<int>(binVal*hist.rows/max);
line(histImage, Point(bin,hist.rows),Point(bin,hist.rows-h),0,1);
}
}
}
效果图:
根据灰度直方图可以看出大多数像素值都大约在100偏右的地方,下一步就是用直方图的这个特性来进行阈值分割图像,效果如下:
途中只剩下了牛的影响,其他的背景全都被剔除了,由此可以看出,直方图是图像的一个重要特性。
参考文献:
OpenCV histogram API Reference :https://download.csdn.net/download/q_z_r_s/10678288