【OpenCV多曝光合成算法之熵值最大块合成】多曝光合成算法
本文使用多曝光对应区块内的熵值大小来分配不同大小的权重,最后线性合成为新区块,从而实现使得曝光合成图片具备最多的LDR细节,代替由于硬件或者软件限制而无法实现的HDR效果 。
#include #includeusing namespace cv;using namespace std;#define BLOCK 50//求熵 函数float entropy(Mat m){float sum = 0;float histogram[3][256] = {0};//3个通道,每个通道256个像素级别 。int one;int n = m.rows * m.cols;for (int k = 0; k < 3; k++){for (int i = 0; i < m.rows; i++){for (int j = 0; j < m.cols; j++){one = int (m.at(i, j)[k]);histogram[k][one]++;}}}//开始计算图像熵for (int i = 0; i < 3; i++){for (int j = 0; j < 256; j++){histogram[i][j] /= n;if (histogram[i][j] != 0)sum += (-histogram[i][j]) * log(histogram[i][j]);}}return sum;}//选取熵最大的图像块最大的权重输出Mat entropy_max(Mat a,Mat b,Mat c){float ans_a = entropy(a),ans_b = entropy(b), ans_c = entropy(c);if ((ans_a > ans_b && ans_a > ans_c)) {if (ans_b>ans_c)return 0.6 * a + 0.3 * b + 0.1 * c;else return 0.6 * a + 0.3 * c + 0.1 * b;}if ((ans_b > ans_a && ans_b > ans_c)){if (ans_a > ans_c)return 0.6 * b + 0.3 * a + 0.1 * c;else return 0.6 * b + 0.3 * c + 0.1 * a;}if ((ans_c > ans_b && ans_c > ans_a)){if (ans_a > ans_b)return 0.6 * c + 0.3 * a + 0.1 * b;else return 0.6 * c + 0.3 * b + 0.1 * a;}}//融合函数Mat fusion(Mat src_OE,Mat src_UE, Mat src_ME,int block){//创建一个Mat类型out_ROIMat out_ROI_ue,out_ROI_oe, out_ROI_me;//输出暂存块 。out_ROI_ue = Mat(block, block, CV_8UC3);out_ROI_oe = Mat(block, block, CV_8UC3);out_ROI_me = Mat(block, block, CV_8UC3);Mat out_ROI;//计算出的熵比较高的那一块out_ROI = Mat(block, block, CV_8UC3);Mat out;//创建对象out = src_ME;//输出对象//创建每次循环的处理区域work_ROI , 并初始化坐标极其宽度高度Rect work_ROI;work_ROI.x = 0;//矩形左上角横坐标work_ROI.y = 0;//矩形左上角纵坐标work_ROI.width = block;//矩形宽为blockwork_ROI.height = block;//矩形高为block//原图像ROI位置以及大小Rect类型储存for (int j = 0; j < src_OE.cols / block; j++)//外层循环循环原图列数/block 次{for (int i = 0; i < src_OE.rows / block; i++) //内层循环原图行数/block 次{//rect_ROI坐标转换到下一个矩形区块 。work_ROI.x = block * i;//工作区域向后移动block个像素work_ROI.y = block * j;//工作区域向后移动block个像素//比较三张图的熵的最大值out_ROI_oe = src_OE(work_ROI);out_ROI_ue = src_UE(work_ROI);out_ROI_me = src_ME(work_ROI);out_ROI = entropy_max(out_ROI_ue, out_ROI_oe,out_ROI_me);//把熵最大的这一块赋给out_ROI//把这一块填充到out的这一个部分里面out_ROI.copyTo(out(work_ROI));}}return out;}int main(){ Mat src_OE = imread("C:\\Users\\hl\\Desktop\\oe2.jpg", IMREAD_COLOR);Mat src_UE = imread("C:\\Users\\hl\\Desktop\\ue2.jpg", IMREAD_COLOR);Mat src_ME = imread("C:\\Users\\hl\\Desktop\\me2.jpg", IMREAD_COLOR);//Mat src = http://www.kingceram.com/post/imread("C:\\Users\\hl\\Desktop\\CESHI2.jpg", IMREAD_COLOR);imshow("过曝光",src_OE);imshow("欠曝光",src_UE);imshow("正常曝光",src_ME);Mat oe, ue, me;// ceshi;cvtColor(src_OE, oe, COLOR_BGR2Lab);cvtColor(src_OE, ue, COLOR_BGR2Lab);cvtColor(src_OE, me, COLOR_BGR2Lab);//cvtColor(src, ceshi, COLOR_BGR2Lab);//熵最大融合Mat out;out = fusion(src_OE, src_UE, src_ME,BLOCK);imshow("曝光融合后", out);//cvtColor(out, ceshi , COLOR_BGR2Lab);//观察总熵值cout << "过曝总熵:" << entropy(oe) << endl;cout << "欠曝总熵:" << entropy(ue) << endl;cout << "正常曝光总熵:" << entropy(me) << endl;cout << "曝光合成总熵:" << entropy(out) << endl;//cout << "测试熵:" << entropy(ceshi) << endl;waitKey();return 0;
算法效果如下:
左上:block大小为2525个像素,熵值为15.1996
文章插图
右上:block大小为2020个像素 , 熵值为15.1069
左下:block大小为个像素,熵值为15.3519
右上:block大小为个像素,熵值为15.5222
虽说肉眼可见最多细节信息 , 但是这个引发的块状效应依然无法容忍,之后会持续更新对于该算法的改进 。敬请期待 。