Home | History | Annotate | Download | only in ocl
      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