【问题标题】:implement laplacian 3x3实施拉普拉斯 3x3
【发布时间】:2011-11-18 23:02:27
【问题描述】:

我正在阅读 Gonzalez 和 Woods 的 DIP 第 2 版,并尝试使用 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 循环中遗漏了什么?

Edit1:在谷歌上环顾后终于得到了答案。这个dsp的东西肯定很棘手!我在上面的代码中添加了,它会锐化图像。

干杯

【问题讨论】:

  • 这对 dsp.stackexchange.com 来说是个好问题

标签: c++ image-processing wxwidgets


【解决方案1】:

你不应该在计算加权和之后除以掩码中的像素数,从而产生加权平均值吗?没有这个,九个像素值的总和(即使乘以不太亮的掩码值)很容易超过 255。

【讨论】:

  • 掩码矩阵中的值之和为零,所以不,不会有任何会导致溢出的整体增益。但是,您确实需要注意在中间计算中使用更大的类型,否则在计算总和时可能会溢出 8 位值。对于每个像素,拉普拉斯算子将其替换为所有相邻像素的总和减去原始像素值的 8 倍,这是一种微分运算。它用于边缘检测。
  • 谢谢。我现在会调查一下。
  • @Jason R:回答这个问题——我认为这正是这里发生的事情。
  • @Jason R:我从你的最后两句话中得到的是,对于输出像素 g(x,y) = 所有邻居的总和(总共 9) - 8*f(x, y) 而 f(x,y) 是输入像素?
  • @Jason R:如果你有一个值为 0 的像素被 8 个像素包围,所有这些像素的值都是 255,你会得到 8 * 255 作为结果。相反,如果它是被 0 包围的 255,则得到 -8 * 255。这绝对是溢出。只有当滤波器积分为 1 时,您才能获得整体增益。
【解决方案2】:

我认为您的问题是 r、g 和 b 是 unsigned int 类型,并且根据您使用的编译器及其优化方式,您会将它们隐式转换为 rtotal += r* kernel[y+1][x+1]; 等行中的浮点数。但是如果编译器的转换与您的预期不同,则计算中间值将不起作用,因为 unsigned int 不能为负数。

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

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

【讨论】:

  • 当浮点数乘以无符号字符时,编译器总是将无符号字符提升为浮点数。但最后不适合 8 位,负值肯定是问题。
  • r,g,b 是无符号字符的原因是因为 GetRed/Green/Blue 函数返回无符号字符。
【解决方案3】:

首先,与拉普拉斯算子卷积的结果可能有负值。考虑一个被 0 包围的值为 1 的像素。该像素的卷积结果将为-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/btotal 中,这是一个浮点值,它应该足够大,对吗?据我所见,一个邻居的最大值可以是 8*255 或 -8*255,就像你上面所说的那样,即 (-)2040 *9(九个邻居加在一起)= (-)18360。我在 c++ 中查找浮点范围,它说浮点的范围是 7digits。但是,现在我完全明白为什么我有一个黑白像素的大博客是因为我错过了其他计算。请参阅我的版本 OP。谢谢!
  • 您使用浮点数作为 r/g/btotal 的事实很好。当您将 r/g/btotal 的值截断为 0 到 255 之间时,就会出现问题。而不是将低于 0 的所有值设置为 0 并将高于 255 的所有值设置为 255,您应该缩放该值。您正在截断范围,而您应该压缩范围。
  • 是的,我现在明白了。我应该缩放值而不是截断它。 tyvm!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-07
  • 2011-04-28
  • 2020-12-23
  • 2016-07-24
  • 2011-04-29
相关资源
最近更新 更多