【OpenCV计算机视觉编程攻略】用直方图提取目标

简介

图像是由不同数值(颜色) 的像素构成的, 像素值在整幅图像中的分布情况是该图像的一个重要属性。图像由像素构成, 每个像素有不同的数值。 例如, 在单通道灰度图像中, 每个像素都有一个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

猜你喜欢

转载自blog.csdn.net/q_z_r_s/article/details/82793729