Skip to content

Commit 84ed730

Browse files
committed
Add Automatic Color Equalization(ACE) and its Fast Implementation.cpp
1 parent 3bd7d8b commit 84ed730

File tree

2 files changed

+195
-0
lines changed

2 files changed

+195
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
#include <stdio.h>
2+
#include <iostream>
3+
#include <immintrin.h>
4+
#include <opencv2/opencv.hpp>
5+
#include <opencv2/core/core.hpp>
6+
#include <opencv2/ml/ml.hpp>
7+
#include "opencv2/highgui/highgui.hpp"
8+
using namespace cv;
9+
using namespace cv::ml;
10+
using namespace std;
11+
12+
namespace ACE {
13+
//Gray
14+
Mat stretchImage(Mat src) {
15+
int row = src.rows;
16+
int col = src.cols;
17+
Mat dst(row, col, CV_64FC1);
18+
double MaxValue = 0;
19+
double MinValue = 256.0;
20+
for (int i = 0; i < row; i++) {
21+
for (int j = 0; j < col; j++) {
22+
MaxValue = max(MaxValue, src.at<double>(i, j));
23+
MinValue = min(MinValue, src.at<double>(i, j));
24+
}
25+
}
26+
for (int i = 0; i < row; i++) {
27+
for (int j = 0; j < col; j++) {
28+
dst.at<double>(i, j) = (1.0 * src.at<double>(i, j) - MinValue) / (MaxValue - MinValue);
29+
if (dst.at<double>(i, j) > 1.0) {
30+
dst.at<double>(i, j) = 1.0;
31+
}
32+
else if (dst.at<double>(i, j) < 0) {
33+
dst.at<double>(i, j) = 0;
34+
}
35+
}
36+
}
37+
return dst;
38+
}
39+
40+
Mat getPara(int radius) {
41+
int size = radius * 2 + 1;
42+
Mat dst(size, size, CV_64FC1);
43+
for (int i = -radius; i <= radius; i++) {
44+
for (int j = -radius; j <= radius; j++) {
45+
if (i == 0 && j == 0) {
46+
dst.at<double>(i + radius, j + radius) = 0;
47+
}
48+
else {
49+
dst.at<double>(i + radius, j + radius) = 1.0 / sqrt(i * i + j * j);
50+
}
51+
}
52+
}
53+
double sum = 0;
54+
for (int i = 0; i < size; i++) {
55+
for (int j = 0; j < size; j++) {
56+
sum += dst.at<double>(i, j);
57+
}
58+
}
59+
for (int i = 0; i < size; i++) {
60+
for (int j = 0; j < size; j++) {
61+
dst.at<double>(i, j) = dst.at<double>(i, j) / sum;
62+
}
63+
}
64+
return dst;
65+
}
66+
67+
Mat NormalACE(Mat src, int ratio, int radius) {
68+
Mat para = getPara(radius);
69+
int row = src.rows;
70+
int col = src.cols;
71+
int size = 2 * radius + 1;
72+
Mat Z(row + 2 * radius, col + 2 * radius, CV_64FC1);
73+
for (int i = 0; i < Z.rows; i++) {
74+
for (int j = 0; j < Z.cols; j++) {
75+
if((i - radius >= 0) && (i - radius < row) && (j - radius >= 0) && (j - radius < col)) {
76+
Z.at<double>(i, j) = src.at<double>(i - radius, j - radius);
77+
}
78+
else {
79+
Z.at<double>(i, j) = 0;
80+
}
81+
}
82+
}
83+
84+
Mat dst(row, col, CV_64FC1);
85+
for (int i = 0; i < row; i++) {
86+
for (int j = 0; j < col; j++) {
87+
dst.at<double>(i, j) = 0.f;
88+
}
89+
}
90+
for (int i = 0; i < size; i++) {
91+
for (int j = 0; j < size; j++) {
92+
if (para.at<double>(i, j) == 0) continue;
93+
for (int x = 0; x < row; x++) {
94+
for (int y = 0; y < col; y++) {
95+
double sub = src.at<double>(x, y) - Z.at<double>(x + i, y + j);
96+
double tmp = sub * ratio;
97+
if (tmp > 1.0) tmp = 1.0;
98+
if (tmp < -1.0) tmp = -1.0;
99+
dst.at<double>(x, y) += tmp * para.at<double>(i, j);
100+
}
101+
}
102+
}
103+
}
104+
return dst;
105+
}
106+
107+
Mat FastACE(Mat src, int ratio, int radius) {
108+
int row = src.rows;
109+
int col = src.cols;
110+
if (min(row, col) <= 2) {
111+
Mat dst(row, col, CV_64FC1);
112+
for (int i = 0; i < row; i++) {
113+
for (int j = 0; j < col; j++) {
114+
dst.at<double>(i, j) = 0.5;
115+
}
116+
}
117+
return dst;
118+
}
119+
120+
Mat Rs((row + 1) / 2, (col + 1) / 2, CV_64FC1);
121+
122+
resize(src, Rs, Size((col + 1) / 2, (row + 1) / 2));
123+
Mat Rf= FastACE(Rs, ratio, radius);
124+
resize(Rf, Rf, Size(col, row));
125+
resize(Rs, Rs, Size(col, row));
126+
Mat dst(row, col, CV_64FC1);
127+
Mat dst1 = NormalACE(src, ratio, radius);
128+
Mat dst2 = NormalACE(Rs, ratio, radius);
129+
for (int i = 0; i < row; i++) {
130+
for (int j = 0; j < col; j++) {
131+
dst.at<double>(i, j) = Rf.at<double>(i, j) + dst1.at<double>(i, j) - dst2.at<double>(i, j);
132+
}
133+
}
134+
return dst;
135+
}
136+
137+
Mat getACE(Mat src, int ratio, int radius) {
138+
int row = src.rows;
139+
int col = src.cols;
140+
vector <Mat> v;
141+
split(src, v);
142+
v[0].convertTo(v[0], CV_64FC1);
143+
v[1].convertTo(v[1], CV_64FC1);
144+
v[2].convertTo(v[2], CV_64FC1);
145+
Mat src1(row, col, CV_64FC1);
146+
Mat src2(row, col, CV_64FC1);
147+
Mat src3(row, col, CV_64FC1);
148+
149+
for (int i = 0; i < row; i++) {
150+
for (int j = 0; j < col; j++) {
151+
src1.at<double>(i, j) = 1.0 * src.at<Vec3b>(i, j)[0] / 255.0;
152+
src2.at<double>(i, j) = 1.0 * src.at<Vec3b>(i, j)[1] / 255.0;
153+
src3.at<double>(i, j) = 1.0 * src.at<Vec3b>(i, j)[2] / 255.0;
154+
}
155+
}
156+
src1 = stretchImage(FastACE(src1, ratio, radius));
157+
src2 = stretchImage(FastACE(src2, ratio, radius));
158+
src3 = stretchImage(FastACE(src3, ratio, radius));
159+
160+
Mat dst1(row, col, CV_8UC1);
161+
Mat dst2(row, col, CV_8UC1);
162+
Mat dst3(row, col, CV_8UC1);
163+
for (int i = 0; i < row; i++) {
164+
for (int j = 0; j < col; j++) {
165+
dst1.at<uchar>(i, j) = (int)(src1.at<double>(i, j) * 255);
166+
if (dst1.at<uchar>(i, j) > 255) dst1.at<uchar>(i, j) = 255;
167+
else if (dst1.at<uchar>(i, j) < 0) dst1.at<uchar>(i, j) = 0;
168+
dst2.at<uchar>(i, j) = (int)(src2.at<double>(i, j) * 255);
169+
if (dst2.at<uchar>(i, j) > 255) dst2.at<uchar>(i, j) = 255;
170+
else if (dst2.at<uchar>(i, j) < 0) dst2.at<uchar>(i, j) = 0;
171+
dst3.at<uchar>(i, j) = (int)(src3.at<double>(i, j) * 255);
172+
if (dst3.at<uchar>(i, j) > 255) dst3.at<uchar>(i, j) = 255;
173+
else if (dst3.at<uchar>(i, j) < 0) dst3.at<uchar>(i, j) = 0;
174+
}
175+
}
176+
vector <Mat> out;
177+
out.push_back(dst1);
178+
out.push_back(dst2);
179+
out.push_back(dst3);
180+
Mat dst;
181+
merge(out, dst);
182+
return dst;
183+
}
184+
}
185+
186+
using namespace ACE;
187+
188+
int main() {
189+
Mat src = imread("F:\\sky.jpg");
190+
Mat dst = getACE(src, 4, 7);
191+
imshow("origin", src);
192+
imshow("result", dst);
193+
waitKey(0);
194+
}

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@
2828
- Adaptive correction algorithm for illumination inhomogeneity image based on two-dimensional gamma function.cpp C++复现了《基于二维伽马函数的光照不均匀图像自适应校正算法》这篇论文,对光照不均匀的图像有较好的校正效果,且不会像Retiex那样出现光晕。原理请看:https://blog.csdn.net/just_sort/article/details/88569129
2929
- Real-time adaptive contrast enhancement for imaging sensors.cpp C++复现了《Real-time adaptive contrast enhancement for imaging sensors》这篇论文,实时自适应局部对比度增强算法。原理请看:https://blog.csdn.net/just_sort/article/details/85208124
3030
- AutomaticWhiteBalanceMethod.cpp C++复现了《A Novel Automatic White Balance Method For Digital Still Cameras》这篇论文,实现了效果比完美反射更好得白平衡效果。原理请看:https://blog.csdn.net/just_sort/article/details/89183909
31+
- Automatic Color Equalization(ACE) and its Fast Implementation.cpp C++复现了IPOL《Automatic Color Equalization(ACE) and its Fast Implementation》论文,用于自动色彩均衡。原理请看:https://blog.csdn.net/just_sort/article/details/85237711
3132

0 commit comments

Comments
 (0)