Python cairo save figure as np array 给出奇怪的结果
Python cairo save figure as np array gives weird results
尝试运行我的例子:
import numpy as np
import cairo
import matplotlib.pyplot as plt
img_size = 28
size = 0.8
color = (255, 0, 0)
thickness = 2
data = np.zeros((img_size, img_size, 3), dtype=np.uint8)
surface = cairo.ImageSurface.create_for_data(
data, cairo.FORMAT_RGB16_565, img_size, img_size
)
cr = cairo.Context(surface)
# fill with solid white
cr.set_source_rgb(1, 1, 1)
cr.paint()
size = img_size * size - thickness
cr.rectangle((img_size - size) / 2, (img_size - size) / 2, size, size)
cr.set_line_width(thickness)
cr.set_source_rgb(*color)
cr.stroke()
surface.write_to_png("shape.png")
plt.imshow(data)
plt.savefig("shape_from_np.png")
shape.png 看起来像:
shape_from_np.png 看起来像:
我在想也许我错过了格式,或者 channels/shape,但是如果我打印出像 data[:,:,0]
这样的红色层,它也会在下半部分显示奇怪的 0 值,我我不确定为什么。
我在文档中找到了 ImageSurface.create_from_png(...)
,所以我使用了您的 'shape.png'
来测试它将用于 PNG 图像的值。
import cairo
surface = cairo.ImageSurface.create_from_png('shape.png')
print('format:', surface.get_format())
print('width :', surface.get_width())
print('height:', surface.get_height())
print('stride:', surface.get_stride())
print('stride/width:', surface.get_stride()/surface.get_width())
这给出了
format: 1
width : 28
height: 28
stride: 112
stride/width: 4.0
我发现 format: 1
表示 cairo.Format.RGB24
并且在文档 cairo.Format 中我发现它需要 32bit
像素,这意味着 4
字节
data = np.zeros((img_size, img_size, 4), dtype=np.uint8)
同样的 4
给了我 stride/width
(stride/28
)
使用这些值我可以创建正确的图像但是 BGR
而不是 RGB
所以它还需要一些改变。
但是 cv2
使用 BGR
图像并且它可以正确保存它而无需更改。
import cv2
cv2.imwrite('cv2.png', data)
import numpy as np
import cairo
import matplotlib.pyplot as plt
img_size = 28
size = 0.8
color = (255, 0, 0)
thickness = 2
data = np.zeros((img_size, img_size, 4), dtype=np.uint8)
surface = cairo.ImageSurface.create_for_data(data, cairo.FORMAT_RGB24, img_size, img_size)
cr = cairo.Context(surface)
# fill with solid white
cr.set_source_rgb(1, 1, 1)
cr.paint()
size = int(img_size * size) - thickness
cr.rectangle((img_size - size) / 2, (img_size - size) / 2, size, size)
cr.set_line_width(thickness)
cr.set_source_rgb(*color)
cr.stroke()
plt.imshow(data)
plt.savefig("shape_from_np.png")
surface.write_to_png("shape.png")
import cv2
cv2.imwrite('cv2.png', data)
文档:ImageSurface, Format
尝试运行我的例子:
import numpy as np
import cairo
import matplotlib.pyplot as plt
img_size = 28
size = 0.8
color = (255, 0, 0)
thickness = 2
data = np.zeros((img_size, img_size, 3), dtype=np.uint8)
surface = cairo.ImageSurface.create_for_data(
data, cairo.FORMAT_RGB16_565, img_size, img_size
)
cr = cairo.Context(surface)
# fill with solid white
cr.set_source_rgb(1, 1, 1)
cr.paint()
size = img_size * size - thickness
cr.rectangle((img_size - size) / 2, (img_size - size) / 2, size, size)
cr.set_line_width(thickness)
cr.set_source_rgb(*color)
cr.stroke()
surface.write_to_png("shape.png")
plt.imshow(data)
plt.savefig("shape_from_np.png")
shape.png 看起来像:
shape_from_np.png 看起来像:
我在想也许我错过了格式,或者 channels/shape,但是如果我打印出像 data[:,:,0]
这样的红色层,它也会在下半部分显示奇怪的 0 值,我我不确定为什么。
我在文档中找到了 ImageSurface.create_from_png(...)
,所以我使用了您的 'shape.png'
来测试它将用于 PNG 图像的值。
import cairo
surface = cairo.ImageSurface.create_from_png('shape.png')
print('format:', surface.get_format())
print('width :', surface.get_width())
print('height:', surface.get_height())
print('stride:', surface.get_stride())
print('stride/width:', surface.get_stride()/surface.get_width())
这给出了
format: 1
width : 28
height: 28
stride: 112
stride/width: 4.0
我发现 format: 1
表示 cairo.Format.RGB24
并且在文档 cairo.Format 中我发现它需要 32bit
像素,这意味着 4
字节
data = np.zeros((img_size, img_size, 4), dtype=np.uint8)
同样的 4
给了我 stride/width
(stride/28
)
使用这些值我可以创建正确的图像但是 BGR
而不是 RGB
所以它还需要一些改变。
但是 cv2
使用 BGR
图像并且它可以正确保存它而无需更改。
import cv2
cv2.imwrite('cv2.png', data)
import numpy as np
import cairo
import matplotlib.pyplot as plt
img_size = 28
size = 0.8
color = (255, 0, 0)
thickness = 2
data = np.zeros((img_size, img_size, 4), dtype=np.uint8)
surface = cairo.ImageSurface.create_for_data(data, cairo.FORMAT_RGB24, img_size, img_size)
cr = cairo.Context(surface)
# fill with solid white
cr.set_source_rgb(1, 1, 1)
cr.paint()
size = int(img_size * size) - thickness
cr.rectangle((img_size - size) / 2, (img_size - size) / 2, size, size)
cr.set_line_width(thickness)
cr.set_source_rgb(*color)
cr.stroke()
plt.imshow(data)
plt.savefig("shape_from_np.png")
surface.write_to_png("shape.png")
import cv2
cv2.imwrite('cv2.png', data)
文档:ImageSurface, Format