OpenCV 直方图统计像素

目录

1.计算图像的直方图

 2.使用查找表修改图像外观

 3.反投影直方图以检测特定的图像内容


​​​​​​​

1.计算图像的直方图

首先实现单通道灰度图像

class Histogram1D
{
public:
	cv::MatND getHistogram(const cv::Mat &image);
	cv::Mat getHistogramImage(const cv::Mat &image);
	cv::Mat applyLookUp(const cv::Mat& image, const cv::MatND& lookup);
	cv::Mat stretch(const cv::Mat &image, int minValue);
	cv::Mat equalize(const cv::Mat &image);

	Histogram1D(){

		histSize[0] = 256;
		hranges[0] = 0.0;
		hranges[1] = 255.0;
		ranges[0] = hranges;
		channels[0] = 0;
	}

private:
	int histSize[1];	//项的数据
	float hranges[2];	//像素最大最小
	const float *ranges[1];
	int channels[1];

};

类实现:



cv::MatND Histogram1D::getHistogram(const cv::Mat &image)
{
	cv::MatND hist;

	cv::calcHist(&image, 
					  1,	//计算单张图像
			   channels, 	//通道数量
		      cv::Mat(), 	//不使用图像作为掩码
		           hist, 	//返回的直方图
		              1, 	//这是1D的直方图
		       histSize, 	//项的数量
		        ranges);	//像素值范围

	return hist;
}


cv::Mat Histogram1D::getHistogramImage(const cv::Mat &image)
{
	//首先计算直方图
	cv::MatND hist = getHistogram(image);

	//获取最大 最小
	double maxVal = 0;
	double minVal = 0;
	cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);

	//显示直方图的图像

	cv::Mat histImg(histSize[0],histSize[0],CV_8U,cv::Scalar(255));

	//设置最高点为nbins的90%
	int hpt = static_cast<int>(0.9*histSize[0]);

	//每个条目都绘制一条垂直线
	for (int h = 0; h<histSize[0]; h++)
	{
		float binVal = hist.at<float>(h);

		int intensity = static_cast<int>(binVal*hpt / maxVal);

		cv::line(histImg, cv::Point(h, histSize[0]),
						  cv::Point(h, histSize[0] - intensity),
					      cv::Scalar::all(0));
		
	}

	return histImg;
}



// Stretches the source image.
cv::Mat Histogram1D::stretch(const cv::Mat &image, int minValue)
{

	cv::MatND hist = getHistogram(image);
	cv::Mat result;
	int imin = 0, imax = histSize[0] - 1, dim = 256;
	for (; imin < histSize[0]; imin++)
	{
		if (hist.at<float>(imin) > minValue)
		{
			break;
		}
	}
	for (; imax >= 0; imax--)
	{
		if (hist.at<float>(imax) > minValue)
		{
			break;
		}
	}
	cv::Mat lut(1, &dim, CV_8U);

	for (int i = 0; i < 256; i++)
	{
		if (i < imin) lut.at<uchar>(i) = 0;
		else if (i > imax) lut.at<uchar>(i) = 255;
		else lut.at<uchar>(i) = static_cast<uchar>(255.0*(i - imin) / (imax - imin) + 0.5);
	}
	result = applyLookUp(image, lut);

	return result;

}

// Applies a lookup table transforming an input image into a 1-channel image
cv::Mat Histogram1D::applyLookUp(const cv::Mat& image, const cv::MatND& lookup)
{
	cv::Mat result;
	cv::LUT(image, lookup, result);
	return result;
}

cv::Mat Histogram1D::equalize(const cv::Mat &image)
{
	cv::Mat result;
	cv::Mat src = image;

	cvtColor(src, src, CV_BGR2GRAY);

	cv::equalizeHist(src,result);

	return result;
}

应用实现:

