[英]4 bit per pixel image from binary file in Python with Numpy and CV2?
假设我想将二进制数据表示为黑白图像,每个像素的灰度值只有 16 个不同的级别,以便每两个相邻像素(纵向)代表一个字节。 我怎样才能做到这一点? 例如,如果我使用以下内容:
import numpy as np
path = r'mybinaryfile.bin'
bin_data = np.fromfile(path, dtype='uint8')
scalar = 20
width = int(1800/scalar)
height = int(1000/scalar)
for jj in range(50):
wid = int(width*height)
img = bin_data[int(jj*wid):int((jj+1)*wid)].reshape(height,width)
final_img = cv2.resize(img, (scalar*width, scalar*height), interpolation = cv2.INTER_NEAREST)
fn = f'tmp/output_{jj}.png'
cv2.imwrite(fn, final_img)
我可以创建一系列代表二进制文件的 PNG 文件,每个 20 x 20 像素块代表一个字节。 但是,这会为灰色 (256) 创建太多唯一值,因此我需要将其减少到更少 (16)。 我如何将每个像素“拆分”为具有 16 个不同灰度级(4 bpp,而不是 8 个)的两个像素?
使用 4 bpp 而不是 8 bpp 应该会使图像文件的数量增加一倍,因为我保持分辨率相同但将我用来表示一个字节的像素数量增加一倍(每字节 2 个像素而不是 1 个像素)。
我了解到你想取一个 8 位数字并将高四位和低四位分开。
这可以通过几个按位运算来完成。
def split_octet(data):
"""
For each 8-bit number in array, split them into two 4-bit numbers"""
split_data = []
for octet in data:
upper = octet >> 4
lower = octet & 0x0f
print(f"8bit:{octet:02x} upper:{upper:01x} and lower:{lower:01x}")
split_data.extend([upper, lower])
return split_data
对于要创建的灰度图像,需要将数据转换为 0 到 255 范围内的值。但是您只想保留 16 个离散值。 这可以通过将 0 到 1 范围内的 4 位值归一化来完成。将值乘以 255 以返回 uint8 值。
def create_square_grayscale(data, data_shape):
# Normalize data from 0 to 1
normalized = np.array(data, np.float64) / 0xf
# fold data to image shape
pixel_array = normalized.reshape(data_shape)
# change 16 possible values over 0 to 255 range
return np.array(pixel_array * 0xff, np.uint8)
我的完整测试用例是:
from secrets import token_bytes
import cv2
import numpy as np
pixel_size = 20
final_image_size = (120, 120)
def gen_data(data_size):
# Generate some random data
return token_bytes(data_size)
def split_octet(data):
"""
For each 8-bit number in array, split them into two 4-bit numbers"""
split_data = []
for octet in data:
upper = octet >> 4
lower = octet & 0x0f
print(f"8bit:{octet:02x} upper:{upper:01x} and lower:{lower:01x}")
split_data.extend([upper, lower])
return split_data
def create_square_grayscale(data, data_shape):
# Normalize data from 0 to 1
normalized = np.array(data, np.float64) / 0xf
# fold data to image shape
pixel_array = normalized.reshape(data_shape)
# change 16 possible values over 0 to 255 range
return np.array(pixel_array * 0xff, np.uint8)
def main():
side1, side2 = (int(final_image_size[0]/pixel_size),
int(final_image_size[1]/pixel_size))
rnd_data = gen_data(int((side1 * side2)/2))
split_data = split_octet(rnd_data)
img = create_square_grayscale(split_data, (side1, side2))
print("image data:\n", img)
new_res = cv2.resize(img, None, fx=pixel_size, fy=pixel_size,
interpolation=cv2.INTER_AREA)
cv2.imwrite("/tmp/rnd.png", new_res)
if __name__ == '__main__':
main()
其中提供了以下内容的成绩单:
8bit:34 upper:3 and lower:4
8bit:d4 upper:d and lower:4
8bit:bd upper:b and lower:d
8bit:c3 upper:c and lower:3
8bit:61 upper:6 and lower:1
8bit:9e upper:9 and lower:e
8bit:5f upper:5 and lower:f
8bit:1b upper:1 and lower:b
8bit:a5 upper:a and lower:5
8bit:31 upper:3 and lower:1
8bit:22 upper:2 and lower:2
8bit:8a upper:8 and lower:a
8bit:1e upper:1 and lower:e
8bit:84 upper:8 and lower:4
8bit:3a upper:3 and lower:a
8bit:c0 upper:c and lower:0
8bit:3c upper:3 and lower:c
8bit:09 upper:0 and lower:9
image data:
[[ 51 68 221 68 187 221]
[204 51 102 17 153 238]
[ 85 255 17 187 170 85]
[ 51 17 34 34 136 170]
[ 17 238 136 68 51 170]
[204 0 51 204 0 153]]
并生成了下图:
原始数据有 18 个字节,有 36 个块/"20x20_pixels"
如果我将问题中的尺寸更改为 1800、1000,我会得到:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.