Image Sharpening Using Laplacian Filter

后端 未结 4 1106
天涯浪人
天涯浪人 2020-12-14 11:57

I was trying to sharpening on some standard image from Gonzalez books. Below are some code that I have tried but it doesn\'t get closer to the results of the sharpened image

相关标签:
4条回答
  • 2020-12-14 12:37

    I think the problem is that you are blurring the image before take the 2nd derivate.

    Here is the working code with the C++ API (I'm using Opencv 2.4.3). I tried also with MATLAB and the result is the same.

    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    #include <iostream>
    
    using namespace cv;
    using namespace std;
    
    
    int main(int /*argc*/, char** /*argv*/) {
    
        Mat img, imgLaplacian, imgResult;
    
        //------------------------------------------------------------------------------------------- test, first of all
        // now do it by hand
        img = (Mat_<uchar>(4,4) << 0,1,2,3,4,5,6,7,8,9,0,11,12,13,14,15); 
    
        // first, the good result
        Laplacian(img, imgLaplacian, CV_8UC1);
        cout << "let opencv do it" << endl;
        cout << imgLaplacian << endl;
    
        Mat kernel = (Mat_<float>(3,3) << 
            0,  1, 0,
            1, -4, 1,
            0,  1, 0); 
        int window_size = 3;
    
        // now, reaaallly by hand
        // note that, for avoiding padding, the result image will be smaller than the original one.
        Mat frame, frame32;
        Rect roi;
        imgLaplacian = Mat::zeros(img.size(), CV_32F);
        for(int y=0; y<img.rows-window_size/2-1; y++) {
            for(int x=0; x<img.cols-window_size/2-1; x++) {
                roi = Rect(x,y, window_size, window_size);
                frame = img(roi);
                frame.convertTo(frame, CV_32F);
                frame = frame.mul(kernel);
                float v = sum(frame)[0];
                imgLaplacian.at<float>(y,x) = v;
            }
        }
        imgLaplacian.convertTo(imgLaplacian, CV_8U);
        cout << "dudee" << imgLaplacian << endl;
    
        // a little bit less "by hand"..
        // using cv::filter2D
        filter2D(img, imgLaplacian, -1, kernel);
        cout << imgLaplacian << endl;
    
    
        //------------------------------------------------------------------------------------------- real stuffs now
        img = imread("moon.jpg", 0); // load grayscale image
    
        // ok, now try different kernel
        kernel = (Mat_<float>(3,3) << 
            1,  1, 1,
            1, -8, 1,
            1,  1, 1); // another approximation of second derivate, more stronger
    
        // do the laplacian filtering as it is
        // well, we need to convert everything in something more deeper then CV_8U
        // because the kernel has some negative values, 
        // and we can expect in general to have a Laplacian image with negative values
        // BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
        // so the possible negative number will be truncated
        filter2D(img, imgLaplacian, CV_32F, kernel);
        img.convertTo(img, CV_32F);
        imgResult = img - imgLaplacian;
    
        // convert back to 8bits gray scale
        imgResult.convertTo(imgResult, CV_8U);
        imgLaplacian.convertTo(imgLaplacian, CV_8U);
    
        namedWindow("laplacian", CV_WINDOW_AUTOSIZE);
        imshow( "laplacian", imgLaplacian );
    
        namedWindow("result", CV_WINDOW_AUTOSIZE);
        imshow( "result", imgResult );
    
        while( true ) {
            char c = (char)waitKey(10);
            if( c == 27 ) { break; }
        }
    
        return 0;
    }
    

    Have fun!

    0 讨论(0)
  • 2020-12-14 12:44

    It is indeed a well-known result in image processing that if you subtract its Laplacian from an image, the image edges are amplified giving a sharper image.

    Laplacian Filter Kernel algorithm: sharpened_pixel = 5 * current – left – right – up – down

    enter image description here

    So the Code will look like these:

    void sharpen(const Mat& img, Mat& result)
    {    
        result.create(img.size(), img.type());
        //Processing the inner edge of the pixel point, the image of the outer edge of the pixel should be additional processing
        for (int row = 1; row < img.rows-1; row++)
        {
            //Front row pixel
            const uchar* previous = img.ptr<const uchar>(row-1);
            //Current line to be processed
            const uchar* current = img.ptr<const uchar>(row);
            //new row
            const uchar* next = img.ptr<const uchar>(row+1);
            uchar *output = result.ptr<uchar>(row);
            int ch = img.channels();
            int starts = ch;
            int ends = (img.cols - 1) * ch;
            for (int col = starts; col < ends; col++)
            {
                //The traversing pointer of the output image is synchronized with the current row, and each channel value of each pixel in each row is given a increment, because the channel number of the image is to be taken into account.
                *output++ = saturate_cast<uchar>(5 * current[col] - current[col-ch] - current[col+ch] - previous[col] - next[col]);
            }
        } //end loop
        //Processing boundary, the peripheral pixel is set to 0
        result.row(0).setTo(Scalar::all(0));
        result.row(result.rows-1).setTo(Scalar::all(0));
        result.col(0).setTo(Scalar::all(0));
        result.col(result.cols-1).setTo(Scalar::all(0));
    }
    
    int main()
    {    
        Mat lena = imread("lena.jpg");
        Mat sharpenedLena;
        ggicci::sharpen(lena, sharpenedLena);
    
        imshow("lena", lena);
        imshow("sharpened lena", sharpenedLena);
        cvWaitKey();
        return 0;
    }
    

    If you are a lazier. Have fun with the following.

     int main()
     {    
         Mat lena = imread("lena.jpg");
         Mat sharpenedLena;
         Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, -1, 4, -1, 0, -1, 0);
         cv::filter2D(lena, sharpenedLena, lena.depth(), kernel);
    
         imshow("lena", lena);
         imshow("sharpened lena", sharpenedLena);
        cvWaitKey();
        return 0;
    }
    

    And the result like these.enter image description here

    0 讨论(0)
  • 2020-12-14 12:50

    You need to do img - laplace instead of img + laplace.

    laplace: f(x,y) = f(x-1,y+1) + f(x-1,y-1) + f(x,y+1) + f(x+1,y) - 4*f(x,y)
    

    So, if you see subtract laplace from the original image you would see that the minus sign in front of 4*f(x,y) gets negated and this term becomes positive.

    You could also have kernel with -5 in the center pixel instead of -4 to make the laplacian a one-step process instead of getting the getting the laplace and doing img - laplace Why? Try deriving that yourself.

    This would be the final kernel.

    Mat kernel = (Mat_(3,3) << -1, 0, -1, 0, -5, 0, -1, 0, -1);

    0 讨论(0)
  • 2020-12-14 12:55

    I think the main problem lies in the fact that you do img + laplace, while img - laplace would give better results. I remember that img - 2*laplace was best, but I cannot find where I read that, probably in one of the books I read in university.

    0 讨论(0)
提交回复
热议问题