在下面的代码片段中,传递x和y值会将点放在(y,x)坐标中,而绘图在(x,y)中完成。设置绘图缓冲区的正确方法是什么,以便将像素和绘图放在同一个坐标系中?
from PIL import Image, ImageDraw
def visual_test(x, y):
grid = np.zeros((100, 100, 3), dtype=np.uint8)
grid[:] = [0, 0, 0]
grid[x, y] = [255, 0, 0]
img = Image.fromarray(grid, 'RGB')
draw = ImageDraw.Draw(img)
draw.line((x, y, x, y-5), fill=(255,255,255), width=1)
img.show()
答案 0 :(得分:1)
注意:使用"轴"我指的是图像坐标,而不是NumPy的数组维度。
问题在于对ndarray
维度的解释(" N维数组")或坐标系的定义在那种情况下。
Pillow,很清楚:
Python Imaging Library使用笛卡尔像素坐标系, 左上角有(0,0)。请注意,坐标参考 到隐含的像素角;像素的中心寻址为(0, 0)实际上位于(0.5,0.5)。
坐标通常以2元组(x,y)的形式传递给库。 矩形表示为4元组,左上角 首先给出。例如,一个覆盖所有800x600像素的矩形 图像写为(0,0,800,600)。
这看起来像这样(图像 - >公共领域):
您的代码经过修改后可创建2x2像素图像:
import numpy as np
from PIL import Image # Pillow
w, h, d = 2,2,3
x,y = 0,1
grid = np.zeros((w, h, d), dtype=np.uint8) # NumPyarray for image data
#test = np.zeros(w*h*d, dtype=np.uint8).reshape(w, h, d)
#print(np.array_equal(grid,test)) # => True
# red pixel with NumPy
grid[x, y] = [255, 0, 0]
print(grid[::])
# green pixel with Pillow
img = Image.fromarray(grid, 'RGB')
pixels = img.load()
pixels[x,y] = (0, 255, 0)
# display temporary image file with default application
scale = 100
img.resize((w*scale,h*scale)).show()
显示问题(在(0,1)处绘制像素,绿色:枕头,红色:ndarray):
X和Y确实被交换了:
是因为NumPy还是Pillow?
ndarray
打印为
[[[ 0 0 0]
[255 0 0]]
[[ 0 0 0]
[ 0 0 0]]]
可轻松重新格式化以在视觉上对应于图像像素
[
[ [ 0 0 0] [255 0 0] ]
[ [ 0 0 0] [ 0 0 0] ]
]
表明Pillow正如人们所期望的那样解释数组。
但为什么NumPy ndarray
似乎交换了轴?
让我们进一步分开
[ # grid
[ # grid[0]
[ 0 0 0] #grid[0,0]
[255 0 0] #grid[0,1]
]
[ #grid[1]
[ 0 0 0] #grid[1,0]
[ 0 0 0] #grid[1,1]
]
]
让我们测试一下(-i
一旦脚本完成,Python就会以交互模式运行):
>py -i t.py
[[[ 0 0 0]
[255 0 0]]
[[ 0 0 0]
[ 0 0 0]]]
>>> grid[0,1]
array([255, 0, 0], dtype=uint8)
>>> grid[0]
array([[ 0, 0, 0],
[255, 0, 0]], dtype=uint8)
>>> ^Z
确认了上面假定的指数。
ndarray
的第一个维度如何对应于图像线或Y轴,第二个维度对应于图像列或X轴(第三个维度对应于RGB像素值)。
所以,要匹配"坐标系",要么......
让我们看看:
<强> 1。在写入ndarray
:
# red pixel with NumPy
grid[y, x] = [255, 0, 0]
预计会产生
[[[ 0 0 0]
[ 0 0 0]]
[[255 0 0]
[ 0 0 0]]]
和
当然包装函数可以做到这一点。
2。 Transposing数组suggested by zch无法在三维数组上轻松 ,因为此函数会影响默认情况下所有尺寸:
grid = np.transpose(grid)
print("transposed\n", grid)
print("shape:", grid.shape)
结果
[[[ 0 0]
[255 0]]
[[ 0 0]
[ 0 0]]
[[ 0 0]
[ 0 0]]]
shape: (3, 2, 2)
并且由于指定了Pillow RGB
图像模式,因此抛出了异常:
ValueError: not enough image data
但np.transpose
,axes
还有一个额外的论点:
...根据给定的值对轴进行置换。
我们只想交换0
和1
,而不是2
,所以:
grid = np.transpose(grid, (1,0,2))
还有其他类似的功能,例如
grid = np.swapaxes(grid,0,1)
第3。改变解释?
Pillow&#39; PIL.Image.fromarray
可以用交换轴解释ndarray
吗?除了mode
之外,它没有任何其他参数用于颜色(实际上,请参阅source code)。
使用缓冲区协议从导出阵列接口的对象创建映像内存。 如果obj不连续,则调用tobytes方法并使用frombuffer()。
该功能指出如何拨打PIL.Image.frombuffer()
(source),其中包含更多选项,用于&#34;解码器&#34;。
Array interface? Buffer protocol?这对于现在来说都太低了......
<强> TL; DR 强>
只需交换索引变量(或者)!
<小时/> 进一步阅读: - https://docs.scipy.org/doc/numpy-dev/user/quickstart.html