使用 openCV 导出 openGL 纹理时出现异常
anomaly while exporting openGL texture using openCV
出于调试目的,我决定编写纹理导出函数:
def image_export(self, file_name: str):
im_format = file_name.rsplit('.')[-1]
if im_format in ('jpg',):
iformat = gl.GL_BGR
elif im_format in ('png',):
iformat = gl.GL_BGRA
else:
raise NotImplementedError
with self: # binding texture
# gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1)
im = (gl.glGetTexImage(gl.GL_TEXTURE_2D, 0, iformat, gl.GL_FLOAT) * 255).astype('uint8')
im = np.flip(im, axis=0)
cv2.imwrite(file_name, im)
使用 500x500 纹理进行测试并且工作正常:
但是当我尝试 500x600 时,事情变得很奇怪:
我必须重塑它以获得所需的图像:
# ...
im = im.reshape((600, 500, 3)) # added line
im = np.flip(im, axis=0)
cv2.imwrite(file_name, im)
然后结果是:
最近我问了一个问题
所以我尝试了 gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1)
,但没有发现它有任何影响。
重塑没有意义。如果不重塑,我应该简单地获得 90 度旋转的图像。我有什么不明白的?
添加:
看完评论,试着总结一下我的理解。你(某人)能证实我的结论吗?
reshape
is not the same as transpose
。 reshape
不会改变轴(因此不会旋转)但会改变数组的形状(宽度和高度)。
例如:
a = numpy.array([[1, 2, 3, 4],
[5, 6, 7, 8]])
ar = a.reshape((4, 2))
print(ar)
重塑:
[[1 2]
[3 4]
[5 6]
[7 8]]
转置:
at = a.transpose((1, 0))
print(at)
[[1 5]
[2 6]
[3 7]
[4 8]]
glGetTexImage
returns 具有形状的数组 (width, height, 频道)。这意味着 RGB 200x100 图像的形状是 (200, 100, 3)。您可以使用 print(im.shape)
.
来验证这一点
然而 numpy.ndarray.shape
is specified in row major order (rows, columns). This means the shape of the numpy.array
a = np.array([[1, 2, 3, 4],
[5, 6, 7, 8]])
不是 (4, 2) 而是 (2, 4).
表示 RGB 4x2 图像的数组的形状
a = np.array(
[[(r1, g1, b1), (r2, g2, b2), (r3, g3, b3), (r4, g4, b4)],
[(r5, g5, b5), (r6, g6, b6), (r7, g7, b7), (r8, g8, b8)]])
是 (2, 4, 3).
PyOpenGL 和 NumPy (cv2) 对形状的解释不同。因此,您必须更改形状和 reshape
数组:
im = im.reshape((im.shape[1], im.shape[0], im.shape[2]))
总结:没有什么复杂的。 PyOpenGL returns 形式的形状信息 (w, h, c),但 NumPy 需要 (h, w, c)。图像的像素是线性存储的。不需要更改顺序,但必须更改它们的解释方式。
出于调试目的,我决定编写纹理导出函数:
def image_export(self, file_name: str):
im_format = file_name.rsplit('.')[-1]
if im_format in ('jpg',):
iformat = gl.GL_BGR
elif im_format in ('png',):
iformat = gl.GL_BGRA
else:
raise NotImplementedError
with self: # binding texture
# gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1)
im = (gl.glGetTexImage(gl.GL_TEXTURE_2D, 0, iformat, gl.GL_FLOAT) * 255).astype('uint8')
im = np.flip(im, axis=0)
cv2.imwrite(file_name, im)
使用 500x500 纹理进行测试并且工作正常:
但是当我尝试 500x600 时,事情变得很奇怪:
我必须重塑它以获得所需的图像:
# ...
im = im.reshape((600, 500, 3)) # added line
im = np.flip(im, axis=0)
cv2.imwrite(file_name, im)
然后结果是:
最近我问了一个问题gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1)
,但没有发现它有任何影响。
重塑没有意义。如果不重塑,我应该简单地获得 90 度旋转的图像。我有什么不明白的?
添加:
看完评论,试着总结一下我的理解。你(某人)能证实我的结论吗?
reshape
is not the same as transpose
。 reshape
不会改变轴(因此不会旋转)但会改变数组的形状(宽度和高度)。
例如:
a = numpy.array([[1, 2, 3, 4],
[5, 6, 7, 8]])
ar = a.reshape((4, 2))
print(ar)
重塑:
[[1 2] [3 4] [5 6] [7 8]]
转置:
at = a.transpose((1, 0))
print(at)
[[1 5] [2 6] [3 7] [4 8]]
glGetTexImage
returns 具有形状的数组 (width, height, 频道)。这意味着 RGB 200x100 图像的形状是 (200, 100, 3)。您可以使用 print(im.shape)
.
然而 numpy.ndarray.shape
is specified in row major order (rows, columns). This means the shape of the numpy.array
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
不是 (4, 2) 而是 (2, 4).
表示 RGB 4x2 图像的数组的形状
a = np.array(
[[(r1, g1, b1), (r2, g2, b2), (r3, g3, b3), (r4, g4, b4)],
[(r5, g5, b5), (r6, g6, b6), (r7, g7, b7), (r8, g8, b8)]])
是 (2, 4, 3).
PyOpenGL 和 NumPy (cv2) 对形状的解释不同。因此,您必须更改形状和 reshape
数组:
im = im.reshape((im.shape[1], im.shape[0], im.shape[2]))
总结:没有什么复杂的。 PyOpenGL returns 形式的形状信息 (w, h, c),但 NumPy 需要 (h, w, c)。图像的像素是线性存储的。不需要更改顺序,但必须更改它们的解释方式。