Pillow
Pillow copied to clipboard
Bilinear resize is incorrect
What did you do?
import numpy as np
from PIL import Image
import cv2
def pil_linear(im, shape_wh):
im = Image.fromarray(im.astype("float32"), mode="F")
return np.array(im.resize(shape_wh, Image.BILINEAR))
def cv_linear(im, shape_wh):
return cv2.resize(im, shape_wh, interpolation=cv2.INTER_LINEAR)
np.set_printoptions(linewidth=200)
input = np.arange(100).reshape(10, 10).astype("float32")
shape1 = (5, 5)
output_1 = pil_linear(input, shape1)
output_2 = cv_linear(input, shape1)
print("INPUT:\n", input)
print("Pillow: \n", output_1)
print("OpenCV: \n", output_2)
What did you expect to happen?
I expect Pillow to produce the same results as output_2
What actually happened?
The output is
INPUT:
[[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
[10. 11. 12. 13. 14. 15. 16. 17. 18. 19.]
[20. 21. 22. 23. 24. 25. 26. 27. 28. 29.]
[30. 31. 32. 33. 34. 35. 36. 37. 38. 39.]
[40. 41. 42. 43. 44. 45. 46. 47. 48. 49.]
[50. 51. 52. 53. 54. 55. 56. 57. 58. 59.]
[60. 61. 62. 63. 64. 65. 66. 67. 68. 69.]
[70. 71. 72. 73. 74. 75. 76. 77. 78. 79.]
[80. 81. 82. 83. 84. 85. 86. 87. 88. 89.]
[90. 91. 92. 93. 94. 95. 96. 97. 98. 99.]]
Pillow:
[[ 7.857143 9.642858 11.642858 13.642858 15.428572]
[25.714285 27.5 29.5 31.5 33.285713]
[45.714287 47.5 49.5 51.5 53.285713]
[65.71429 67.5 69.5 71.5 73.28571 ]
[83.57143 85.35714 87.35714 89.35714 91.14285 ]]
OpenCV:
[[ 5.5 7.5 9.5 11.5 13.5]
[25.5 27.5 29.5 31.5 33.5]
[45.5 47.5 49.5 51.5 53.5]
[65.5 67.5 69.5 71.5 73.5]
[85.5 87.5 89.5 91.5 93.5]]
I understand that Pillow does not necessarily produce the same outputs as OpenCV, and there are a few issues about such inconsistency - some of them are OpenCV's fault.
However, in this particular example, I think Pillow is incorrect at the boundaries. I expect the input pixels [[0, 1], [10, 11]] to become 5.5 after downsampling.
What are your OS, Python and Pillow versions?
- OS: Linux
- Python: 3.8
- Pillow: 7.0.0
Any comments on this issue may also apply to #4445
what would be the possible reason for these kind of phenomenon?
actually I also tried to use PIL, matlab and cv2 to do BICUBIC downsampling and they all shows different result.
but the math formula is fixed??? how come we try to implement same math formula but end up with different outputs???
and for those people who work on image restoration area...i believe they might suffer from this issue...
I am confused...

Regarding the first post, Pillow performs two passes over the image - horizontal, and then vertical.
https://github.com/python-pillow/Pillow/blob/b4bf2885f365b23e16772380173e971f89b208bf/src/libImaging/Resample.c#L655
So why is the first value 7.857143?
The coefficients generated by our bilinear function are 0.428571, 0.428571 and 0.142857.
Applying that horizontally,
0 * 0.428571 + 1 * 0.428571 + 2 * 0.142857 = 0.714285
10 * 0.428571 + 11 * 0.428571 + 12 * 0.142857 = 10.714275
20 * 0.428571 + 21 * 0.428571 + 22 * 0.142857 = 20.714265
and then vertically,
0.714285 * 0.428571 + 10.714275 * 0.428571 + 20.714265 * 0.142857 = 7.85712714287
You suggest that Pillow should only consider 0, 1, 10 and 11 to get the first pixel value. Instead, Pillow is also considering 2, 12, 20, 21 and 22. That is different to OpenCV, but I see no reason why it should be thought of as incorrect. 0, 1, 10 and 11 are still all considered equally.
It is hard to discuss the second problem here because there isn't an image or code provided.
We don't aim to mimic OpenCV. If you have an image and code, we can talk about how Pillow calculates the final value. If you have a reference for how bicubic downsampling should work, we can talk about how Pillow differs from that.