哪种插值方法最适合调整图像大小?

60

我有一个numpy数组,希望使用opencv进行调整大小。它的值范围从0到255。如果我选择使用cv2.INTER_CUBIC,可能会得到超出此范围的值。这是不可取的,因为调整大小后的数组仍应表示一张图像。

一种解决方法是将结果剪切到[0, 255]范围内。另一种方法是使用不同的插值方法。

据我所知,使用INTER_AREA对于缩小图像是有效的,但对于放大图像,则类似于最近邻插值,对于我的目的来说不太理想。

我应该使用INTER_CUBIC(并剪切),INTER_AREA还是INTER_LINEAR?

使用INTER_CUBIC超出范围的值的示例:

a = np.array( [ 0, 10, 20, 0, 5, 2, 255, 0, 255 ] ).reshape( ( 3, 3 ) )
[[  0  10  20]
 [  0   5   2]
 [255   0 255]]

b = cv2.resize( a.astype('float'), ( 4, 4 ), interpolation = cv2.INTER_CUBIC )
[[   0.            5.42489886   15.43670964   21.29199219]
 [ -28.01513672   -2.46422291    1.62949324  -19.30908203]
 [  91.88964844   25.07939219   24.75106835   91.19140625]
 [ 273.30322266   68.20603609   68.13853455  273.15966797]]

编辑:正如berak指出的那样,将类型从int64转换为float允许使用原始范围外的值。cv2.resize()函数不能使用默认的'int64'类型。但是,转换为'uint8'将自动使值饱和到[0..255]。

另外,正如SaulloCastro指出的那样,另一个相关的答案展示了scipy的插值方法,并且默认方法是立方插值(带饱和度)。


你说得对,确实是这样。 然而,我担心由于遇到了负值,我可能在误用三次插值法。 同时请注意,输入数组“a”仅为3x3,这对于INTER_CUBIC的4x4补丁来说太小了。但是这种现象也会出现在更大的图像中。 - Roee E
1
在您的上下文中,“最佳”是什么意思?由于您没有其他信息,只有由新子像素表示的块的平均值,因此您似乎心中已经有一个关于它们应该如何看起来的模型。 - Bort
1
那是一个很好的问题。因为我想将图像调整到更大的尺寸,所以我希望使用一种最小化伪影和/或混叠的插值方法。然而,我并不完全确定在调整图像大小时应该寻找什么最佳实践或者我应该寻找什么。我猜测不同的插值方法在不同方面都是“最佳的”,这也是我的问题的一部分。 - Roee E
在ImageMagick中,更灵活的插值方法可以实现更高质量的结果,从而减轻伪影和增强清晰度等问题。其中一些方法是在线性色彩空间中完成的。请参见https://imagemagick.org/Usage/filter/ 和 https://imagemagick.org/Usage/filter/nicolas/。 - fmw42
双三次插值用于放大,双线性插值用于缩小(https://hammadiqbal.com/tutorial/the-best-method-of-image-reduction-in-photoshop/) - rinogo
显示剩余4条评论
4个回答

75
如果您正在 放大 图像,建议使用 INTER_LINEARINTER_CUBIC 插值方式。 如果您正在 缩小 图像,建议使用 INTER_AREA 插值方式。
立方插值计算复杂度较高,因此比线性插值慢。但生成的图像质量更高。

4
INTER_AREA插值方法在图像缩小时如何工作? - seralouk
32
你有支持你主张的任何证据吗? - jdhao
相关阅读:https://hammadiqbal.com/tutorial/the-best-method-of-image-reduction-in-photoshop/ - rinogo
1
另外,https://chadrick-kwag.net/cv2-resize-interpolation-methods/。 - rinogo
6
根据OpenCV的文档所述,要缩小图像时,最好使用INTER_AREA插值方法,而要放大图像时,则通常使用INTER_CUBIC(较慢)或INTER_LINEAR(速度更快但效果还可以)插值方法。 - Salvatore
1
@seralouk 插值方法的完整列表和描述也可以在这里找到:https://docs.opencv.org/3.4/da/d54/group__imgproc__transform.html#ga5bb5a1fea74ea38e1a5445ca803ff121。 - Salvatore

21
为了解决这个问题,您应该找出给定图片的新尺寸,其中可以进行插值。然后将插值采样图像复制到目标图像中,如下所示:

为了克服这个问题,你需要找出给定图片的新尺寸,可以在新尺寸上进行插值处理。然后将插值采样图像复制到目标图像中,步骤如下:

# create target image and copy sample image into it
(wt, ht) = imgSize # target image size
(h, w) = img.shape # given image size
fx = w / wt
fy = h / ht
f = max(fx, fy)
newSize = (max(min(wt, int(w / f)), 1),
           max(min(ht, int(h / f)), 1))  # scale according to f (result at least 1 and at most wt or ht)
img = cv2.resize(img, newSize, interpolation=cv2.INTER_CUBIC) #INTER_CUBIC interpolation
target = np.ones([ht, wt]) * 255  # shape=(64,800)
target[0:newSize[1], 0:newSize[0]] = img

一些可能的OpenCV插值方法包括:

  • INTER_NEAREST - 最近邻插值
  • INTER_LINEAR - 双线性插值(默认使用)
  • INTER_AREA - 使用像素面积关系进行重采样。这可能是图像降采样的首选方法,因为它可以得到无莫尔纹的结果。但当图像被放大时,它与INTER_NEAREST方法类似。
  • INTER_CUBIC - 在4×4像素邻域上进行双三次插值
  • INTER_LANCZOS4 - 在8×8像素邻域上进行Lanczos插值

此处查看每种插值方法的结果。


5

我认为你应该从INTER_LINEAR开始,它是resize()函数的默认选项。它将足够好的视觉效果和足够好的时间性能结合在一起(尽管它不像INTER_NEAREST那样快)。并且它不会创建那些超出范围的值。


5

我的回答基于测试结果。最终支持 @shivam 的答案。我测试了这些插值方法,包括组合、收缩和扩大。并且在放大后,我使用原始图像计算了PSNR。

[cv2.INTER_AREA,
cv2.INTER_BITS,
cv2.INTER_BITS2,
cv2.INTER_CUBIC,
cv2.INTER_LANCZOS4,
cv2.INTER_LINEAR,
cv2.INTER_LINEAR_EXACT,
cv2.INTER_NEAREST]

shirking=0.25
enlarge=4

针对165张不同形状的图片进行了测试。我选择了最高和次高的PSNR值并计算了数量。

对于最高值,插值的次数如下图所示。 maximum psnr

从这个测试中,最高的PSNR值由AREALANCZOS4的组合给出,对于141/204个图像,它们的PSNR值最高。

我还想包含第二个最大值。因此,这里只给出第二最大值结果的结果。 2nd max psnr

这里的AREACUBIC给出了第二好的结果。利用AREA+CUBIC, 19/204获得了最高的PSNR值,而利用AREA+CUBIC,158/347获得了第二高的PSNR值。

这些结论很模糊,所以我打开了使用CUBIC给出最高PSNR值的文件。结果发现,具有大量纹理和抽象的图像使用CUBIC会获得最高的PSNR值。

因此,我进一步测试了AREA+CUBICAREA+LANCZOS4。 我得出的结论是,如果您缩小图像的倍数<10,则使用LANCZOS4更好。 它将在少于10倍缩放时为您提供更好的结果,如果图片很大,则比CUBIC更好。

至于我的程序,我将图像缩小了4倍,因此对于我来说,AREA+LANCZOS4效果更好。

脚本和图片: https://github.com/crackaf/triple-recovery/tree/main/tests


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