anomaly while exporting openGL texture using openCV

Question:

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 500×500 texture and works fine:
good result

But when I try 500×600 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

Asked By: 김기영

||

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 200×100 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 4×2 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.

Answered By: Rabbid76
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.