一、什么是直方图规定化?
1、定义:直方图规定化是指一幅输入图像经过点运算变化,将原图像的灰度直方图改造成所希望的直方图形状。
2、目的:变换直方图使之成为某个想要的形状。但由于数字图像的灰度级是离散并且是有限的,所以直方图规定化的结果一般只是与目标直方图的形状大体接近,并非理想的完全一致。
3、功效:比直方图均衡化更加灵活(直方图均衡化可看成特殊的直方图规定化),常用与图片风格一致性的自动处理。
4、直方图规定化的应用
① 能有效地改善图像的整体或局部特征,广泛运用在图像增强处理中。
② 保证不同图像的影调风格的一致性,在处理艺术图像时十分有用。
二、直方图规定化的原理
直方图规定化有两种方式:SML单映射和GML组映射。
✔ ① SML单映射的实现原理是:首先计算原始图像和规定目标的累计直方图(将统计直方图归一化到(0, 1)之间,再计算累计概率分布函数),然后对原图像的累计直方图寻求一一映射关系(每个灰度值映射到与目标的累计直方图最近的点)。有了映射关系后,遍历原图像的每个像素点,做相应的点运算变换即可。
✔ ② GML单映射的实现原理是:首先计算原始图像和规定目标的累计直方图(将统计直方图归一化到(0, 1)之间,再计算累计概率分布函数),然后对原图像的累计直方图进行分组:先在原图像的累计直方图中找到与目标直方图的每个灰度值距离最近的点(如下图的所示的 0→3;3→5;7→7,即0,3,7为在原图像中要找的点),让点与点之间构成一组,映射到目标直方图中对应的灰度值。有了映射关系后,遍历原图像的每个像素点,做相应的点运算变换即可。
三、直方图规定化的实现
由上述一个简单的小例子可以看出,GML组映射比SML单映射的规定化效果要好,所以我们这里采用GML的方式来实现,具体代码如下:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
Mat gray_hist; //直方图计算的结果
void CalHistogram(Mat& img);
void HistMap(Mat& img_src, Mat& img_obj);
int main()
{
//注意imread后不加参数,默认读取进来的是RGB图像
Mat img_src = imread("D:\\数字图像处理\\图片素材\\Bmp Samples\\24位真彩.bmp");
Mat img_obj = imread("D:\\数字图像处理\\图片素材\\基本运算\\欧美系\\欧美系2.bmp");
Mat imgOutput; //规定化后的输出图像
//分割原图像通道
vector<Mat> src_channels;
Mat src_blue, src_green, src_red;
split(img_src, src_channels);
src_blue = src_channels.at(0);
src_green = src_channels.at(1);
src_red = src_channels.at(2);
//分割目标图像通道
vector<Mat> obj_channels;
Mat obj_blue, obj_green, obj_red;
split(img_obj