这两天一直在研究匀光匀色算法才了解到了直方图匹配算法,想要了解这个算法又要先了解直方图均衡化算法,通过网上查找了很多资料,没有现成C++代码,经过仔细思考和实验后大概复现了该算法。特此记录,以备查阅
参考链接如下:
1、匀光匀色–直方图匹配算法实现与应用
2、基于OpenCV的直方图匹配
3、直方图均衡化的数学原理

先介绍一下基本概念

测试数据


原始数据


底图影像

直方图匹配匀光匀色效果

从上图可以看出原始影像与模板颜色不一致,经过直方图匹配匀光匀色后颜色一致性较好。

直方图均衡算法

先看看直方图均衡算法原理知识:





先在根据上面的算法步骤,计算一幅影像的直方图均衡影像

1、获取一张影像Mat的直方图,即计算hs

void getImgHistogram(Mat image, map<int, double> & map)
{//获取一张影像Mat的直方图,即计算hsint w = image.cols;int h = image.rows;double totalPixel = w * h;double rate = 1 / (image.channels() * totalPixel);//所有像素分之一for (int i = 0; i < 256; i++) {//map.put(i, 0.0);// 通过循环,往集合里面填充0~255个位置,初始值都为0map[i] = 0.0;}//分别统计图像上0~255上分布总数for (int row = 0; row < h; row++) {uchar* uc_pixel = image.data + row * image.step;for (int col = 0; col < w; col++) {//uc_pixel[0] = 255 - uc_pixel[0];//uc_pixel[1] = 255 - uc_pixel[1];//uc_pixel[2] = 255 - uc_pixel[2];for (int BandID = 0; BandID < image.channels(); BandID++){map[uc_pixel[BandID]] += rate;}uc_pixel += image.channels();//map[uc_pixel[0]] += rate;//map[uc_pixel[1]] += rate;//map[uc_pixel[2]] += rate;//uc_pixel += 3;}}return;
}

2、计算累计直方图,即hp

 double SrcSum = 0;map<int, double> SrcImg_AccMap;//计算累计直方图,即hpfor (int i = 0; i < 256; i++){SrcSum += SrcImg_map[i];SrcImg_AccMap[i] = SrcSum;}

3、对直方图中所有像素乘以255即可得到最终直方图均衡的影像,不单独列出代码,最后看所有代码里面可以找到。

所有代码如下:

