最近我正在编写一个脚本来操作图像中的像素值。这个想法是将落入给定范围内的像素设置为特定值。不是使用从像素到像素循环的命令“for”,而是使用图像表达式,例如:
Img = (Img>=thresh_Low && Img<=thresh_Up ? 0 : Img)
问题来了:如果我想用相邻像素的平均值代替像素值,而不仅仅是上面例子中的 0 之类的固定值,那么像素循环似乎就无法避免了。有谁知道这里仍然可以使用图像表达的方法的任何解决方法?
提前致谢。
最近我正在编写一个脚本来操作图像中的像素值。这个想法是将落入给定范围内的像素设置为特定值。不是使用从像素到像素循环的命令“for”,而是使用图像表达式,例如:
Img = (Img>=thresh_Low && Img<=thresh_Up ? 0 : Img)
问题来了:如果我想用相邻像素的平均值代替像素值,而不仅仅是上面例子中的 0 之类的固定值,那么像素循环似乎就无法避免了。有谁知道这里仍然可以使用图像表达的方法的任何解决方法?
提前致谢。
计算图像表达式比任何逐像素操作都要高效得多。即使您因此计算了一些不需要的平均值,脚本也会执行得更快。所以:
您应该计算一个平均图像(对于所有像素,而不仅仅是蒙版的像素),然后在蒙版分配中使用它。
以下示例说明了这一点。只有最后两行是您问题的直接答案。该条件用于复制原始值或平均值:
number aver_NN = 3 // Next neighbor averaging. 1 = 3x3, 2 = 5x5 etc.)
number maskRad = 0.3 // just a radius to show masking
image img := GetFrontImage()
if ( 2 != img.ImageGetNumDimensions() ) Throw( "Only 2D images are supported." )
// Create average image (ignoring border region for simplicity)
image av := img * 0
for( number dx=-aver_NN; dx<=aver_NN; dx++ )
for( number dy=-aver_NN; dy<=aver_NN; dy++ )
av += img.offset(dx,dy)
av /= (2*aver_NN + 1) ** 2
// Apply masked replacement
image replaced = iradius < iwidth*maskrad ? av : img
replaced.ShowImage()
平均是通过使用offset
命令将整个图像移动一个像素来完成的。0
此命令将用该值替换边框像素。将所有移位的图像相加并除以图像的数量,因此在每个像素处给出了相邻像素的平均值,但边界像素中的归一化是不正确的。以下脚本使用显式图像而不是 for 循环来显示这一点:
number size = 25
image test := realimage("Source",4,size,size)
test = 1 + random()
test.ShowImage()
image offset_N = test.offset( 0, -1 )
image offset_S = test.offset( 0, 1 )
image offset_W = test.offset( -1, 0 )
image offset_E = test.offset( 1, 0 )
offset_N.ShowImage()
offset_N.SetName("N")
offset_S.ShowImage()
offset_S.SetName("S")
offset_W.ShowImage()
offset_W.SetName("W")
offset_E.ShowImage()
offset_E.SetName("E")
image average = test + offset_N + offset_S + offset_W + offset_E
average /= 5
average.SetName("Average")
average.ShowImage()
EGUPerformActionWithAllShownImages("Arrange")
为了解决边界问题,可以使用两种策略进行标准化。
...
image average = test + offset_N + offset_S + offset_W + offset_E
average.SetName("Average")
// Divide corners by 3
// Divide edges by 4
// Divide rest by 5
average.slice2(0,0,0 ,0,2,size-1, 1,2,size-1) /= 3
average.slice2(1,0,0 ,0,size-2,1, 1,2,size-1) /= 4
average.slice2(0,1,0 ,0,2,size-1, 1,size-2,1) /= 4
average.slice2(1,1,0 ,0,size-2,1, 1,size-2,1) /= 5
...
1
与源大小相同的 -valued 图像并执行相同的求和步骤!这使得上面的脚本变成:number aver_NN = 2 // Next neighbor averaging. 1 = 3x3, 2 = 5x5 etc.)
number maskRad = 1 // just a radius to show masking
image img := GetFrontImage()
if ( 2 != img.ImageGetNumDimensions() ) Throw( "Only 2D images are supported." )
// Create average image
image av = img * 0
image weight = av
image proxy = av + 1
for( number dx=-aver_NN; dx<=aver_NN; dx++ )
{
for( number dy=-aver_NN; dy<=aver_NN; dy++ )
{
av += img.offset(dx,dy)
weight += proxy.offset(dx,dy)
}
}
weight.SetName("Sum weight")
weight.showImage()
av /= weight
// Apply masked replacement
image replaced = iradius < iwidth*maskrad ? av : img
replaced.ShowImage()
Convolution()
命令创建平均图像,该命令可以立即正确处理边界情况。在这里,只需将平均图像创建为:// Create average image
// Define an averaging kernel
image kernel := [5,5] : {
{ 0, 0, 1, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 1, 1, 1, 1, 1 },
{ 0, 1, 1, 1, 0 },
{ 0, 0, 1, 0, 0 }
}
image av = img.Convolution(kernel)
av.ShowImage()