将像素信息写入文件并读取

1 投票
4 回答
65 浏览
提问于 2025-04-14 16:55

有没有人能帮我一下?我在一个本该很简单的问题上转了好几圈!

我有一个像素信息的数组,想用它来重建一张小图片。获取像素数据的部分已经搞定,这些信息存在一个二维数组里,像这样:

[(255,0,0),(125,111,2),(.... etc

接下来,我想把这些信息写入一个文件,然后从另一个程序中读取回来,格式要一样(或者相似)。比如,第十个像素的颜色数据可以通过 pixel[9][0] 来获取红色值,pixel[9][1] 来获取绿色值,等等。

我觉得我应该能把这些数据写成字节,因为所有数字都小于256,这样每个字节可以逐个读取并添加到另一个列表里。但似乎没有办法做到这一点!我尝试的所有方法都把数字保存成了单独的数字字符,比如 (255,0,0) 被存成了 '2','5','5','0','0'。如果我试着存数字,结果也是只存了数字字符;如果我试着存字节,又出现错误,提示不能把整数存成字节。存成字符串也没用,因为数字字符又和换行符等我根本不需要的东西一起存了。

我不得不删掉我尝试过的代码示例,因为无论我怎么做,提交问题时总是提示代码格式不正确。唯一能发帖的办法就是把所有代码都删掉!不过我用过 'write' 和 int、chr,但就是没用。

这个文件是要在 Raspberry Pi Pico 上读取的。

有没有人有什么想法?谢谢!

4 个回答

0

我觉得你应该使用 .bmp 格式的图片文件,因为它是存储原始图片的标准格式,不会压缩或者丢失数据。

Python 有一个叫做 Pillow 的库,可以用来处理图片(你可以通过像 pip 这样的工具来安装它)。

这里有一些链接可以帮助你:

3

用像素列表来处理图像并不是最自然的方式,因为图像是二维的,也就是说它们有高度和宽度,像素的行和列自然是这样排列的:

image[0,34]

大多数图像处理工具包在Python中使用的结构是Numpy的ndarray。它看起来是这样的:

#!/usr/bin/env python3

import numpy as np

# Create empty image 2 rows, 4 columns, and 3 RGB pixels at each location
image = np.zeros((2,4,3), np.uint8)

# 1st row: Red, Green, Blue, Black
image[0,0] = [255,0,0]
image[0,1] = [0,255,0]
image[0,2] = [0,0,255]
image[0,3] = [0,0,0]

# 2nd row: Cyan, Magenta, Yellow, White
image[1,0] = [0,255,255]
image[1,1] = [255,0,255]
image[1,2] = [255,255,0]
image[1,3] = [255,255,255]

# Save to a file
image.tofile('image.rgb')

使用Numpy数组后,你可以在电脑上使用PIL/Pillow、OpenCV和scikit-image来查看、调整大小、转换、裁剪和处理图像。

不过,你选择的格式有个问题,就是它是一个列表,无法让你知道图像的高度和宽度,所以当你重新加载它时,你得到的只是一个列表,而没有高度和宽度的信息:

reloaded = np.fromfile('image.rgb', dtype=np.uint8)

如果你打印出来,你会得到一个包含24个数字的列表:

print(reloaded)
array([255,   0,   0,   0, 255,   0,   0,   0, 255,   0,   0,   0,   0, 0, 255, 255,   0, 255, 255, 255,   0, 255, 255, 255], dtype=uint8)

如果你检查它的形状,你会发现它是一个一维的24个数字的列表,而不是一个有高度和宽度的图像:

print(reloaded.shape)
(24,)

所以你需要通过其他方式“知道”它的形状,然后重新调整它:

reloaded = np.fromfile('image.rgb', dtype=np.uint8).reshape((2,4,3))

然后你可以在电脑的命令行中使用ImageMagick来处理这个图像,比如放大它并转换成PNG格式:

magick -size 4x2 -depth 8 image.rgb -scale 300x bigger.png

在这里输入图像描述


我觉得Numpy在MicroPython中并不存在,所以你可以用@hjuste在Pico上写的代码来读取这个图像。


不过……

我认为这个格式并不好,因为它没有图像的高度和宽度,其他程序也很难读取、处理或显示它。我建议你使用PPM格式,它非常简单,前面有一个简短的头部,包含图像的大小。

而且,你可以用ASCII格式而不是二进制格式来写,这样就可以用文本编辑器编辑它。虽然效率有点低,但正如你所说,你的图像很小。

所以,为了写一个简单的(ASCII/未压缩的)PPM文件,你可以使用OpenCV,如下所示,来写我在回答开始时创建的图像:

import cv2 as cv

... create "image" like I did above ...

# Save image as ASCII PPM file
cv.imwrite('result.ppm', image, [cv.IMWRITE_PXM_BINARY,0])

然后你可以在Pico上非常简单地读取它,大致像这样:

with open('result.ppm') as f:
    s = f.read()

# Find anything that looks like numbers
l = re.findall(r'[0-9P]+',s)

# Pick up width and height
w, h = int(l[1]), int(l[2])

# Pick up remaining pixels
pixels = l[4:]

使用PPM格式的好处是:

  • 你的图像可以与其他工具(如ImageMagick、vips、Photoshop、MS-Paint、IrfanView)兼容,方便查看和修改
  • 它们在Pico上容易读取

例如,你可以非常简单地用ImageMagick制作一个红色的24x8 PPM图像:

magick -size 24x8 xc:red -compress none -depth 8 red.ppm

或者像这样调整一个PNG的大小并转换为PPM:

magick image.png -resize 80x40 -compress none -depth 8 image.ppm
1

你是说像这样吗?

# Example pixel data
pixels = [
    (255, 0, 0),    # Red
    (125, 111, 2),  # Some other color
    # Add more pixel data here
]

# Open a file in binary write mode
with open("image_data.bin", "wb") as file:
    for pixel in pixels:
        # Write each color component as a byte
        for color_component in pixel:
            file.write(bytes([color_component]))

# Reading back the data
read_pixels = []
with open("image_data.bin", "rb") as file:
    while True:
        # Read 3 bytes (one for each color component) at a time
        color_components = file.read(3)
        if not color_components:
            break
        # Unpack the bytes into a tuple representing the color
        color = tuple(color_components)
        read_pixels.append(color)

print(read_pixels[0][0]) # The first index represents the pixel, the second index represents the color from that pixel.

撰写回答