void OpenCVQtGui::Histogram_clicked()
{
	cv::Mat Result = hist1D.getHistogramImage(image);


    cv::imshow("hist1DImage", Result);


	cv::threshold(image, Result, 60, 255, cv::THRESH_BINARY);

	cvtColor(Result, Result, CV_BGR2RGB);

	QImage img1 = QImage((const unsigned char*)(Result.data), Result.cols, Result.rows, QImage::Format_RGB888);

	ui.label_2->setPixmap(QPixmap::fromImage(img1));

	ui.label_2->resize(QSize(img1.width(), img1.height()));

}

 2.实现彩色直方图


class ColorHistogram
{
public:
	ColorHistogram()
	{
		histSize[0] = histSize[1] = histSize[2] = 256;
		hranges[0] = 0.0;
		hranges[1] = 255.0;
		ranges[0] = hranges;
		ranges[1] = hranges;
		ranges[2] = hranges;
		channels[0] = 0;
		channels[1] = 1;
		channels[2] = 2;
	}

	cv::MatND getHistogram(const cv::Mat &image);
	cv::SparseMat getSparseHistogram(const cv::Mat &image);
	cv::Mat getHistogramImage(const cv::Mat &image);

private:
	int histSize[3];
	float hranges[2];
	const float *ranges[3];
	int channels[3];

};

类实现:

cv::MatND ColorHistogram::getHistogram(const cv::Mat &image)
{
	cv::MatND hist;

	cv::calcHist(&image,
					  1,
				channels,
			   cv::Mat(),
					hist,
					   3,
				histSize,
				 ranges);
	return hist;
}

cv::SparseMat ColorHistogram::getSparseHistogram(const cv::Mat &image)
{
	cv::SparseMat hist(3,histSize,CV_32F);

	cv::calcHist(&image,
					  1,
			   channels,
			  cv::Mat(),
				   hist,
					  3,
			   histSize,
			    ranges);
	return hist;
}

