初识Opencv4.X----图像直方图匹配

直方图匹配的原理:
直方图匹配的原理

//图像直方图匹配
#include <stdio.h>
#include <iostream>
#include <string>
#include <opencv2\opencv.hpp>
using namespace std;
using namespace cv;
void drawHist(Mat &hist, int hist_w, int hist_h, int type, string name);
int main()
{
    
    
	/*
	直方图匹配与直方图均衡相似,但是直方图均衡不能指定往哪个方向均衡,而直方图匹配则是根据输入的模板函数进行均衡
	*/
	Mat img_dst = imread("pp1.jpg", IMREAD_GRAYSCALE);//待匹配的图像
	Mat img_mask = imread("person1.jpeg", IMREAD_GRAYSCALE);//用来匹配的模板图像
	//统计0~255各个灰度值的像素个数
	const int channels[1] = {
    
     0 };
	Mat hist_dst, hist_mask;
	const int histSize[1] = {
    
     256 };
	float a[2] = {
    
     0,255 };
	const float * ranges[1] = {
    
     a };
	//得到的hist是一个单通道,width=1,height=256的Mat变量
	calcHist(&img_dst, 1, channels, Mat(), hist_dst, 1, histSize, ranges);
	calcHist(&img_mask, 1, channels, Mat(), hist_mask, 1, histSize, ranges);
	//归一化的直方图
	drawHist(hist_dst, 512, 400, NORM_INF, "hist_dst");
	drawHist(hist_mask, 512, 400, NORM_INF, "hist_mask");
	//计算两幅图像的累积概率
	float hist_dst_cdf[256] = {
    
     hist_dst.at<float>(0) };
	float hist_mask_cdf[256] = {
    
     hist_mask.at<float>(0) };
	for (int i = 1; i < 256; i++)//这里采用的是累积小于该像素灰度值的比例,如上面的表格所示
	{
    
    
		hist_dst_cdf[i] = hist_dst_cdf[i - 1] + hist_dst.at<float>(i);
		hist_mask_cdf[i] = hist_mask_cdf[i - 1] + hist_mask.at<float>(i);
	}
	//构建累计概率的误差矩阵,diff_cdf[0][0..255]表示hist_dst[0]分别与与hist_mask[0..255]的差值
	float diff_cdf[256][256];
	for (int i = 0; i < 256; i++)
	{
    
    
		for (int j = 0; j < 256; j++)
		{
    
    
			diff_cdf[i][j] = fabs(hist_dst_cdf[i] - hist_mask_cdf[j]);
		}
	}
	//映射灰度值
	Mat lut(1, 256, CV_8U);
	for (int i = 0; i < 256; i++)
	{
    
    
		float min = diff_cdf[i][0];
		int index = 0;
		//找到diff_cdf[i][0..255]中的最小值,此时的j即为要用的灰度值,用来替换i
		for (int j = 0; j < 256; j++)
		{
    
    
			if (min > diff_cdf[i][j])
			{
    
    
				min = diff_cdf[i][j];
				index = j;
			}
		}
		//替换i,注意i,j不仅是数组下标,也是灰度值
		lut.at<uchar>(i) = (uchar)index;
	}
	Mat img_result, hist_result;
	LUT(img_dst, lut, img_result);
	namedWindow("待匹配的图像", WINDOW_NORMAL);
	namedWindow("用来匹配的模板图像", WINDOW_NORMAL);
	namedWindow("匹配后的图像", WINDOW_NORMAL);
	imshow("待匹配的图像", img_dst);
	imshow("用来匹配的模板图像", img_mask);
	imshow("匹配后的图像", img_result);
	calcHist(&img_result, 1, channels, Mat(), hist_result, 1, histSize, ranges);
	drawHist(hist_result, 512, 400, NORM_INF, "hist_result");
	waitKey(0);
	return 0;
}
//画直方图函数,传入参数:hist,图像宽,图像高,归一化方式,窗口名称
void drawHist(Mat &hist, int hist_w, int hist_h,int type, string name)//这个函数适合用NORM_INF方法
{
    
    
	int width = 2;
	Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
	normalize(hist, hist, 1, 0, type, -1, Mat());
	for (int i = 1; i <= hist.rows; i++)
	{
    
    
		rectangle(histImage, Point(width*(i - 1), hist_h - 1),
			Point(width*i - 1, hist_h - cvRound(hist_h*hist.at<float>(i - 1)) - 1),
			Scalar(255, 255, 255), -1);
	}
	namedWindow(name, WINDOW_NORMAL);
	imshow(name, histImage);
}

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_46146657/article/details/120289657