blob: 524caa7a46b9c48c6845fa703f072c3b236e247f [file] [log] [blame]
/*
* cv_edgetaper.cpp - used in deblurring to remove ringing artifacts
*
* Copyright (c) 2016-2017 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Andrey Parfenov <a1994ndrey@gmail.com>
* Author: Wind Yuan <feng.yuan@intel.com>
*/
#include "cv_edgetaper.h"
namespace XCam {
void
CVEdgetaper::create_weights (const cv::Mat &image, const cv::Mat &psf, cv::Mat &coefficients)
{
cv::Mat rows_proj, cols_proj;
cv::Mat rows_proj_border, cols_proj_border;
cv::Mat rows_cor, cols_cor;
// get psf rows and cols projections
cv::reduce (psf, rows_proj, 1, cv::REDUCE_SUM, -1);
cv::reduce (psf, cols_proj, 0, cv::REDUCE_SUM, -1);
// calculate correlation for psf projections
cv::copyMakeBorder (rows_proj, rows_proj_border, (psf.rows - 1) / 2, (psf.rows - 1) / 2, 0, 0, cv::BORDER_CONSTANT, cv::Scalar::all (0));
cv::copyMakeBorder (cols_proj, cols_proj_border, 0, 0, (psf.cols - 1) / 2, (psf.cols - 1) / 2, cv::BORDER_CONSTANT, cv::Scalar::all (0));
cv::matchTemplate (rows_proj_border, rows_proj, rows_cor, cv::TM_CCORR);
cv::matchTemplate (cols_proj_border, cols_proj, cols_cor, cv::TM_CCORR);
// make it symmetric on both sides
cv::Mat rows_add = cv::Mat_<float>(1, 1) << rows_proj.at<float> (0, 0);
cv::Mat cols_add = cv::Mat_<float>(1, 1) << cols_proj.at<float> (0, 0);
cv::vconcat (rows_cor, rows_add, rows_cor);
cv::hconcat (cols_cor, cols_add, cols_cor);
double min, max;
cv::minMaxLoc (rows_cor, &min, &max);
rows_cor /= max;
cv::minMaxLoc (cols_cor, &min, &max);
cols_cor /= max;
// get matrix from projections
cv::Mat alpha = (cv::Scalar (1) - rows_proj) * (cv::Scalar (1) - cols_proj);
// expand it to the image size
int nc = image.cols / psf.cols + 1;
int nr = image.rows / psf.rows + 1;
cv::Mat expanded;
cv::repeat (alpha, nr, nc, expanded);
cv::Mat weights = expanded (cv::Rect (expanded.cols / 2 - image.cols / 2, expanded.rows / 2 - image.rows / 2, image.cols, image.rows));
coefficients = weights.clone ();
}
void
CVEdgetaper::edgetaper (const cv::Mat &img, const cv::Mat &psf, cv::Mat &output)
{
cv::Mat blurred = cv::Mat::zeros (img.rows, img.cols, CV_32FC1);
// flip PSF to perform convolution
cv::Mat psf_flipped;
cv::flip (psf, psf_flipped, -1);
cv::filter2D (img, blurred, CV_32FC1, psf_flipped, cv::Point (-1, -1), 0, cv::BORDER_CONSTANT);
cv::Mat coefficients;
create_weights (img, psf, coefficients);
cv::Mat result;
img.convertTo (result, CV_32FC1);
result = result.mul (coefficients) + blurred.mul (cv::Scalar (1.0f) - coefficients);
output = result.clone ();
}
}