直方图匹配+c语言+opencv

调用:

	cv::Mat ref_glass, src_glass;
	cv::Mat dst_glass = cv::Mat::zeros(src_glass.rows, src_glass.cols, src_glass.type());
	HistSpecify(src_glass, ref_glass, dst_glass);

class Histogram1D
{
private:
	int histSize[1]; // 项的数量
	float hranges[2]; // 统计像素的最大值和最小值
	const float* ranges[1];
	int channels[1]; // 仅计算一个通道

public:
	Histogram1D()
	{
		// 准备1D直方图的参数
		histSize[0] = 256;
		hranges[0] = 0.0f;
		hranges[1] = 255.0f;
		ranges[0] = hranges;
		channels[0] = 0;
	}

	cv::Mat getHistogram(const cv::Mat &image)
	{
		cv::Mat hist;
		// 计算直方图
		calcHist(&image,// 要计算图像的
			1,                // 只计算一幅图像的直方图
			channels,        // 通道数量
			cv::Mat(),            // 不使用掩码
			hist,            // 存放直方图
			1,                // 1D直方图
			histSize,        // 统计的灰度的个数
			ranges);        // 灰度值的范围
		return hist;
	}

	cv::Mat getHistogramImage(const cv::Mat &image)
	{
		cv::Mat hist = getHistogram(image);

		//查找最大值用于归一化
		double maxVal = 0;

		minMaxLoc(hist, NULL, &maxVal);

		//绘制直方图的图像
		cv::Mat histImg(histSize[0], histSize[0], CV_8U, cv::Scalar(255));

		// 设置最高点为最大值的90%
		double hpt = 0.9 * histSize[0];
		//每个条目绘制一条垂直线
		for (int h = 0; h < histSize[0]; h++)
		{
			//直方图的元素类型为32位浮点数
			float binVal = hist.at<float>(h);
			int intensity = static_cast<int>(binVal * hpt / maxVal);
			line(histImg, cv::Point(h, histSize[0]),
				cv::Point(h, histSize[0] - intensity), cv::Scalar::all(0));
		}
		return histImg;
	}
};
/**
 * @brief HistSpecify 对灰度图像进行直方图规定化
 * @param src 输入图像
 * @param ref 参考图像,解析参考图像的直方图并用于规定化
 * @param result 直方图规定化后的图像
 * @note 手动设置一个直方图并用于规定化比较麻烦,这里使用一个参考图像来进行
 */
static void HistSpecify(const cv::Mat &src, const cv::Mat &ref, cv::Mat &result)
{
	Histogram1D hist1D;
	cv::Mat src_hist = hist1D.getHistogram(src);
	cv::Mat dst_hist = hist1D.getHistogram(ref);

	float src_cdf[256] = { 0 };
	float dst_cdf[256] = { 0 };

	// 直方图进行归一化处理
	src_hist /= (src.rows * src.cols);
	dst_hist /= (ref.rows * ref.cols);

	// 计算原始直方图和规定直方图的累积概率
	for (int i = 0; i < 256; i++)
	{
		if (i == 0)
		{
			src_cdf[i] = src_hist.at<float>(i);
			dst_cdf[i] = dst_hist.at<float>(i);
		}
		else
		{
			src_cdf[i] = src_cdf[i - 1] + src_hist.at<float>(i);
			dst_cdf[i] = dst_cdf[i - 1] + dst_hist.at<float>(i);
		}
	}

	// 累积概率的差值
	float diff_cdf[256][256];
	for (int i = 0; i < 256; i++)
		for (int j = 0; j < 256; j++)
			diff_cdf[i][j] = fabs(src_cdf[i] - dst_cdf[j]);

	// 构建灰度级映射表
	cv::Mat lut(1, 256, CV_8U);
	for (int i = 0; i < 256; i++)
	{
		// 查找源灰度级为i的映射灰度
		// 和i的累积概率差值最小的规定化灰度
		float min = diff_cdf[i][0];
		int index = 0;
		for (int j = 1; j < 256; j++)
		{
			if (min > diff_cdf[i][j])
			{
				min = diff_cdf[i][j];
				index = j;
			}
		}
		lut.at<uchar>(i) = static_cast<uchar>(index);
	}

	// 应用查找表,做直方图规定化
	LUT(src, lut, result);
}

  


posted @ 2020-11-18 14:51  皮卡皮卡妞  阅读(231)  评论(0编辑  收藏  举报