使用拉普拉斯滤波器的图像锐化

时间:2012-08-09 07:00:31

标签: opencv

我试图从冈萨雷斯的书中锐化一些标准图像。下面是我尝试过的一些代码,但它没有接近锐化图像的结果。

cvSmooth(grayImg, grayImg, CV_GAUSSIAN, 3, 0, 0, 0);

IplImage* laplaceImg = cvCreateImage(cvGetSize(oriImg), IPL_DEPTH_16S, 1);

IplImage* abs_laplaceImg = cvCreateImage(cvGetSize(oriImg), IPL_DEPTH_8U, 1);

cvLaplace(grayImg, laplaceImg, 3);

cvConvertScaleAbs(laplaceImg, abs_laplaceImg, 1, 0);

IplImage* dstImg = cvCreateImage(cvGetSize(oriImg), IPL_DEPTH_8U, 1);
cvAdd(abs_laplaceImg, grayImg, dstImg, NULL); 

Before Sharpening锐化之前

My Sharpening Result我的锐化结果

Desired Result期望的结果

Absolute Laplace绝对拉普拉斯

4 个答案:

答案 0 :(得分:6)

我认为问题在于你在拍摄第二个衍生物之前模糊了图像。

这是使用C ++ API的工作代码(我正在使用Opencv 2.4.3)。我也试过MATLAB,结果是一样的。

#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;
}

玩得开心!

答案 1 :(得分:1)

我认为主要的问题在于你做了img + laplace,而img - laplace会给出更好的结果。我记得img - 2 * laplace是最好的,但我找不到我读到的地方,可能是我在大学读过的一本书。

答案 2 :(得分:1)

您需要img - laplace代替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)

因此,如果你看到从原始图像中减去拉普拉斯,你会看到4 * f(x,y)前面的减号被否定,这个词变为正数。

你也可以拥有-5 in the center pixel instead of -4的内核,使laplacian成为一个单步的过程,而不是让laplace得到laplace并做img - laplace为什么?尝试自己推导出来。

这将是最终的内核。

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

答案 3 :(得分:0)

图像处理确实是众所周知的结果,如果从图像中减去拉普拉斯算子,图像边缘会被放大,从而产生更清晰的图像。

  

拉普拉斯滤波器内核算法:sharpened_pixel = 5 *当前 - 左 - 右 - 上 - 下

enter image description here

所以代码看起来像这样:

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;
}

如果你是一个懒惰的人。享受以下乐趣。

 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;
}

结果就像这些。enter image description here