1 /*
2 * cv_edgetaper.cpp - used in deblurring to remove ringing artifacts
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@gmail.com>
19 * Author: Wind Yuan <feng.yuan@intel.com>
20 */
21
22 #include "cv_edgetaper.h"
23
24 namespace XCam {
25
26
CVEdgetaper()27 CVEdgetaper::CVEdgetaper ()
28 : CVBaseClass ()
29 {
30
31 }
32
33 void
create_weights(const cv::Mat & image,const cv::Mat & psf,cv::Mat & coefficients)34 CVEdgetaper::create_weights (const cv::Mat &image, const cv::Mat &psf, cv::Mat &coefficients)
35 {
36 cv::Mat rows_proj, cols_proj;
37 cv::Mat rows_proj_border, cols_proj_border;
38 cv::Mat rows_cor, cols_cor;
39 // get psf rows and cols projections
40 cv::reduce (psf, rows_proj, 1, CV_REDUCE_SUM, -1);
41 cv::reduce (psf, cols_proj, 0, CV_REDUCE_SUM, -1);
42 // calculate correlation for psf projections
43 cv::copyMakeBorder (rows_proj, rows_proj_border, (psf.rows - 1) / 2, (psf.rows - 1) / 2, 0, 0, cv::BORDER_CONSTANT, cv::Scalar::all (0));
44 cv::copyMakeBorder (cols_proj, cols_proj_border, 0, 0, (psf.cols - 1) / 2, (psf.cols - 1) / 2, cv::BORDER_CONSTANT, cv::Scalar::all (0));
45 cv::matchTemplate (rows_proj_border, rows_proj, rows_cor, CV_TM_CCORR);
46 cv::matchTemplate (cols_proj_border, cols_proj, cols_cor, CV_TM_CCORR);
47 // make it symmetric on both sides
48 cv::Mat rows_add = cv::Mat_<float>(1, 1) << rows_proj.at<float> (0, 0);
49 cv::Mat cols_add = cv::Mat_<float>(1, 1) << cols_proj.at<float> (0, 0);
50 cv::vconcat (rows_cor, rows_add, rows_cor);
51 cv::hconcat (cols_cor, cols_add, cols_cor);
52 double min, max;
53 cv::minMaxLoc (rows_cor, &min, &max);
54 rows_cor /= max;
55 cv::minMaxLoc (cols_cor, &min, &max);
56 cols_cor /= max;
57 // get matrix from projections
58 cv::Mat alpha = (cv::Scalar (1) - rows_proj) * (cv::Scalar (1) - cols_proj);
59 // expand it to the image size
60 int nc = image.cols / psf.cols + 1;
61 int nr = image.rows / psf.rows + 1;
62 cv::Mat expanded;
63 cv::repeat (alpha, nr, nc, expanded);
64 cv::Mat weights = expanded (cv::Rect (expanded.cols / 2 - image.cols / 2, expanded.rows / 2 - image.rows / 2, image.cols, image.rows));
65 coefficients = weights.clone ();
66 }
67
68 void
edgetaper(const cv::Mat & img,const cv::Mat & psf,cv::Mat & output)69 CVEdgetaper::edgetaper (const cv::Mat &img, const cv::Mat &psf, cv::Mat &output)
70 {
71 cv::Mat blurred = cv::Mat::zeros (img.rows, img.cols, CV_32FC1);
72 // flip PSF to perform convolution
73 cv::Mat psf_flipped;
74 cv::flip (psf, psf_flipped, -1);
75 cv::filter2D (img, blurred, CV_32FC1, psf_flipped, cv::Point (-1, -1), 0, cv::BORDER_CONSTANT);
76 cv::Mat coefficients;
77 create_weights (img, psf, coefficients);
78 cv::Mat result;
79 img.convertTo (result, CV_32FC1);
80 result = result.mul (coefficients) + blurred.mul (cv::Scalar (1.0f) - coefficients);
81 output = result.clone ();
82 }
83
84 }
85