如何将numpy数组中两个数字的位向右滚动?

xiozqbni  于 2023-05-17  发布在  其他
关注(0)|答案(1)|浏览(130)

我写了一个脚本来转移bmp图像台达电子HMI(工业自动化触摸面板)。这里的主要情况是HMI使用了一种有点奇怪的像素格式。它看起来像16位RGB555,但每个像素的两个字节的颜色的所有位都向右移动,在BRG和绿色中使用4位而不是5位。
我写了一些代码,它似乎工作正常,图像显示正确,但它需要大量的时间来转换600x250像素的图像(约1.5秒)。
最后,我有一个两个数字的numpy数组,我需要向右滚动,但就像一个数字,而不是每个单独的。

def img_to_hex(img):
    # swapping green channel with red
    green_ch = img[:, :, 1].copy()
    red_ch = img[:, :, 2].copy()
    img[:, :, 1] = red_ch
    img[:, :, 2] = green_ch

    # decoding to 555 color
    im555 = np.vstack(cv2.cvtColor(img, cv2.COLOR_RGB2BGR555))

    for ind, i in enumerate(im555):
        # changing bytes order for every pixel
        bits = ''
        im555[ind][0], im555[ind][1] = im555[ind][1], im555[ind][0]

        # converting int to bin
        for num in im555[ind]:
            bits = bits + bin(num)[2:].rjust(8, '0')

        # rotating string
        rot_str = rotate_string(bits, 2)

        # converting bits to int
        im555[ind][0], im555[ind][1] = int(rot_str[:8], 2), int(rot_str[8:], 2)

    img_bytes = im555.tobytes()

    return img_bytes.hex()

def rotate_string(input, d):
    # slice string in two parts to right
    rfirst = input[0: len(input) - d]
    rsecond = input[len(input) - d:]
    return rsecond + rfirst

运行此代码的示例结果:

[255 127] <class 'numpy.ndarray'> shape - (2,)
0111111111111111 - original - 0xFF 0x7F
1101111111111111 - rolled - 0xDF 0xFF
[223 255] <class 'numpy.ndarray'> shape - (2,)

[170  45] <class 'numpy.ndarray'> shape - (2,)
0010110110101010 - original - 0xAA 0x2D 
1000101101101010 - rolled - 0x8B 0x6A 
[139 106] <class 'numpy.ndarray'> shape - (2,)

我也试着用numpy来做这个:

for ind, i in enumerate(im555):
        im555[ind][0], im555[ind][1] = im555[ind][1], im555[ind][0]
        im555[ind] = np.packbits((np.roll((np.unpackbits(im555[ind])), 2)))

但是转换600x250pix图像大约需要12秒。
那么我如何才能快速做到这一点呢?

zpgglvta

zpgglvta1#

人们可能认为numpy非常快,但在代码中有三个离散的操作-即unpack,roll(ROR),pack
下面是一个可能有用的ROR的纯Python实现(还包括定时装置):

from random import randint
from time import perf_counter

BITS = 32

values = [randint(0, 2**BITS-1) for _ in range(600*250)]

def ror(n, shift, bits=BITS):
    assert 0 <= n < 2**bits and shift > 0, 'Invalid parameters'
    return n >> shift | (n & 2**shift-1) << bits - shift

start = perf_counter()

for v in values:
    ror(v, 2)

end = perf_counter()

print(f'Duration={end-start:.4f}s')

输出:

Duration=0.0322s

相关问题