From 179b27ad8caf1a922c010986152332854a757c94 Mon Sep 17 00:00:00 2001 From: KIU Shueng Chuan Date: Tue, 30 Mar 2021 09:11:43 +0800 Subject: [PATCH 1/3] image_testing.py: swap red and blue channels --- pyqtgraph/tests/image_testing.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pyqtgraph/tests/image_testing.py b/pyqtgraph/tests/image_testing.py index bfb8dc0f..e64df55e 100644 --- a/pyqtgraph/tests/image_testing.py +++ b/pyqtgraph/tests/image_testing.py @@ -145,8 +145,13 @@ def assertImageApproved(image, standardFile, message=None, **kwargs): image = fn.imageToArray(qimg, copy=False, transpose=False) - # transpose BGRA to RGBA - image = image[..., [2, 1, 0, 3]] + # the standard images seem to have their Red and Blue swapped + if sys.byteorder == 'little': + # transpose B,G,R,A to R,G,B,A + image = image[..., [2, 1, 0, 3]] + else: + # transpose A,R,G,B to A,B,G,R + image = image[..., [0, 3, 2, 1]] if message is None: code = inspect.currentframe().f_back.f_code From 17e2f0f5f2f1c03c786ac48e2f609483b0d307c3 Mon Sep 17 00:00:00 2001 From: KIU Shueng Chuan Date: Tue, 30 Mar 2021 08:57:33 +0800 Subject: [PATCH 2/3] fix makeARGB() endian ordering --- pyqtgraph/functions.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/pyqtgraph/functions.py b/pyqtgraph/functions.py index 0dc0183f..09f8d921 100644 --- a/pyqtgraph/functions.py +++ b/pyqtgraph/functions.py @@ -1242,9 +1242,11 @@ def makeARGB(data, lut=None, levels=None, scale=None, useRGBA=False, output=None # decide channel order if useRGBA: - order = [0,1,2,3] # array comes out RGBA + dst_order = [0, 1, 2, 3] # R,G,B,A + elif sys.byteorder == 'little': + dst_order = [2, 1, 0, 3] # B,G,R,A (ARGB32 little endian) else: - order = [2,1,0,3] # for some reason, the colors line up as BGR in the final image. + dst_order = [1, 2, 3, 0] # A,R,G,B (ARGB32 big endian) # copy data into image array fastpath = try_fastpath_argb(xp, data, imgData, useRGBA) @@ -1256,13 +1258,13 @@ def makeARGB(data, lut=None, levels=None, scale=None, useRGBA=False, output=None # imgData[..., :3] = data[..., xp.newaxis] # ..but it turns out this is faster: for i in range(3): - imgData[..., i] = data + imgData[..., dst_order[i]] = data elif data.shape[2] == 1: for i in range(3): - imgData[..., i] = data[..., 0] + imgData[..., dst_order[i]] = data[..., 0] else: for i in range(0, data.shape[2]): - imgData[..., i] = data[..., order[i]] + imgData[..., dst_order[i]] = data[..., i] profile('reorder channels') @@ -1272,16 +1274,16 @@ def makeARGB(data, lut=None, levels=None, scale=None, useRGBA=False, output=None else: alpha = False if not fastpath: # fastpath has already filled it in - imgData[..., 3] = 255 + imgData[..., dst_order[3]] = 255 # apply nan mask through alpha channel if nanMask is not None: alpha = True # Workaround for https://github.com/cupy/cupy/issues/4693 if xp == cp: - imgData[nanMask, :, 3] = 0 + imgData[nanMask, :, dst_order[3]] = 0 else: - imgData[nanMask, 3] = 0 + imgData[nanMask, dst_order[3]] = 0 profile('alpha channel') return imgData, alpha From 02a48afc60d99b242287b63b1fd7d451b7857bf5 Mon Sep 17 00:00:00 2001 From: KIU Shueng Chuan Date: Wed, 31 Mar 2021 10:16:42 +0800 Subject: [PATCH 3/3] test_makeARGB() : normalize to B,G,R,A --- pyqtgraph/tests/test_functions.py | 55 ++++++++++++++++++------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/pyqtgraph/tests/test_functions.py b/pyqtgraph/tests/test_functions.py index ea35cc28..3092a8dc 100644 --- a/pyqtgraph/tests/test_functions.py +++ b/pyqtgraph/tests/test_functions.py @@ -147,6 +147,17 @@ def test_rescaleData(): assert np.allclose(s1, s2) +def makeARGB(*args, **kwds): + img, alpha = pg.makeARGB(*args, **kwds) + if kwds.get('useRGBA'): # endian independent + out = img + elif sys.byteorder == 'little': # little-endian ARGB32 to B,G,R,A + out = img + else: # big-endian ARGB32 to B,G,R,A + out = img[..., [3, 2, 1, 0]] + return out, alpha + + def test_makeARGB(): # Many parameters to test here: # * data dtype (ubyte, uint16, float, others) @@ -193,55 +204,55 @@ def test_makeARGB(): # uint8 data tests im1 = np.arange(256).astype('ubyte').reshape(256, 1) - im2, alpha = pg.makeARGB(im1, levels=(0, 255)) + im2, alpha = makeARGB(im1, levels=(0, 255)) checkImage(im2, im1, alpha, False) - im3, alpha = pg.makeARGB(im1, levels=(0.0, 255.0)) + im3, alpha = makeARGB(im1, levels=(0.0, 255.0)) checkImage(im3, im1, alpha, False) - im4, alpha = pg.makeARGB(im1, levels=(255, 0)) + im4, alpha = makeARGB(im1, levels=(255, 0)) checkImage(im4, 255-im1, alpha, False) - im5, alpha = pg.makeARGB(np.concatenate([im1]*3, axis=1), levels=[(0, 255), (0.0, 255.0), (255, 0)]) + im5, alpha = makeARGB(np.concatenate([im1]*3, axis=1), levels=[(0, 255), (0.0, 255.0), (255, 0)]) checkImage(im5, np.concatenate([im1, im1, 255-im1], axis=1), alpha, False) - im2, alpha = pg.makeARGB(im1, levels=(128,383)) + im2, alpha = makeARGB(im1, levels=(128,383)) checkImage(im2[:128], 0, alpha, False) checkImage(im2[128:], im1[:128], alpha, False) # uint8 data + uint8 LUT lut = np.arange(256)[::-1].astype(np.uint8) - im2, alpha = pg.makeARGB(im1, lut=lut) + im2, alpha = makeARGB(im1, lut=lut) checkImage(im2, lut, alpha, False) # lut larger than maxint lut = np.arange(511).astype(np.uint8) - im2, alpha = pg.makeARGB(im1, lut=lut) + im2, alpha = makeARGB(im1, lut=lut) checkImage(im2, lut[::2], alpha, False) # lut smaller than maxint lut = np.arange(128).astype(np.uint8) - im2, alpha = pg.makeARGB(im1, lut=lut) + im2, alpha = makeARGB(im1, lut=lut) checkImage(im2, np.linspace(0, 127.5, 256, dtype='ubyte'), alpha, False) # lut + levels lut = np.arange(256)[::-1].astype(np.uint8) - im2, alpha = pg.makeARGB(im1, lut=lut, levels=[-128, 384]) + im2, alpha = makeARGB(im1, lut=lut, levels=[-128, 384]) checkImage(im2, np.linspace(191.5, 64.5, 256, dtype='ubyte'), alpha, False) - im2, alpha = pg.makeARGB(im1, lut=lut, levels=[64, 192]) + im2, alpha = makeARGB(im1, lut=lut, levels=[64, 192]) checkImage(im2, np.clip(np.linspace(384.5, -127.5, 256), 0, 255).astype('ubyte'), alpha, False) # uint8 data + uint16 LUT lut = np.arange(4096)[::-1].astype(np.uint16) // 16 - im2, alpha = pg.makeARGB(im1, lut=lut) + im2, alpha = makeARGB(im1, lut=lut) checkImage(im2, np.arange(256)[::-1].astype('ubyte'), alpha, False) # uint8 data + float LUT lut = np.linspace(10., 137., 256) - im2, alpha = pg.makeARGB(im1, lut=lut) + im2, alpha = makeARGB(im1, lut=lut) checkImage(im2, lut.astype('ubyte'), alpha, False) # uint8 data + 2D LUT @@ -249,39 +260,39 @@ def test_makeARGB(): lut[:,0] = np.arange(256) lut[:,1] = np.arange(256)[::-1] lut[:,2] = 7 - im2, alpha = pg.makeARGB(im1, lut=lut) + im2, alpha = makeARGB(im1, lut=lut) checkImage(im2, lut[:,None,::-1], alpha, False) # check useRGBA - im2, alpha = pg.makeARGB(im1, lut=lut, useRGBA=True) + im2, alpha = makeARGB(im1, lut=lut, useRGBA=True) checkImage(im2, lut[:,None,:], alpha, False) # uint16 data tests im1 = np.arange(0, 2**16, 256).astype('uint16')[:, None] - im2, alpha = pg.makeARGB(im1, levels=(512, 2**16)) + im2, alpha = makeARGB(im1, levels=(512, 2**16)) checkImage(im2, np.clip(np.linspace(-2, 253, 256), 0, 255).astype('ubyte'), alpha, False) lut = (np.arange(512, 2**16)[::-1] // 256).astype('ubyte') - im2, alpha = pg.makeARGB(im1, lut=lut, levels=(512, 2**16-256)) + im2, alpha = makeARGB(im1, lut=lut, levels=(512, 2**16-256)) checkImage(im2, np.clip(np.linspace(257, 2, 256), 0, 255).astype('ubyte'), alpha, False) lut = np.zeros(2**16, dtype='ubyte') lut[1000:1256] = np.arange(256) lut[1256:] = 255 im1 = np.arange(1000, 1256).astype('uint16')[:, None] - im2, alpha = pg.makeARGB(im1, lut=lut) + im2, alpha = makeARGB(im1, lut=lut) checkImage(im2, np.arange(256).astype('ubyte'), alpha, False) # float data tests im1 = np.linspace(1.0, 17.0, 256)[:, None] - im2, alpha = pg.makeARGB(im1, levels=(5.0, 13.0)) + im2, alpha = makeARGB(im1, levels=(5.0, 13.0)) checkImage(im2, np.clip(np.linspace(-128, 383, 256), 0, 255).astype('ubyte'), alpha, False) lut = (np.arange(1280)[::-1] // 10).astype('ubyte') - im2, alpha = pg.makeARGB(im1, lut=lut, levels=(1, 17)) + im2, alpha = makeARGB(im1, lut=lut, levels=(1, 17)) checkImage(im2, np.linspace(127.5, 0, 256).astype('ubyte'), alpha, False) # nans in image @@ -289,7 +300,7 @@ def test_makeARGB(): # 2d input image, one pixel is nan im1 = np.ones((10, 12)) im1[3, 5] = np.nan - im2, alpha = pg.makeARGB(im1, levels=(0, 1)) + im2, alpha = makeARGB(im1, levels=(0, 1)) assert alpha assert im2[3, 5, 3] == 0 # nan pixel is transparent assert im2[0, 0, 3] == 255 # doesn't affect other pixels @@ -297,7 +308,7 @@ def test_makeARGB(): # 3d RGB input image, any color channel of a pixel is nan im1 = np.ones((10, 12, 3)) im1[3, 5, 1] = np.nan - im2, alpha = pg.makeARGB(im1, levels=(0, 1)) + im2, alpha = makeARGB(im1, levels=(0, 1)) assert alpha assert im2[3, 5, 3] == 0 # nan pixel is transparent assert im2[0, 0, 3] == 255 # doesn't affect other pixels @@ -305,7 +316,7 @@ def test_makeARGB(): # 3d RGBA input image, any color channel of a pixel is nan im1 = np.ones((10, 12, 4)) im1[3, 5, 1] = np.nan - im2, alpha = pg.makeARGB(im1, levels=(0, 1), useRGBA=True) + im2, alpha = makeARGB(im1, levels=(0, 1), useRGBA=True) assert alpha assert im2[3, 5, 3] == 0 # nan pixel is transparent