diff options
author | Andrey Parfenov <a1994ndrey@gmail.com> | 2017-12-23 03:44:38 +0300 |
---|---|---|
committer | windyuan <feng.yuan@intel.com> | 2017-12-25 09:59:29 +0800 |
commit | f60f0a65705112bfa3ff3dc35d63d6896014ab8c (patch) | |
tree | e5dc31e920908dfa17b6b7269e6c96d464a5af7d | |
parent | be3ac1e217dd371c77983c812dfb149c258a3f42 (diff) | |
download | libxcam-f60f0a65705112bfa3ff3dc35d63d6896014ab8c.tar.gz |
fix edgetaper
Signed-off-by: Andrey Parfenov <a1994ndrey@gmail.com>
-rw-r--r-- | modules/ocl/cv_edgetaper.cpp | 112 | ||||
-rw-r--r-- | modules/ocl/cv_edgetaper.h | 7 | ||||
-rw-r--r-- | modules/ocl/cv_image_deblurring.cpp | 53 | ||||
-rw-r--r-- | modules/ocl/cv_image_deblurring.h | 6 | ||||
-rw-r--r-- | tests/test-image-deblurring.cpp | 2 |
5 files changed, 83 insertions, 97 deletions
diff --git a/modules/ocl/cv_edgetaper.cpp b/modules/ocl/cv_edgetaper.cpp index a07eeac..ab79238 100644 --- a/modules/ocl/cv_edgetaper.cpp +++ b/modules/ocl/cv_edgetaper.cpp @@ -25,86 +25,60 @@ namespace XCam { CVEdgetaper::CVEdgetaper () - : CVBaseClass() + : CVBaseClass () { } void -CVEdgetaper::normalized_autocorrelation (const cv::Mat &psf, cv::Mat &auto_correlation_psf) +CVEdgetaper::create_weights (const cv::Mat &image, const cv::Mat &psf, cv::Mat &coefficients) { - cv::Mat correlation; - cv::copyMakeBorder (psf, auto_correlation_psf, psf.cols - 1, 0, psf.rows - 1, 0, cv::BORDER_CONSTANT, cv::Scalar::all(0)); - cv::filter2D (auto_correlation_psf, correlation, -1, psf, cv::Point(0, 0), 0, cv::BORDER_CONSTANT); - cv::normalize (correlation, correlation, 0, 1.0f, cv::NORM_MINMAX); - auto_correlation_psf = correlation.clone (); + 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::create_weights (cv::Mat &coefficients, const cv::Mat &psf) -{ - int psfr_last = psf.rows - 1; - int psfc_last = psf.cols - 1; - - cv::Mat auto_correlation_psf; - normalized_autocorrelation(psf, auto_correlation_psf); - - for (int i = 0; i < coefficients.rows; i++) - { - for (int j = 0; j < coefficients.cols; j++) { - if (i < psfr_last) - { - if (j < psfc_last) - coefficients.at<float>(i, j) = auto_correlation_psf.at<float>(i, j); - else if (psfc_last <= j && j < (coefficients.cols - psfc_last)) - coefficients.at<float>(i, j) = auto_correlation_psf.at<float>(i, psfc_last); - else - coefficients.at<float>(i, j) = auto_correlation_psf.at<float>(i, j - (coefficients.cols - 2 * psfc_last) + 1); - } - else if (psfr_last <= i && i < (coefficients.rows - psfr_last)) - { - if (j < psfc_last) - coefficients.at<float>(i, j) = auto_correlation_psf.at<float>(psfr_last, j); - else if (psfc_last <= j && j < (coefficients.cols - psfc_last)) - coefficients.at<float>(i, j) = 1.0f; - else - coefficients.at<float>(i, j) = auto_correlation_psf.at<float>(psfr_last, j - (coefficients.cols - 2 * psfc_last) + 1); - } - else - { - if (j < psfc_last) - coefficients.at<float>(i, j) = auto_correlation_psf.at<float>(i - (coefficients.rows - 2 * psfr_last) + 1, j); - else if (psfc_last <= j && j < (coefficients.cols - psfc_last)) - coefficients.at<float>(i, j) = auto_correlation_psf.at<float>(i - (coefficients.rows - 2 * psfr_last) + 1, psfc_last); - else - coefficients.at<float>(i, j) = auto_correlation_psf.at<float>(i - (coefficients.rows - 2 * psfr_last) + 1, j - (coefficients.cols - 2 * psfc_last) + 1); - } - } - } -} - -cv::Mat -CVEdgetaper::edgetaper (const cv::Mat &img, const cv::Mat &psf) +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); - cv::filter2D (img, blurred, CV_32F, psf, cv::Point(-1, -1), 0, cv::BORDER_CONSTANT); - - cv::Mat coefficients = cv::Mat::zeros (img.rows, img.cols, CV_32FC1); - create_weights (coefficients, psf); - cv::Mat result = img.clone (); - result.convertTo (result, CV_32FC1); - for (int i = 0; i < img.rows; i++) - { - for (int j = 0; j < img.cols; j++) - { - if (coefficients.at<float>(i, j) != 1.0f) - { - result.at<float>(i, j) = img.at<unsigned char>(i, j) * coefficients.at<float>(i, j) + - blurred.at<float>(i, j) * (1.0f - coefficients.at<float>(i, j)); - } - } - } - return result; + // 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 (); } } diff --git a/modules/ocl/cv_edgetaper.h b/modules/ocl/cv_edgetaper.h index 9c00fc7..1ead29f 100644 --- a/modules/ocl/cv_edgetaper.h +++ b/modules/ocl/cv_edgetaper.h @@ -30,17 +30,16 @@ namespace XCam { + class CVEdgetaper : public CVBaseClass { public: explicit CVEdgetaper (); - - cv::Mat edgetaper (const cv::Mat &image, const cv::Mat &psf); + void edgetaper (const cv::Mat &image, const cv::Mat &psf, cv::Mat &output); private: - void create_weights (cv::Mat &coefficients, const cv::Mat &psf); - void normalized_autocorrelation (const cv::Mat &psf, cv::Mat &auto_correlation_psf); + void create_weights (const cv::Mat &image, const cv::Mat &psf, cv::Mat &coefficients); XCAM_DEAD_COPY (CVEdgetaper); }; diff --git a/modules/ocl/cv_image_deblurring.cpp b/modules/ocl/cv_image_deblurring.cpp index c036b42..730eb42 100644 --- a/modules/ocl/cv_image_deblurring.cpp +++ b/modules/ocl/cv_image_deblurring.cpp @@ -25,12 +25,12 @@ namespace XCam { CVImageDeblurring::CVImageDeblurring () - : CVBaseClass() + : CVBaseClass () { - _helper = new CVImageProcessHelper(); - _sharp = new CVImageSharp(); - _edgetaper = new CVEdgetaper(); - _wiener = new CVWienerFilter(); + _helper = new CVImageProcessHelper (); + _sharp = new CVImageSharp (); + _edgetaper = new CVEdgetaper (); + _wiener = new CVWienerFilter (); } void @@ -152,35 +152,52 @@ CVImageDeblurring::estimate_kernel_size (const cv::Mat &image) } void -CVImageDeblurring::blind_deblurring (const cv::Mat &blurred, cv::Mat &deblurred, cv::Mat &kernel, int kernel_size, float noise_power) +CVImageDeblurring::blind_deblurring (const cv::Mat &blurred, cv::Mat &deblurred, cv::Mat &kernel, int kernel_size, float noise_power, bool use_edgetaper) { cv::Mat gray_blurred; cv::cvtColor (blurred, gray_blurred, CV_BGR2GRAY); - if (noise_power < 0) { + if (noise_power < 0) + { cv::Mat median_blurred; medianBlur (gray_blurred, median_blurred, 3); noise_power = 1.0f / _helper->get_snr (gray_blurred, median_blurred); - XCAM_LOG_DEBUG("estimated inv snr %f", noise_power); + XCAM_LOG_DEBUG ("estimated inv snr %f", noise_power); } - if (kernel_size < 0) { + if (kernel_size < 0) + { kernel_size = estimate_kernel_size (gray_blurred); - XCAM_LOG_DEBUG("estimated kernel size %d", kernel_size); + XCAM_LOG_DEBUG ("estimated kernel size %d", kernel_size); + } + if (use_edgetaper) { + XCAM_LOG_DEBUG ("edgetaper will be used"); + } + else { + XCAM_LOG_DEBUG ("edgetaper will not be used"); } - std::vector<cv::Mat> blurred_rgb(3); - cv::split(blurred, blurred_rgb); - std::vector<cv::Mat> deblurred_rgb(3); + std::vector<cv::Mat> blurred_rgb (3); + cv::split (blurred, blurred_rgb); + std::vector<cv::Mat> deblurred_rgb (3); cv::Mat result_deblurred; cv::Mat result_kernel; blind_deblurring_one_channel (gray_blurred, result_kernel, kernel_size, noise_power); for (int i = 0; i < 3; i++) { - _wiener->wiener_filter (_edgetaper->edgetaper(blurred_rgb[i], result_kernel), result_kernel, deblurred_rgb[i], noise_power); + cv::Mat input; + if (use_edgetaper) + { + _edgetaper->edgetaper (blurred_rgb[i], result_kernel, input); + } + else + { + input = blurred_rgb[i].clone (); + } + _wiener->wiener_filter (input, result_kernel, deblurred_rgb[i], noise_power); _helper->apply_constraints (deblurred_rgb[i], 0); } cv::merge (deblurred_rgb, result_deblurred); result_deblurred.convertTo (result_deblurred, CV_8UC3); fastNlMeansDenoisingColored (result_deblurred, deblurred, 3, 3, 7, 21); - kernel = result_kernel.clone(); + kernel = result_kernel.clone (); } void @@ -189,19 +206,17 @@ CVImageDeblurring::blind_deblurring_one_channel (const cv::Mat &blurred, cv::Mat cv::Mat kernel_current = cv::Mat::zeros (kernel_size, kernel_size, CV_32FC1); cv::Mat deblurred_current = _helper->erosion (blurred, 2, 0); float sigmar = 20; - cv::Mat enhanced_blurred = blurred.clone (); for (int i = 0; i < _config.iterations; i++) { cv::Mat sharpened = _sharp->sharp_image_gray (deblurred_current, sigmar); _wiener->wiener_filter (blurred, sharpened.clone (), kernel_current, noise_power); - kernel_current = kernel_current (cv::Rect(0, 0, kernel_size, kernel_size)); + kernel_current = kernel_current (cv::Rect (0, 0, kernel_size, kernel_size)); double min_val; double max_val; cv::minMaxLoc (kernel_current, &min_val, &max_val); _helper->apply_constraints (kernel_current, (float)max_val / 20); _helper->normalize_weights (kernel_current); - enhanced_blurred = _edgetaper->edgetaper (blurred, kernel_current); - _wiener->wiener_filter (enhanced_blurred, kernel_current.clone(), deblurred_current, noise_power); + _wiener->wiener_filter (blurred, kernel_current.clone(), deblurred_current, noise_power); _helper->apply_constraints (deblurred_current, 0); sigmar *= 0.9; } diff --git a/modules/ocl/cv_image_deblurring.h b/modules/ocl/cv_image_deblurring.h index f46de35..afac22c 100644 --- a/modules/ocl/cv_image_deblurring.h +++ b/modules/ocl/cv_image_deblurring.h @@ -35,7 +35,7 @@ namespace XCam { struct CVIDConfig { int iterations; // number of iterations for IBD algorithm - CVIDConfig (unsigned int _iterations = 200) + CVIDConfig (unsigned int _iterations = 50) { iterations = _iterations; } @@ -46,11 +46,9 @@ class CVImageDeblurring : public CVBaseClass public: explicit CVImageDeblurring (); - void set_config (CVIDConfig config); CVIDConfig get_config (); - - void blind_deblurring (const cv::Mat &blurred, cv::Mat &deblurred, cv::Mat &kernel, int kernel_size = -1, float noise_power = -1.0f); + void blind_deblurring (const cv::Mat &blurred, cv::Mat &deblurred, cv::Mat &kernel, int kernel_size = -1, float noise_power = -1.0f, bool use_edgetaper = true); private: void blind_deblurring_one_channel (const cv::Mat &blurred, cv::Mat &kernel, int kernel_size, float noise_power); diff --git a/tests/test-image-deblurring.cpp b/tests/test-image-deblurring.cpp index 91f019f..a5b24ab 100644 --- a/tests/test-image-deblurring.cpp +++ b/tests/test-image-deblurring.cpp @@ -111,7 +111,7 @@ int main (int argc, char *argv[]) } cv::Mat deblurred; cv::Mat kernel; - imageDeblurring->blind_deblurring (blurred, deblurred, kernel, -1, -1, true); + imageDeblurring->blind_deblurring (blurred, deblurred, kernel, -1, -1, false); float input_sharp = sharp->measure_sharp (blurred); float output_sharp = sharp->measure_sharp (deblurred); if (need_save_output) |