灰度拉普拉斯锐化实现

时间:2018-10-06 11:04:17

标签: c++ opencv image-processing

我正在尝试使用C ++实现拉普拉斯锐化,到目前为止,这是我的代码:

img = imread("cow.png", 0);
Mat convoSharp() {

    //creating new image
    Mat res = img.clone();
    for (int y = 0; y < res.rows; y++) {
        for (int x = 0; x < res.cols; x++) {
            res.at<uchar>(y, x) = 0.0;
        }
    }

    //variable declaration
    int filter[3][3] = { {0,1,0},{1,-4,1},{0,1,0} };
    //int filter[3][3] = { {-1,-2,-1},{0,0,0},{1,2,1} };
    int height = img.rows;
    int width = img.cols;
    int filterHeight = 3;
    int filterWidth = 3;
    int newImageHeight = height - filterHeight + 1;
    int newImageWidth = width - filterWidth + 1;
    int i, j, h, w;

    //convolution
    for (i = 0; i < newImageHeight; i++) {
        for (j = 0; j < newImageWidth; j++) {
            for (h = i; h < i + filterHeight; h++) {
                for (w = j; w < j + filterWidth; w++) {
                    res.at<uchar>(i,j) += filter[h - i][w - j] * img.at<uchar>(h,w);
                }
            }
        }
    }

    //img - laplace
    for (int y = 0; y < res.rows; y++) {
        for (int x = 0; x < res.cols; x++) {

            res.at<uchar>(y, x) = img.at<uchar>(y, x) - res.at<uchar>(y, x);

        }
    }



    return res;
}

this is the result

我真的不知道出了什么问题,我还尝试了不同的过滤器(1,1,1),(1,-8,1),(1,1,1),结果也相同(更多或更少)。我认为我不需要对结果进行归一化,因为结果的范围是0-255。有人可以解释我的代码中真正出了什么问题吗?

2 个答案:

答案 0 :(得分:0)

问题uchar太小,无法保留部分文件加盖操作的结果。

您应该创建一个临时变量,并将所有过滤后的位置添加到该变量,然后检查temp的值是否在<0,255>范围内,否则,您需要将最终结果限制为<0,255>

通过在行下面执行

res.at<uchar>(i,j) += filter[h - i][w - j] * img.at<uchar>(h,w);

部分结果可能大于255(uchar中的最大值)或为负(在过滤器中为-4或-8)。 temp必须为整数类型,以处理部分结果为负值的情况。

修复:

for (i = 0; i < newImageHeight; i++) {
    for (j = 0; j < newImageWidth; j++) {
        int temp = res.at<uchar>(i,j); // added
        for (h = i; h < i + filterHeight; h++) {
            for (w = j; w < j + filterWidth; w++) {
                temp += filter[h - i][w - j] * img.at<uchar>(h,w); // add to temp
            }
        }
        // clamp temp to <0,255>
        res.at<uchar>(i,j) = temp;
    }
}

减去图像时,还应该将值限制在<0,255>范围内。

答案 1 :(得分:0)

部分原因是您的ucharrafix07 suggested一样泛滥,但这并不是全部问题。

图像的拉普拉斯包含负值。它必须。而且您无法将其钳位为0,您需要保留负值。同样,给定您的过滤器版本,它的值最多可以为4 * 255。这意味着您需要使用带符号的16位类型来存储此输出。

但是有一种更简单,更有效的方法!

您正在计算img - laplace(img)。就卷积(*)而言,这是1 * img - laplace_kernel * img = (1 - laplace_kernel) * img。也就是说,您可以将这两个操作组合成一个卷积。不会更改图像的1内核是[(0,0,0),(0,1,0),(0,0,0)]。从中减去您的Laplace内核,您将获得[(0,-1,0),(-1,5,-1),(0,-1,0)]

因此,只需计算与该内核的卷积,然后使用int作为中间类型,然后将其钳位到uchar的输出范围即可,如rafix07所示。