#include <opencv.hpp>
#include <map>
#include <vector>using namespace std;
using namespace cv;
void getImgHistogram(Mat image, map<int, double> & map);
Mat GetEquHistogramMat(Mat SrcImage, map<int, double> SrcImg_AccMap);//获取均衡化的影像Matint main()
{const char* SrcPath = "D:/datas/ColorMap/back/Test.png";const char* outPutPath = "D:/datas/ColorMap/back/Test_ZFTJH.png";Mat SrcImage = imread(SrcPath);map<int, double> SrcImg_map;//定义直方图map,直方图可以使用map进行定义,也可以使用一个一维数组定义getImgHistogram(SrcImage, SrcImg_map);//获取影像直方图//计算累计直方图double SrcSum = 0;map<int, double> SrcImg_AccMap;//累计直方图for (int i = 0; i < 256; i++){SrcSum += SrcImg_map[i];SrcImg_AccMap[i] = SrcSum;}Mat SrcImage_Equ = GetEquHistogramMat(SrcImage, SrcImg_AccMap);//获取直方图均衡化的Matimwrite(outPutPath, SrcImage_Equ);printf("Success save img:%s\n", outPutPath);imshow("SrcImage", SrcImage);imshow("SrcImage_Equ", SrcImage_Equ);waitKey(0);return 0;
}void getImgHistogram(Mat image, map<int, double> & map)
{//获取影像直方图int w = image.cols;int h = image.rows;double totalPixel = w * h;double rate = 1 / (image.channels() * totalPixel);//所有像素分之一for (int i = 0; i < 256; i++) {// 通过循环,往集合里面填充0~255个位置,初始值都为0map[i] = 0.0;}//分别统计图像上0~255上分布总数for (int row = 0; row < h; row++) {uchar* uc_pixel = image.data + row * image.step;for (int col = 0; col < w; col++) {//每个波段像素for (int BandID = 0; BandID < image.channels(); BandID++){map[uc_pixel[BandID]] += rate;}uc_pixel += image.channels();//map[uc_pixel[0]] += rate;//map[uc_pixel[1]] += rate;//map[uc_pixel[2]] += rate;//uc_pixel += 3;}}return;
}Mat GetEquHistogramMat(Mat SrcImage, map<int, double> SrcImg_AccMap)//获取直方图均衡化的Mat
{//累计直方图,然后再每个直方图像素乘以255即得到均衡的直方图Mat resultImg = SrcImage.clone();//均衡化的src图for (int row = 0; row < resultImg.rows; row++) {uchar* uc_pixel = resultImg.data + row * resultImg.step;for (int col = 0; col < resultImg.cols; col++) {for (int BandID = 0; BandID < SrcImage.channels(); BandID++){uc_pixel[BandID]=255* SrcImg_AccMap[uc_pixel[BandID]];}uc_pixel += SrcImage.channels();//uc_pixel[0] = 255 * SrcImg_AccMap[uc_pixel[0]];//uc_pixel[1] = 255 * SrcImg_AccMap[uc_pixel[1]];//uc_pixel[2] = 255 * SrcImg_AccMap[uc_pixel[2]];//uc_pixel += 3;}}return resultImg;}

直方图匹配算法

直方图匹配算法是在直方图均衡算法基础上进行的衍生
直方图匹配:将一张图片的直方图匹配到目标图上,使两张图的视觉感觉接近
关于理论公式有很多,如果喜欢看理论知识,这里还有一篇博客:直方图匹配的数学原理 。写了很多,但是公式太复杂了,看不是很懂。直到看了下面这幅图我才懂了直方图匹配的流程步骤

上图说的是待匹配影像A和参考底图B,分别对其进行直方图均衡化(说简单点就是累计直方图乘以255),输出的直方图均衡的影像称为:A_Equ、B_Equ影像,看A_Equ和B_Equ那个像素值距离最近,则将B上的该直方图值映射给A,形成一个映射表。例如通过上面最下面这副图可以得到映射表(映射表可以用map<int ,uchar>数据格式表达,或者uchar*的一维数组来表达,以数组下标表示直方图值),为了值观表达,上图的映射表{0:0,1:1,2:1,3:2,4:4}。
我认为上图映射表中其实有点问题(该表我是从参考链接三中搬过来的):A图的像素3,转换成均衡化影像像素值为18,18这个值在B_Equ中距离15是3(fabs(18-15)),距离20是2(fabs(18-20)),依照取出B_Equ最近的像素作为映射像素,所以该值应该映射到B_Equ中的像素20,对应B中的的是3,所以映射表中3映射成3,而不是2。
最后一步就是根据引射表{0:0,1:1,2:1,3:2,4:4}进行修正A影像得到的就是右下角的直方图匹配后的影像,将该影像存出来则是最终结果。

注意这是直方图匹配大概流程,如果想要颜色与底图颜色更接近,则需要对待匹配影像的每个波段都与底图影像每个波段做匹配,效果则最好。

上代码:


#include <opencv.hpp>
#include <map>
#include <vector>using namespace std;
using namespace cv;
void getSigBandImgHistogram(Mat SrcImage, map<int, double> &SrcImg_SigMap, int BandId);int main(int argc, char* argv[])
{//const char* SrcPath = "D:/datas/test/ColorCorrection/Src.png";//const char* BaseMap = "D:/datas/test/ColorCorrection/baseMap.png";//const char* outPutPath= "D:/datas/test/ColorCorrection/outPut.png";const char* SrcPath = argv[1];const char* BaseMap = argv[2];const char* outPutPath = argv[3];int IsDislay = atoi(argv[4]);//是否显示匹配后影像效果,0为不显示,其他的都显示Mat SrcImage = imread(SrcPath);Mat BaseMapImg = imread(BaseMap);cout << SrcImage.channels() << endl;vector<uchar*>resultMultMap;//存储每个波段最终的映射关系for (int BandId = 0; BandId < SrcImage.channels(); BandId++){//单独对影像每个波段进行直方图均衡,然后找到最终的映射关系printf("Start Get BandID:%d Histogram!\n", BandId);uchar* SigResultBandMap = new uchar[256];//首先定义一下单个波段的映射结果//1、获取单波段直方图map<int, double> SrcImg_SigMap;//map<int, double> BaseMapImg_SigMap;getSigBandImgHistogram(SrcImage, SrcImg_SigMap, BandId);getSigBandImgHistogram(BaseMapImg, BaseMapImg_SigMap, BandId);//计算累计直方图double BaseSum_SigMap = 0;double SrcSum_SigMap = 0;map<int, double> SrcImg_AccSigMap;//累计直方图map<int, double> BaseMapImg_AccSigMap;//累计直方图for (int i = 0; i < 256; i++){SrcSum_SigMap += SrcImg_SigMap[i];SrcImg_AccSigMap[i] = SrcSum_SigMap;BaseSum_SigMap += BaseMapImg_SigMap[i];BaseMapImg_AccSigMap[i] = BaseSum_SigMap;}printf("Start Build resultMap :%d!\n", BandId);for (int i = 0; i < 256; i++){double MinValue = 255;//最小值初始化for (int j = 0; j < 256; j++){double SubVelue = fabs(SrcImg_AccSigMap[i] * 255 - BaseMapImg_AccSigMap[j] * 255);//取绝对值if (MinValue > SubVelue){//找到最靠近直方图均衡化的值,作为映射值MinValue = SubVelue;SigResultBandMap[i] = j;}}}resultMultMap.push_back(SigResultBandMap);}//最后进行直方图像素替换Mat resultImg = SrcImage.clone();//均衡化的src图for (int row = 0; row < resultImg.rows; row++) {uchar* uc_pixel = resultImg.data + row * resultImg.step;for (int col = 0; col < resultImg.cols; col++){for (int BID = 0; BID < SrcImage.channels(); BID++){uc_pixel[BID] = resultMultMap[BID][uc_pixel[BID]];}//uc_pixel[0] = resultMap[uc_pixel[0]];//uc_pixel[2] = resultMap[uc_pixel[2]];//uc_pixel[1] = resultMap[uc_pixel[1]];//uc_pixel += 3;uc_pixel += SrcImage.channels();}}imwrite(outPutPath, resultImg);printf("Success save img:%s\n", outPutPath);if (IsDislay != 0){//是否显示影像imshow("SrcImage", SrcImage);//imshow("SrcImage_Equ", SrcImage_Equ);imshow("BaseMapImg", BaseMapImg);//imshow("BaseMapImg_Equ", BaseMapImg_Equ);imshow("resultImg", resultImg);waitKey(0);}return 0;
}void getSigBandImgHistogram(Mat SrcImage, map<int, double> &SrcImg_SigMap, int BandId)
{//获取指定波段的直方图信息int w = SrcImage.cols;int h = SrcImage.rows;double totalPixel = w * h;double rate = 1 / totalPixel;for (int i = 0; i < 256; i++) {//map.put(i, 0.0);// 通过循环,往集合里面填充0~255个位置,初始值都为0SrcImg_SigMap[i] = 0.0;}//分别统计图像上0~255上分布总数for (int row = 0; row < h; row++) {uchar* uc_pixel = SrcImage.data + row * SrcImage.step;for (int col = 0; col < w; col++) {SrcImg_SigMap[uc_pixel[BandId]] += rate;uc_pixel += 3;}}return;}

结果如下图

直方图均衡化算法、直方图匹配算法 C++ 代码相关推荐

  1. 红外图像直方图均衡化算法理解

    1.红外图像直方图均衡化背景与目的 红外相机探测器的输出模式有模拟量和数字量,模拟量输出的需要用ADC转换,因而红外相机输出的数据位数一般都在12位到16位,对应的灰度级基本在2^12~2^16级而人 ...

  2. Python实现图像直方图均衡化算法

    title: "Python实现图像直方图均衡化算法" date: 2018-06-12T17:10:48+08:00 tags: [""] categorie ...

  3. 限制对比度自适应直方图均衡化算法原理、实现及效果

    一.自适应直方图均衡化(Adaptive histgram equalization/AHE) 1.简述 自适应直方图均衡化(AHE)用来提升图像的对比度的一种计算机图像处理技术.和普通的直方图均衡算 ...

  4. 一些常用的直方图均衡化算法

    直方图均衡化(HE) 直方图均衡化是常用的图像增强的方法.通过一种映射改变图像中的灰度值,增加图像灰度值的动态范围从而增加图像的对比度.过度曝光的图像中的灰度值主要集中在高亮度的范围内,而曝光不足的图 ...

  5. 图像直方图均衡化算法 python实现

    一. 直方图均衡化: 直方图均衡化是使图像直方图变得平坦的操作.直方图均衡化能够有效地解决图像整体过暗.过亮的问题,增加图像的清晰度. 具体流程如下所示.其中S是总的像素数,Zmax是像素的最大取值( ...

  6. 直方图均衡化算法原理详解

    算法 经典算法 下面以一幅3*2像素的简单图片(图C)为例,来说明灰度直方图均衡化的算法. (图C) 图C的直方图: 注意看百分位(Percentile)这一项.一般软件的百分位是 当前色阶的像素数量 ...

  7. 直方图均衡化算法原理及bins的理解

    原理部分转载于:直方图均衡化算法原理与实现 bin的理解和直观展示见 part2 part1 直方图均衡化算法原理 我们知道提高图像对比度的变换函数f(x)需要满足以下条件: f(x)在0<=x ...

  8. 不调用python函数实现直方图均衡化_直方图均衡化(HE)

    前面我们已经讲过图像的直方图,那图像的直方图均衡化又是干嘛的呢? 顾名思义:其实对直方图进行均衡化,哈哈感觉自己说的就是废话... 举个例子: import cv2 from matplotlib i ...

  9. opencv进阶学习笔记7:直方图,直方图均衡化,直方图比较,直方图反向投影

    基础版传送门: python3+opencv学习笔记汇总目录(适合基础入门学习) 进阶版笔记目录链接: python+opencv进阶版学习笔记目录(适合有一定基础) 直方图基础讲解: opencv学 ...

  10. [Opencv](python)直方图均衡化与直方图比较

    1,直方图均衡化 (Histogram Equalization) 假如图像的灰度分布不均匀,其灰度分布集中在较窄的范围内,使图像的细节不够清晰,对比度较低.直方图均衡化,对图像进行非线性拉伸,重新分 ...

最新文章

  1. 015_logback中的自定义Appender
  2. eclipse build workspace太慢或者 js出错问题解决
  3. Windows下架设Apache并支持ASP-Win+Apache+ASP
  4. 快速排序算法的优化思路总结
  5. Windows中安装ElasticSearch(单机+集群+Kibana)
  6. yuki翻译器钩子_【galgame游戏剧情翻译工具】YUKI整合翻译工具下载
  7. 远程连接virtualBox本地虚拟机并访问虚拟机服务
  8. week7 TT的魔猫
  9. Linux命令查看Linux服务器内存、CPU、显卡、硬盘使用情况
  10. CIFAR10数据集集 cifar-10-python.tar.gz
  11. 【CAD .NET】设置保存为pdf文件的页面参数 边距,横向竖向
  12. 当你使用笔记本电脑插入公司的局域网后你的wifi功能无法上网了,而且公司局域网没有外网,怎么既可以进公司局域网又可以上外网
  13. npm安装失败及解决办法 error network tunneling socket could not be established
  14. 用js实现登录的简单验证
  15. 在修改了PS1环境变量后,系统终端出现不换行问题解决
  16. Selenium WebDrive使用Edge浏览器模拟登录163邮箱
  17. py基础---多线程、多进程、协程
  18. ip切换脚本(修改ipv4中ip地址、子网掩码、默认网关)
  19. LeetCode 546. 移除盒子 Python
  20. 外汇蜡烛图入门,基本蜡烛图形态

热门文章

  1. 大学excel题库含答案_大学生计算机基础excel试题及答案
  2. 升级ios13后,iPhone手机新增了截长屏功能,实用又方便
  3. 千图成像python_爬取英雄联盟所有皮肤图片实现千图成像~
  4. 抓包工具Wireshark npcap
  5. mysql环境变量配置还是不行_为什么要配置mysql环境变量
  6. U2000V1R2安装部署工作日报
  7. web开发规范 - html书写规范
  8. 前剪枝算法和后剪枝算法区别
  9. 手机+文件共享服务器软件,windows文件共享服务器软件
  10. python xy 官网_zwPython,字王集成式python开发平台,比pythonXY更强大、更方便。