实施拉普拉斯 3x3
我正在阅读 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 循环中遗漏了一些东西吗?
Edit1:在谷歌上查找后终于得到答案。这个 dsp 东西绝对是棘手的!我添加到上面的代码中,它会锐化图像。
干杯
Im reading DIP 2nd edition by Gonzalez and Woods and try to my hands dirty with Laplacian mask (page 129&130) using wxImage.
float kernel [3][3]= {{1, 1, 1},{1,-8, 1},{1, 1, 1}};
here is the processing loops:
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);
I applied that to the North Pole picture (grey image) and all I get is a blob of black and white pixels!
Any ideas where may I have missed something in the for loops?
Edit1: Finally get the answer after looking around on google. This dsp stuff is definitely tricky! I added to the code above, it will sharpen the image.
Cheers
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先,与拉普拉斯算子卷积的结果可能具有负值。考虑一个值为 1 且被 0 包围的像素。该像素处的卷积结果将为-8。
其次,结果的范围将在 [-8 * 255, 8 * 255] 之间,这绝对不适合 8 位。本质上,当您进行范围检查时,您将丢失大部分信息,并且大多数结果像素最终将是 0 或 255。
您要做的是将结果存储在有符号类型的数组中并且足够宽以处理范围。然后,如果您希望输出 8 位图像,则需要重新缩放值,以便 -8 * 255 映射到 0,8 * 255 映射到 255。或者您可以重新缩放它,以便最小值映射到0 和最大值映射到 255。
编辑:在这种特定情况下,您可以执行以下操作:
简化为
这会将 rtotal 映射到 0 到 255 之间的范围,而无需截断。您应该对
gtotal
和btotal
执行相同的操作。First, the result of convolving with a Laplacian can have negative values. Consider a pixel with a value of 1 surrounded by 0's. The result of the convolution at that pixel will be -8.
Second, the range of the result will be between [-8 * 255, 8 * 255], which definitely does not fit into 8 bits. Essentially, when you do your range checking, you are losing most of the information, and most of your resulting pixels will end up either being 0 or 255.
What you have to do is store the result in an array of a type that is signed and wide enough to handle the range. Then, if you wish to output an 8-bit image, you would need to rescale the values so that -8 * 255 maps to 0, and 8 * 255 maps to 255. Or you can rescale it so that the least value maps to 0 and the greatest value maps to 255.
Edit: in this specific case, you can do the following:
which simplifies to
This would map rtotal into a range between 0 and 255 without truncation. You should do the same for
gtotal
andbtotal
.我认为你的问题是 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 是循环到垂直。I think your problem is that r, g and b are type unsigned int and that, depending on which compiler you are using and how it is optimising, you are implicitly casting them to floats in the lines
rtotal += r* kernel[y+1][x+1];
etc. But if the compiler casts differently to your expectations then computing the middle value will not work because unsigned int can't be negative.Solution: change r, g and b to float.
It won't make any difference but there is a tiny error in the lines
r = Image->GetRed(i+y,j+x);
because i is looping over the horizontal and j is looping to vertical.在计算加权和后,您是否不应该除以掩模中的像素数,从而产生加权平均值?如果没有这个,九个像素值的总和(即使乘以不太亮的掩模值)将很容易超过 255。
Are you not supposed to divide by the number of pixels in the mask after computing the weighted sum, thus producing a weighted average? Without this, the sum of nine pixel values (even when multiplied with not-too-bright mask values) will easily exceed 255.