Python中在2D数组上计算滑动窗口内众数的最有效方法是什么?

3
我有一张RGBA图像需要放大,同时保持平滑。但是问题在于我需要保持颜色完全不变(背景:我正在调整一个地图的大小,其中各个省份的颜色已经编码),所以我不能仅使用双三次插值进行调整大小,因为这也会插值像素颜色并使其平滑。因此,为了获得平滑的边缘,我希望使用最近邻居法进行放大(给我阶梯状图案),然后通过用目标图像中半径内出现最多的像素颜色替换每个像素来修整边缘,如下所示:
from PIL import Image, ImageFilter
amount=3
image=Image.open(<file>)
image=image.filter(ImageFilter.ModeFilter(amount))

这很快就完成了,但不起作用,因为PIL的ImageFilters在每个通道上单独操作。我试图采用numpy数组并在循环中执行以下操作:
dest[x,y]=Counter([tuple(e) for e in reshape(source[max(x-r,0):x+r+1,max(y-r,0):y+r+1],(-1,4))]).most_common()[0][0]

请注意,这里的目标(dest)和源(source)都是形状为XxYx4的数组,因此需要进行必要的重塑和转换为元组。
理论上来说,这种方法可以奏效,但对于我正在处理的8200万像素图像,需要12小时才能完成。 我推断这主要是由于强制类型转换和重塑造成的不必要开销。
在Python中如何适当地做到这一点呢?
我已经准备好放弃并编写一个C++模块来完成这个任务了。任何能让我远离这条路的建议都将不胜感激!

你见过这个吗?我之前为了类似的图像处理任务不得不多次使用内联C++,如果你正在处理8200万像素,那么这听起来就是一项非常适合使用C++进行重型计算的工作。PerformancePython - Ancallan
1
通常情况下,当我需要加速numpy数组的操作时,我要么尝试找到一种聪明的方法让numpy处理所有工作,要么使用Python迭代器。我很难理解你第二个代码片段中发生了什么。你能提供一个更小的数组的简单示例吗? - user545424
@Ancallan 那个链接真是大开眼界。我写了一些 C 代码并将其内联,实现了 x500 的加速。如果你的评论是一个解决方案,我会接受它的。但仍然存在一个问题,我必须依赖人们拥有 scipy 和编译器的访问权限,但我想我可以接受这一点! - megawidget
2个回答

1

如果您关心图像中的一组固定颜色,则“调色板”图像模式可能更合适(至少,如果您的地图中没有超过256种颜色)。

我建议先将图像转换为“P”模式(因为我不太熟悉PIL,所以不确定这有多容易。也许您需要首先明确构建调色板?),然后应用模式过滤器。

我想到的另一个解决方案是,在放大时简单地使用双三次插值,然后使用从原始图像派生的调色板将其转换为调色板图像。这可能会产生比您当前方法更好的结果(并且更容易实现)。


唉,我有超过2000种颜色。 不然的话,这个解决方案本来很棒。 - megawidget

-1

EPX在图像缩放中介绍不了新的颜色。2x倍缩放会这样做:

  A    --\ 1 2
C P B  --/ 3 4
  D 

IF C==A => 1=A
IF A==B => 2=B
...

该文档中还描述了3倍缩放。
除此之外,我同意“直接使用C”--这取决于你知道什么。 有人使用过np_inline吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接