实现拉普拉斯3x3

implement laplacian 3x3

本文关键字:3x3 普拉斯 实现      更新时间:2023-10-16

我正在阅读Gonzalez和Woods的DIP第二版,并尝试使用wxImage使用拉普拉斯掩模(第129页和130页)。

float kernel [3][3]= {{1, 1, 1},{1,-8, 1},{1, 1, 1}};   

下面是处理循环:

unsigned char r,g,b;                    
float rtotal, gtotal, btotal; rtotal = gtotal = btotal = 0.0;   
//ignore the border pixel              
for(int i = 1; i<imgWidth-1; i++)
{
   for(int j = 1; j<imgHeight-1; j++) 
    {
     rtotal = gtotal=btotal =0.0;

       for(int y = -1; y<=1;y++)
       {
            for(int x = -1; x<=1;x++)
            {
            // get each channel pixel value
            r = Image->GetRed(i+y,j+x);
            g = Image->GetGreen(i+y,j+x);
            b = Image->GetBlue(i+y,j+x);
            // calculate each channel surrouding neighbour pixel value base   
            rtotal += r* kernel[y+1][x+1];
            gtotal += g* kernel[y+1][x+1] ;
            btotal += b* kernel[y+1][x+1];
            }
    }
            //edit1: here is how to sharpen the image
            // original pixel - (0.2 * the sum of pixel neighbour)
            rtotal = loadedImage->GetRed(x,y) - 0.2*rtotal;
    gtotal = loadedImage->GetGreen(x,y) - 0.2*gtotal;
    btotal = loadedImage->GetBlue(x,y) - 0.2*btotal;
    // range checking
    if (rtotal >255) rtotal = 255;
       else if (rtotal <0) rtotal = 0;
    if(btotal>255) btotal = 255;
       else if(btotal < 0) btotal = 0;
    if(gtotal > 255) gtotal = 255;
       else if (gtotal < 0 ) gtotal =0;
    // commit new pixel value
    Image->SetRGB(i,j, rtotal, gtotal, btotal);

我把它应用到北极的图片(灰色图像),我得到的是一个黑色和白色像素的斑点!

任何想法,我可能错过了一些东西在for循环?

编辑1:终于在谷歌上找到了答案。这个dsp的东西绝对是棘手的!我添加到上面的代码,它将锐化图像。

欢呼

首先,与拉普拉斯算子卷积的结果可以是负值。考虑一个值为1的像素,周围是0。在该像素处的卷积结果将是-8。

第二,结果的范围将在[-8 * 255,8 * 255]之间,这肯定不适合8位。从本质上讲,当你进行范围检查时,你会丢失大部分信息,并且大多数得到的像素最终将为0或255。

你需要做的是将结果存储在一个有符号且足够宽的数组中,以处理该范围。然后,如果希望输出8位图像,则需要重新缩放值,以便-8 * 255映射为0,8 * 255映射为255。或者您可以重新调整它,使最小值映射为0,最大值映射为255。

编辑:在这种特殊情况下,您可以执行以下操作:

rtotal = (rtotal + 8 * 255) / (16 * 255) * 255;

简化为

rtotal = (rtotal + 8 * 255) / 16;

将rtotal映射为0到255之间的范围而不截断。您应该对gtotalbtotal执行相同的操作。

我认为你的问题是r, g和b是类型unsigned int,这取决于你正在使用的编译器以及它是如何优化的,你隐式地将它们转换为rtotal += r* kernel[y+1][x+1];等行的浮点数。但是,如果编译器的类型转换与您的期望不同,那么计算中间值将无法工作,因为unsigned int不能为负。

解决方案:将r、g、b改为float

这不会有任何区别,但是在r = Image->GetRed(i+y,j+x);行中有一个小错误,因为i在水平方向上循环,j在垂直方向上循环。

你不应该在计算加权和后除以掩码中的像素数,从而产生加权平均值吗?如果不这样做,9个像素值的总和(即使与不太亮的蒙版值相乘)将很容易超过255。