anomaly while exporting openGL texture using openCV

Viewed 134

For debugging purpose I decided to write texture exporting function:

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)

Tested with 500x500 texture and works fine:
good result

But when I try 500x600 thing goes strange: bad result

I have to reshape it to get desired image:

    # ...
    im = im.reshape((600, 500, 3)) # added line
    im = np.flip(im, axis=0)
    cv2.imwrite(file_name, im)

Which then results in:
fixed result

Recently I've asked question glTexImage2D data not filled as expected so I tried gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1), but didnt found it effecting anything. Reshaping doesn't make sense. Without reshaping, I should simply get 90 degree rotated image. What am I not understanding?



ADDITION:
After reading the comment, tried to summarize my understanding. Can you(someone) verify my conclusion?

my understanding

1 Answers

reshape is not the same as transpose. reshape does not change the axis (and thus not rotate) but it changes the shape (width and height) of the array.

e.g.:

a = numpy.array([[1, 2, 3, 4],
                 [5, 6, 7, 8]])
ar = a.reshape((4, 2))
print(ar)

reshape:

[[1 2]
 [3 4]
 [5 6]
 [7 8]]

transpose:

at = a.transpose((1, 0))
print(at)
[[1 5]
 [2 6]
 [3 7]
 [4 8]]

glGetTexImage returns an array with the shape (width, height, channels). This means the shape of an RGB 200x100 image is (200, 100, 3). You can verify this with print(im.shape).

However the 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]])

is not (4, 2) but (2, 4).

The shape of an array that represents a RGB 4x2 image

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)]])

is (2, 4, 3).

PyOpenGL and NumPy (cv2) interpret the shape differently. Therefore you must change the shape and reshape the array:

im = im.reshape((im.shape[1], im.shape[0], im.shape[2]))

Summarize: There is nothing complicated about that. PyOpenGL returns shape information in the form (w, h, c), but NumPy expects (h, w, c). The pixels of the image are stored linearly. The order does not need to be changed, but how they are interpreted must be changed.

Related