基于OpenCV 直方图匹配梳理一下直方图匹配的流程。
依上述链接所说,直方图匹配的步骤如下:
- 分别计算源图像与目标图像的累计概率分布
- 分别对源图像和目标图像进行直方图均衡化操作
- 利用映射关系使源图像直方图按照规定进行变换
发现还是注释代码梳理的快一点。
#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
int main(int argc,char* argv[])
{
/*********写路径读入源图像srcImage和目标图像dstImage*********/
cv::Mat srcImage = cv::imread(R"(E:\CodeBlocks\data\lena.jpg)");
cv::Mat dstImage = cv::imread(R"(E:\CodeBlocks\data\starry_night.jpg)");
/***********判断数据是否为空***********/
if (!srcImage.data || ! dstImage.data)
{
std::cerr << "fail to load image" <<std::endl;
exit(-1);
}
/*********对dstImage大小重置,依据srcImage.size()大小重设dstImage大小,输出为dstImage************/
cv::resize(dstImage,dstImage,srcImage.size(),0,0,cv::INTER_LINEAR);
cv::imshow("srcImage",srcImage);
cv::imshow("testImage",dstImage);
/********定义一些空数组,后续统计灰度*************/
//统计直方图参数
float srcCdf[256];
float dstCdf[256];
int srcAddTemp[256];
int dstAddTemp[256];
int histMatchMap[256];
for(int i=0;i<256;i++)
{
srcCdf[i] = 0;
dstCdf[i] = 0;
srcAddTemp[i] = 0;
dstAddTemp[i] = 0;
histMatchMap[i] = 0;
}
float srcSumTemp = 0;
float dstSumTemp = 0;
/***********计算总像素数***********/
int srcNPixel = srcImage.rows * srcImage.cols;
int dstNPixel = dstImage.rows * dstImage.cols;
int matchFlag = 0;
/*********遍历图片每个像素,统计不同灰度值的数量,存放在长256的灰度数组srcAddTemp和dstAddTemp中***********/
//统计像素
for(int i=0;i < srcImage.rows; i++)
{
for(int j = 0; j < srcImage.cols;j++)
{
srcAddTemp[(int)srcImage.at<uchar>(i,j)]++;
dstAddTemp[(int)dstImage.at<uchar>(i,j)]++;
}
}
/**********先累加所有灰度值到srcSumTemp和dstSumTemp,再计算平均每个灰度的分布概率(用每个灰度累计数量/总像素数)***********/
//计算累计概率分布
for(int i=0;i < 256;i++)
{
srcSumTemp += srcAddTemp[i];
srcCdf[i] = srcSumTemp/ srcNPixel;
dstSumTemp += dstAddTemp[i];
dstCdf[i] = dstSumTemp/ dstNPixel;
}
/******先设置一个最小匹配参数minMatchPara,遍历源图像灰度级,查找目标图像灰度级中与其分布概率的差的绝对值最小的灰度级,并将目标图像此时的灰度级赋给matchFlag,统计与源图像256个灰度级对应分布概率最接近的目标图像灰度级,存在histMatchMap中。******/
//直方图匹配实现
for(int i=0;i<256;i++)
{
float minMatchPara = 20;
for(int j=0;j<256;j++)
{
if (minMatchPara > cv::abs(srcCdf[i] - dstCdf[j]))
{
minMatchPara = cv::abs(srcCdf[i] - dstCdf[j]);
matchFlag = j;
}
}
histMatchMap[i] = matchFlag;
}
//初始化匹配图像
cv::Mat HistMatchImage = cv::Mat::zeros(srcImage.size(),CV_8UC3);
/*****彩图变灰******/
cv::cvtColor(srcImage,HistMatchImage,cv::COLOR_BGR2GRAY);
//映射
for(int i=0;i<HistMatchImage.rows;i++)
{
for(int j=0;j<HistMatchImage.cols;j++)
{
HistMatchImage.at<uchar>(i,j) = histMatchMap[(int)HistMatchImage.at<uchar>(i,j) ];
}
}
cv::imshow("ResultImage",HistMatchImage);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
该例程匹配后图像均为灰度图,因为中间做了一个RGB转灰度图操作,但 OpenCV直方图(直方图、直方图均衡,直方图匹配,原理、实现) 提出的对RGB三通道分别匹配,最后累加,结果还是RGB,但程序会出现cv::Exception的奇异问题,待调试。