cv::Mat ColorHistogram::getHistogramImage(const cv::Mat &image)
{

// 	首先计算直方图
	cv::MatND hist;
	std::vector<cv::Mat> b;

	cv::split(image, b);
	cv::Mat b_hist, r_hist, g_hist;

	cv::calcHist(&b[0], 1, channels, cv::Mat(), b_hist, 1, histSize, ranges, true, false);
	cv::calcHist(&b[1], 1, channels, cv::Mat(), g_hist, 1, histSize, ranges, true, false);
	cv::calcHist(&b[2], 1, channels, cv::Mat(), r_hist, 1, histSize, ranges, true, false);

	//创建相关变量
	int hist_w = 512;
	int hist_h = 400;
	int bins = cvRound((double)image.cols / histSize[0]);

	cv::Mat histImg = cv::Mat(image.cols, image.rows, CV_8UC3, cv::Scalar(0, 0, 0));

	cv::normalize(b_hist, b_hist, 0, image.rows, cv::NORM_MINMAX, -1, cv::Mat());
	cv::normalize(g_hist, g_hist, 0, image.rows, cv::NORM_MINMAX, -1, cv::Mat());
	cv::normalize(r_hist, r_hist, 0, image.rows, cv::NORM_MINMAX, -1, cv::Mat());

	//画图
	
	for (size_t i = 0; i <  histSize[0]-1; i++)
	{

		line(histImg, cv::Point(bins * i,		image.rows - cvRound(b_hist.at<float>(i))),
					  cv::Point(bins * (i + 1), image.rows - cvRound(b_hist.at<float>(i+1))), cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
		
		line(histImg, cv::Point(bins * i,		image.rows - cvRound(g_hist.at<float>(i))),
					  cv::Point(bins * (i + 1), image.rows - cvRound(g_hist.at<float>(i + 1))), cv::Scalar(0, 255, 0), 1, cv::LINE_AA);
		
		line(histImg, cv::Point(bins * i,		image.rows - cvRound(r_hist.at<float>(i))),
					  cv::Point(bins *(i + 1),	image.rows - cvRound(r_hist.at<float>(i + 1))), cv::Scalar(255, 0, 0), 1, cv::LINE_AA);
	}

	imshow("图像直方图", histImg);

	return histImg;
}

运行效果:

 2.使用查找表修改图像外观

void OpenCVQtGui::LookUp_clicked()
{

	// Create an image inversion table
	//uchar lookup[256];
	// Create lookup table
	int dims[1] = { 256 };
	cv::MatND lookup(1, dims, CV_8U);

	for (int i = 0; i < 256; i++) {

		lookup.at<uchar>(i) = 255 - i;
	}

	cv::Mat Result = hist1D.applyLookUp(image, lookup);

	cv::namedWindow("Image");
	cv::imshow("Image", Result);

	Result = hist1D.equalize(image);

	cv::namedWindow("Image2");
	cv::imshow("Image2", Result);

	Result = hist1D.stretch(image, 30);
	

	//cv::Mat Result2 = Chist.getHistogramImage(image);

	// 	cv::namedWindow("Image2");
	// 
	// 	cv::imshow("Image2", Result2);


	// 	cv::SparseMat Result3 = Chist.getSparseHistogram(image);
	// 
	// 	cv::namedWindow("Original Image3");
	// 
	// 	cv::imshow("Original Image3", Result2);


	//cv::threshold(image, Result, 60, 255, cv::THRESH_BINARY);

	cvtColor(Result, Result, CV_BGR2RGB);

	QImage img1 = QImage((const unsigned char*)(Result.data), Result.cols, Result.rows, QImage::Format_RGB888);

	ui.label_2->setPixmap(QPixmap::fromImage(img1));

	ui.label_2->resize(QSize(img1.width(), img1.height()));

}

 

 3.反投影直方图以检测特定的图像内容

添加类:

class ContentFinder
{
public:
	ContentFinder()
	{
		threshold = -1.0;
		ranges[0] = hranges;
		ranges[1] = hranges;
		ranges[2] = hranges;
	}
	void setThreshold(float t);
	float getThreshold();
	void setHistogram(const cv::MatND &h);
	cv::Mat find(const cv::Mat& image, float minValue, float maxValue, int *channels, int dim);

private:
	float hranges[2];
	const float *ranges[3];
	float threshold;
	int channels[3];
	cv::MatND histogram;
};

类实现:

void ContentFinder::setThreshold(float t)
{
	threshold = t;
}

float ContentFinder::getThreshold()
{
	return threshold;
}

void ContentFinder::setHistogram(const cv::MatND &h)
{
	histogram = h;
	cv::normalize(histogram, histogram, 1.0);
}

cv::Mat ContentFinder::find(const cv::Mat& image, float minValue, float maxValue, int *channels, int dim)
{
	cv::Mat result;
	hranges[0] = minValue;
	hranges[1] = maxValue;
	for (int i = 0; i < dim; i++)
	{
		this->channels[i] = channels[i];
	}
	cv::calcBackProject(&image,
		1,
		channels,
		histogram,
		result,
		ranges,
		255.0
	);
	if (threshold > 0.0)
	{
		cv::threshold(result, result, 255 * threshold, 255, cv::THRESH_BINARY);
	}
	return result;
}

 应用实现:

void OpenCVQtGui::CalcBack_clicked()
{
	cv::Mat Result = image;

	cv::Mat ImageROI;
	ImageROI = image(cv::Rect(120,70,150,150));

	cv::MatND hist = Chist.getHistogram(ImageROI);

	finder.setHistogram(hist);

	finder.setThreshold(0.05);

	int channels[3] = { 0, 1, 2 };
	Result = finder.find(image, 0, 255, channels, 3);


	cv::namedWindow("Image");

	cv::imshow("Image", ImageROI);

 	cvtColor(Result, Result, CV_BGR2RGB);

	//cv::addWeighted(Result, 1.0, ImageROI, 0.8, 0., Result);

// 	cvtColor(ImageROI, ImageROI, CV_BGR2RGB);


// 	cv::namedWindow("Image");
// 	cv::imshow("Image", ImageROI);
	

	cvtColor(Result, Result, CV_BGR2RGB);

	QImage img1 = QImage((const unsigned char*)(Result.data), Result.cols, Result.rows, QImage::Format_RGB888);

	ui.label_2->setPixmap(QPixmap::fromImage(img1));

	ui.label_2->resize(QSize(img1.width(), img1.height()));

}

效果: 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值