1 /* 2 * cv_image_deblurring.cpp - iterative blind deblurring 3 * 4 * Copyright (c) 2016-2017 Intel Corporation 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * Author: Andrey Parfenov <a1994ndrey (at) gmail.com> 19 * Author: Wind Yuan <feng.yuan (at) intel.com> 20 */ 21 22 #include "cv_image_deblurring.h" 23 24 namespace XCam { 25 26 27 CVImageDeblurring::CVImageDeblurring () 28 : CVBaseClass () 29 { 30 _helper = new CVImageProcessHelper (); 31 _sharp = new CVImageSharp (); 32 _edgetaper = new CVEdgetaper (); 33 _wiener = new CVWienerFilter (); 34 } 35 36 void 37 CVImageDeblurring::set_config (CVIDConfig config) 38 { 39 _config = config; 40 } 41 42 CVIDConfig 43 CVImageDeblurring::get_config () 44 { 45 return _config; 46 } 47 48 void 49 CVImageDeblurring::crop_border (cv::Mat &thresholded) 50 { 51 int top = 0; 52 int left = 0; 53 int right = 0; 54 int bottom = 0; 55 for (int i = 0; i < thresholded.rows; i++) 56 { 57 for (int j = 0; j < thresholded.cols; j++) 58 { 59 if (thresholded.at<unsigned char>(i , j) == 255) 60 { 61 top = i; 62 break; 63 } 64 } 65 if (top) 66 break; 67 } 68 69 for (int i = thresholded.rows - 1; i > 0; i--) 70 { 71 for (int j = 0; j < thresholded.cols; j++) 72 { 73 if (thresholded.at<unsigned char>(i , j) == 255) 74 { 75 bottom = i; 76 break; 77 } 78 } 79 if (bottom) 80 break; 81 } 82 83 for (int i = 0; i < thresholded.cols; i++) 84 { 85 for (int j = 0; j < thresholded.rows; j++) 86 { 87 if (thresholded.at<unsigned char>(j , i) == 255) 88 { 89 left = i; 90 break; 91 } 92 } 93 if (left) 94 break; 95 } 96 97 for (int i = thresholded.cols - 1; i > 0; i--) 98 { 99 for (int j = 0; j < thresholded.rows; j++) 100 { 101 if (thresholded.at<unsigned char>(j, i) == 255) 102 { 103 right = i; 104 break; 105 } 106 } 107 if (right) 108 break; 109 } 110 thresholded = thresholded (cv::Rect(left, top, right - left, bottom - top)); 111 } 112 113 int 114 CVImageDeblurring::estimate_kernel_size (const cv::Mat &image) 115 { 116 int kernel_size = 0; 117 cv::Mat thresholded; 118 cv::Mat dst; 119 cv::Laplacian (image, dst, -1, 3, 1, 0, cv::BORDER_CONSTANT); 120 dst.convertTo (dst, CV_32FC1); 121 cv::filter2D (dst, thresholded, -1, dst, cv::Point(-1, -1), 0, cv::BORDER_CONSTANT); 122 123 for (int i = 0; i < 10; i++) 124 { 125 cv::Mat thresholded_new; 126 double min_val; 127 double max_val; 128 cv::minMaxLoc (thresholded, &min_val, &max_val); 129 cv::threshold (thresholded, thresholded, round(max_val / 3.5), 255, cv::THRESH_BINARY); 130 thresholded.convertTo (thresholded, CV_8UC1); 131 crop_border (thresholded); 132 if (thresholded.rows < 3) 133 { 134 break; 135 } 136 int filter_size = (int)(std::max(3, ((thresholded.rows + thresholded.cols) / 2) / 10)); 137 if (!(filter_size & 1)) 138 { 139 filter_size++; 140 } 141 cv::Mat filter = cv::Mat::ones (filter_size, filter_size, CV_32FC1) / (float)(filter_size * filter_size - 1); 142 filter.at<float> (filter_size / 2, filter_size / 2) = 0; 143 cv::filter2D (thresholded, thresholded_new, -1, filter, cv::Point(-1, -1), 0, cv::BORDER_CONSTANT); 144 kernel_size = (thresholded_new.rows + thresholded_new.cols) / 2; 145 if (!(kernel_size & 1)) 146 { 147 kernel_size++; 148 } 149 thresholded = thresholded_new.clone(); 150 } 151 return kernel_size; 152 } 153 154 void 155 CVImageDeblurring::blind_deblurring (const cv::Mat &blurred, cv::Mat &deblurred, cv::Mat &kernel, int kernel_size, float noise_power, bool use_edgetaper) 156 { 157 cv::Mat gray_blurred; 158 cv::cvtColor (blurred, gray_blurred, CV_BGR2GRAY); 159 if (noise_power < 0) 160 { 161 cv::Mat median_blurred; 162 medianBlur (gray_blurred, median_blurred, 3); 163 noise_power = 1.0f / _helper->get_snr (gray_blurred, median_blurred); 164 XCAM_LOG_DEBUG ("estimated inv snr %f", noise_power); 165 } 166 if (kernel_size < 0) 167 { 168 kernel_size = estimate_kernel_size (gray_blurred); 169 XCAM_LOG_DEBUG ("estimated kernel size %d", kernel_size); 170 } 171 if (use_edgetaper) { 172 XCAM_LOG_DEBUG ("edgetaper will be used"); 173 } 174 else { 175 XCAM_LOG_DEBUG ("edgetaper will not be used"); 176 } 177 std::vector<cv::Mat> blurred_rgb (3); 178 cv::split (blurred, blurred_rgb); 179 std::vector<cv::Mat> deblurred_rgb (3); 180 cv::Mat result_deblurred; 181 cv::Mat result_kernel; 182 blind_deblurring_one_channel (gray_blurred, result_kernel, kernel_size, noise_power); 183 for (int i = 0; i < 3; i++) 184 { 185 cv::Mat input; 186 if (use_edgetaper) 187 { 188 _edgetaper->edgetaper (blurred_rgb[i], result_kernel, input); 189 } 190 else 191 { 192 input = blurred_rgb[i].clone (); 193 } 194 _wiener->wiener_filter (input, result_kernel, deblurred_rgb[i], noise_power); 195 _helper->apply_constraints (deblurred_rgb[i], 0); 196 } 197 cv::merge (deblurred_rgb, result_deblurred); 198 result_deblurred.convertTo (result_deblurred, CV_8UC3); 199 fastNlMeansDenoisingColored (result_deblurred, deblurred, 3, 3, 7, 21); 200 kernel = result_kernel.clone (); 201 } 202 203 void 204 CVImageDeblurring::blind_deblurring_one_channel (const cv::Mat &blurred, cv::Mat &kernel, int kernel_size, float noise_power) 205 { 206 cv::Mat kernel_current = cv::Mat::zeros (kernel_size, kernel_size, CV_32FC1); 207 cv::Mat deblurred_current = _helper->erosion (blurred, 2, 0); 208 float sigmar = 20; 209 for (int i = 0; i < _config.iterations; i++) 210 { 211 cv::Mat sharpened = _sharp->sharp_image_gray (deblurred_current, sigmar); 212 _wiener->wiener_filter (blurred, sharpened.clone (), kernel_current, noise_power); 213 kernel_current = kernel_current (cv::Rect (0, 0, kernel_size, kernel_size)); 214 double min_val; 215 double max_val; 216 cv::minMaxLoc (kernel_current, &min_val, &max_val); 217 _helper->apply_constraints (kernel_current, (float)max_val / 20); 218 _helper->normalize_weights (kernel_current); 219 _wiener->wiener_filter (blurred, kernel_current.clone(), deblurred_current, noise_power); 220 _helper->apply_constraints (deblurred_current, 0); 221 sigmar *= 0.9; 222 } 223 kernel = kernel_current.clone (); 224 } 225 226 } 227