简介
本篇主要是利用三张图片:过曝(相机设置exposure+1)、正常(相机设置exposure+0)、欠曝(相机设置exposure-1),来合成一张在亮出和暗处细节都清晰
的图片,来简易实现图片的HDR功能。
具体实现
实现代码
1 #include <opencv2/core/core.hpp>
2 #include <opencv2/highgui/highgui.hpp>
3 #include <math.h>
4 #include <string.h>
5 #include <opencv/cv.h>
6 #include <stdio.h>
7 #include "opencv2/photo/photo.hpp"
8
9 using namespace cv;
10
11 char highpicName[20];
12 char normalpicName[20];
13 char lowpicName[20];
14 Mat mat1, mat2, mat3, dst_mat, tmp_mat;
15 int highWidth, highHeight;
16 int normalWidth, normalHeight;
17 int lowWidth, lowHeight;
18 IplImage src1, src2, src3, dst_src, tmp_src;
19 double weight=0.5;
20
21
22 void hdrCale(Mat pic1, Mat pic2, Mat pic3){
23 int i, j;
24 CvScalar s1, s2, s3;
25
26
27 src1 = pic1;
28 src2 = pic2;
29 src3 = pic3;
30 dst_src = dst_mat;
31 tmp_src = tmp_mat;
32
33 cvCvtColor(&src2, &tmp_src, CV_BGR2GRAY);
34 for(i=0; i< normalWidth; i++){
35 for(j=0; j<normalHeight; j++){
36 s1 = cvGet2D(&src1, i, j);
37 s2 = cvGet2D(&tmp_src, i, j);
38 s3 = cvGet2D(&src3, i, j);
39 weight = 0.5 + (127 - s2.val[0]) * 0.002;
40 s3.val[0] = (s1.val[0] * weight) + (s3.val[0] * (1-weight));
41 s3.val[1] = (s1.val[1] * weight) + (s3.val[1] * (1-weight));
42 s3.val[2] = (s1.val[2] * weight) + (s3.val[2] * (1-weight));
43 cvSet2D(&dst_src, i, j, s3);
44 }
45 }
46 }
47
48
49 int main(int argc, char *argv[]){
50 if(argc < 4){
51 printf("Please input high exposure/normal exposure/low exposure picture!\n");
52 return -1;
53 }
54 memcpy(highpicName, argv[1], sizeof(argv[1]));
55 memcpy(normalpicName, argv[2], sizeof(argv[2]));
56 memcpy(lowpicName, argv[3], sizeof(argv[3]));
57 mat1 = imread(argv[1]);
58 mat2 = imread(argv[2]);
59 mat3 = imread(argv[3]);
60 highWidth = mat1.rows;
61 highHeight = mat1.cols;
62 normalWidth = mat2.rows;
63 normalHeight = mat2.cols;
64 lowWidth = mat3.rows;
65 lowHeight = mat3.cols;
66 dst_mat = Mat(normalWidth, normalHeight, CV_8UC3, cv::Scalar(0, 0, 0));
67 tmp_mat = Mat(normalWidth, normalHeight, CV_8UC1, cv::Scalar(0, 0, 0));
68
69 hdrCale(mat1, mat2, mat3);
70
71 imshow("normal", mat2);
72 imshow("HDR", dst_mat);
73 imwrite("HDR.jpg", dst_mat);
74 cv::waitKey(0);
75 return 0;
76 }
代码讲解
1、首先进行相对应的初始化操作:运行软件时候,需要传入三张图片,顺序上分别是:过曝、正常、欠曝。打开这三张图片,保存在mat1、mat2、mat3
中,注意这三张图片必须大小一致。接着获取到图片的width和height。最后创建两张空白图片:tmp_mat和dst_mat。
1 if(argc < 4){
2 printf("Please input high exposure/normal exposure/low exposure picture!\n");
3 return -1;
4 }
5 memcpy(highpicName, argv[1], sizeof(argv[1]));
6 memcpy(normalpicName, argv[2], sizeof(argv[2]));
7 memcpy(lowpicName, argv[3], sizeof(argv[3]));
8 mat1 = imread(argv[1]);
9 mat2 = imread(argv[2]);
10 mat3 = imread(argv[3]);
11 highWidth = mat1.rows;
12 highHeight = mat1.cols;
13 normalWidth = mat2.rows;
14 normalHeight = mat2.cols;
15 lowWidth = mat3.rows;
16 lowHeight = mat3.cols;
17 dst_mat = Mat(normalWidth, normalHeight, CV_8UC3, cv::Scalar(0, 0, 0));
18 tmp_mat = Mat(normalWidth, normalHeight, CV_8UC1, cv::Scalar(0, 0, 0));
2、接着进入到HDR的算法处理:对应的处理很简单,主要就是根据就是权重,把过曝和欠曝图片合成到dst_mat中。
具体做法:循环依次打开三张图片的同一位置像素,用正常曝光图片像素,利用公式:weight = 0.5 + (127 - s2.val[0]) * 0.002;
来获得使用过曝、欠曝像素合成到dst_mat中对应使用的权值。接着:s3.val[0] = (s1.val[0] * weight) + (s3.val[0] * (1-weight));
计算出合成像素值之后,写入到dst_mat对应的坐标位置。进而生成HDR照片。
1 void hdrCale(Mat pic1, Mat pic2, Mat pic3){
2 int i, j;
3 CvScalar s1, s2, s3;
4
5 src1 = pic1;
6 src2 = pic2;
7 src3 = pic3;
8 dst_src = dst_mat;
9 tmp_src = tmp_mat;
10
11 cvCvtColor(&src2, &tmp_src, CV_BGR2GRAY);
12 for(i=0; i< normalWidth; i++){
13 for(j=0; j<normalHeight; j++){
14 s1 = cvGet2D(&src1, i, j);
15 s2 = cvGet2D(&tmp_src, i, j);
16 s3 = cvGet2D(&src3, i, j);
17 weight = 0.5 + (127 - s2.val[0]) * 0.002;
18 s3.val[0] = (s1.val[0] * weight) + (s3.val[0] * (1-weight));
19 s3.val[1] = (s1.val[1] * weight) + (s3.val[1] * (1-weight));
20 s3.val[2] = (s1.val[2] * weight) + (s3.val[2] * (1-weight));
21 cvSet2D(&dst_src, i, j, s3);
22 }
23 }
24 }
3、最后将正常照片和HDR照片显示初恋,并将hdr照片保存下来。
1 imshow("normal", mat2);
2 imshow("HDR", dst_mat);
3 imwrite("HDR.jpg", dst_mat);
4 cv::waitKey(0);
效果演示
对应的效果演示如下:
过曝图像:
正常图像
欠曝图像:
HDR图像