-
Notifications
You must be signed in to change notification settings - Fork 0
/
vienerDeconv.cpp
240 lines (209 loc) · 7.19 KB
/
vienerDeconv.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#include "vienerDeconv.h"
int main(int argc, char** argv)
{
char* filename = "____!!!!____"; //input some file!!!
int angle = 455;
int d = 22;
int sz = 65;
int noise = 25;
cv::Mat img;
cv::Mat defocus_psf;
cv::Mat psf;
cv::Mat wiener_deconvolved;
img = cv::imread(filename, CV_LOAD_IMAGE_GRAYSCALE); //reading and preparing an image for
img.convertTo(img, CV_32FC1); //further processing. grayscale - important! (1 channel)
cv::divide(img, 255.0, img);
cv::namedWindow("initial", cv::WINDOW_AUTOSIZE); //windows creation
cv::namedWindow("psf", cv::WINDOW_NORMAL);
cv::namedWindow("defocus_psf", cv::WINDOW_NORMAL);
cv::namedWindow("wiener deconvolved", cv::WINDOW_AUTOSIZE);
//initial creation of blurred image (border blur)
blurred = cv::Mat::zeros(img.rows, img.cols, CV_32FC1);
wiener_deconvolved = wiener_deconvolve(img, false, d, angle, noise, sz); //final function (a.k.a. update)
defocus_psf = defocus_kernel(d, sz); //defocus psf
psf = motion_kernel(angle, d, sz); //motion psf
cv::imshow("initial", img);
cv::imshow("psf", psf); //showing the images
cv::imshow("defocus_psf", defocus_psf);
cv::imshow("wiener deconvolved", wiener_deconvolved);
cv::waitKey(0);
img.release(); //memory cleaning
psf.release();
defocus_psf.release();
wiener_deconvolved.release();
cv::destroyAllWindows(); //exit
return 0;
}
void blur_edge(cv::Mat img, cv::Mat blurred, int d){
int height = img.rows;
int width = img.cols;
cv::Mat img_pad(height + 2 * d, width + 2 * d, CV_32FC1);
cv::Mat img_blur(height + 2 * d, width + 2 * d, CV_32FC1);
cv::copyMakeBorder(img, img_pad, d, d, d, d, cv::BORDER_WRAP);
cv::GaussianBlur(img_pad, img_blur, cvSize(2 * d + 1, 2 * d + 1), -1);
img_blur = img_blur(cv::Range(d, height + d), cv::Range(d, width + d));
cv::Mat blur_mat(height, width, CV_32FC1);
cv::Mat inv_blur_mat(height, width, CV_32FC1);
int arr[4];
float tmp;
for (int i = 0; i < blurred.rows; i++){
for (int j = 0; j < blurred.cols; j++){
arr[0] = i; arr[1] = height - 1 - i; arr[2] = j; arr[3] = width - 1 - j;
tmp = (float)(Min(arr, 4)) / d;
tmp = (tmp < 1.0) ? tmp : (float)(1.0);
blur_mat.at<float>(i, j) = tmp;
inv_blur_mat.at<float>(i, j) = (float)(1.0) - tmp;
}
}
try{
cv::multiply(img, blur_mat, blurred);
cv::multiply(img_blur, inv_blur_mat, blur_mat);
cv::add(blurred, blur_mat, blurred);
}
catch (cv::Exception const& e) {
std::cerr << "OpenCV exception at blur_edge: " << e.what() << std::endl;
}
img_pad.release();
img_blur.release();
blur_mat.release();
inv_blur_mat.release();
}
int Min(int* arr, int len){
if (len == 1){
return arr[0];
}
else {
return (arr[0] < Min(arr + 1, len - 1)) ? arr[0] : Min(arr + 1, len - 1);
}
}
cv::Mat defocus_kernel(int d, int sz){
cv::Mat kern = cv::Mat::zeros(sz, sz, CV_8UC1);
cv::circle(kern, cv::Point(sz, sz), d, 255, -1, CV_AA, 1);
kern.convertTo(kern, CV_32F);
cv::divide(kern, 255.0, kern);
return kern;
}
cv::Mat motion_kernel(int angle, int d, int sz){
cv::Mat kern = cv::Mat::ones(1, d, CV_32FC1);
cv::Mat tmp = cv::Mat::zeros(d, d, CV_32FC1);
cv::Mat move_mat = (cv::Mat_<double>(2, 3) << 1, 0, 0, 0, 1, d / 2);
cv::warpAffine(kern, tmp, move_mat, tmp.size());
cv::Point center(d / 2, d / 2);
cv::Mat M = cv::getRotationMatrix2D(center, angle, 1.0);
cv::warpAffine(tmp, tmp, M, tmp.size());
kern.release();
move_mat.release();
M.release();
return tmp;
}
//deconvolve works with images, read in grayscale mode,
//converted to CV_32F and divided by 255
cv::Mat wiener_deconvolve(cv::Mat img, bool defocus, int d, int ang, int noise, int sz){
double snr = pow(10, -0.1*noise);
blur_edge(img, img, 31);
cv::Mat IMG;
cv::dft(img, IMG, cv::DFT_COMPLEX_OUTPUT);
cv::Mat psf;
if (defocus)
psf = defocus_kernel(d, sz);
else
psf = motion_kernel(ang, d, sz);
cv::namedWindow("psf", cv::WINDOW_NORMAL);
cv::imshow("psf", psf);
cv::divide(psf, cv::sum(psf)[0], psf);
cv::Mat psf_pad = cv::Mat::zeros(img.rows, img.cols, CV_32FC1);
int kh = psf.rows;
int kw = psf.cols;
cv::Mat roi(psf_pad(cv::Rect(0, 0, kw, kh)));
psf.copyTo(roi);
cv::Mat PSF;
cv::dft(psf_pad, PSF, cv::DFT_COMPLEX_OUTPUT, kh);
cv::Mat PSF2 = cv::Mat::zeros(PSF.rows, PSF.cols, PSF.type()); //formula solution
cv::mulSpectrums(PSF, PSF, PSF2, 0, true);
cv::Mat mat_arr[2];
cv::split(PSF2, mat_arr);
mat_arr[0] += snr;
mat_arr[1] = mat_arr[0];
cv::merge(mat_arr, 2, PSF2);
cv::divide(IMG, PSF2, IMG);
cv::mulSpectrums(IMG, PSF, IMG, 0, true);
cv::Mat result(img.rows, img.cols, CV_32FC1);
cv::idft(IMG, result, cv::DFT_REAL_OUTPUT + cv::DFT_SCALE);
roll_mat(result, kh, kw);
IMG.release();
psf.release();
psf_pad.release();
PSF.release();
PSF2.release();
roi.release();
mat_arr[0].release();
mat_arr[1].release();
return result;
}
void roll_mat(cv::Mat img, int x, int y){
cv::Mat tmp = cv::Mat(img.rows, img.cols, img.type());
cv::Mat tmp1;
tmp1 = img(cv::Rect(0, 0, img.cols - y, img.rows - x));
tmp1.copyTo(tmp(cv::Rect(y, x, img.cols - y, img.rows - x)));
tmp1 = img(cv::Rect(img.cols - y, 0, y, img.rows - x));
tmp1.copyTo(tmp(cv::Rect(0, x, y, img.rows - x)));
tmp1 = img(cv::Rect(0, img.rows - x, img.cols - y, x));
tmp1.copyTo(tmp(cv::Rect(y, 0, img.cols - y, x)));
tmp1 = img(cv::Rect(img.cols - y, img.rows - x, y, x));
tmp1.copyTo(tmp(cv::Rect(0, 0, y, x)));
tmp1.release();
tmp.copyTo(img);
tmp.release();
}
cv::Mat tikhon_deconvolve(cv::Mat img, bool defocus, int d, int ang, float r, int sz){
blur_edge(img, img, 31);
cv::Mat IMG;
cv::dft(img, IMG, cv::DFT_COMPLEX_OUTPUT);
cv::Mat psf;
if (defocus)
psf = defocus_kernel(d, sz);
else
psf = motion_kernel(ang, d, sz);
cv::namedWindow("psf", cv::WINDOW_NORMAL);
cv::imshow("psf", psf);
cv::Mat laplac = cv::Mat::eye(3, 3, CV_32FC1);
cv::Laplacian(laplac, laplac, 5);
cv::Mat lapl_big = cv::Mat::zeros(img.rows, img.cols, CV_32FC1);
cv::Mat ptr(lapl_big(cv::Rect(0, 0, 3, 3)));
laplac.copyTo(ptr);
laplac.release();
ptr.release();
cv::Mat LAPL;
cv::dft(lapl_big, LAPL, cv::DFT_COMPLEX_OUTPUT, 3);
cv::mulSpectrums(LAPL, LAPL, LAPL, 0, true);
cv::divide(psf, cv::sum(psf)[0], psf);
cv::Mat psf_pad = cv::Mat::zeros(img.rows, img.cols, CV_32FC1);
int kh = psf.rows;
int kw = psf.cols;
cv::Mat roi(psf_pad(cv::Rect(0, 0, kw, kh)));
psf.copyTo(roi);
cv::Mat PSF;
cv::dft(psf_pad, PSF, cv::DFT_COMPLEX_OUTPUT, kh);
cv::Mat PSF2 = cv::Mat::zeros(PSF.rows, PSF.cols, PSF.type()); //formula solution
cv::mulSpectrums(PSF, PSF, PSF2, 0, true);
cv::add(PSF2, r*LAPL, PSF2);
cv::Mat mat_arr[2];
cv::split(PSF2, mat_arr);
mat_arr[1] = mat_arr[0];
cv::merge(mat_arr, 2, PSF2);
cv::divide(IMG, PSF2, IMG);
cv::mulSpectrums(IMG, PSF, IMG, 0, true);
cv::Mat result(img.rows, img.cols, CV_32FC1);
cv::idft(IMG, result, cv::DFT_REAL_OUTPUT + cv::DFT_SCALE);
roll_mat(result, kh, kw);
IMG.release();
psf.release();
psf_pad.release();
PSF.release();
PSF2.release();
roi.release();
mat_arr[0].release();
mat_arr[1].release();
LAPL.release();
return result;
}