我正在尝试将图像文件处理为可以在黑/白/红电子墨水显示器上显示的内容,但我遇到了输出分辨率的问题。
根据显示的示例代码,它需要两个字节数组(一个用于黑/白,一个用于红色),每个 15,000 字节。电子墨水显示屏的分辨率为400x300。
我使用以下 Python 脚本生成两个 BMP 文件:一个用于黑/白,一个用于红色。这一切都有效,但每个文件大小为 360,000 字节,无法容纳 ESP32 内存。输入图像(PNG 文件)为 195,316 字节。
我正在使用的库有一个名为
EPD_4IN2B_V2_Display(BLACKWHITEBUFFER, REDBUFFER);
的函数,它希望将完整图像(一个用于黑白通道,一个用于红色通道)存储在内存中。但是,对于这些图像尺寸,它不适合 ESP32。而且,该示例对每个颜色通道(BW、R)使用 15KB,所以我觉得我在图像处理中遗漏了一些必要的东西来完成这项工作。
任何人都可以阐明我所缺少的内容吗?我如何更新 Python 图像处理脚本来解决这个问题?
我正在使用Waveshare 4.2英寸电子墨水显示屏和Waveshare ESP32驱动板。很多 Python 代码都是基于 this StackOverflow post 但我似乎找不到问题。
import io
import traceback
from wand.image import Image as WandImage
from PIL import Image
# This function takes as input a filename for an image
# It resizes the image into the dimensions supported by the ePaper Display
# It then remaps the image into a tri-color scheme using a palette (affinity)
# for remapping, and the Floyd Steinberg algorithm for dithering
# It then splits the image into two component parts:
# a white and black image (with the red pixels removed)
# a white and red image (with the black pixels removed)
# It then converts these into PIL Images and returns them
# The PIL Images can be used by the ePaper library to display
def getImagesToDisplay(filename):
print(filename)
red_image = None
black_image = None
try:
with WandImage(filename=filename) as img:
img.resize(400, 300)
with WandImage() as palette:
with WandImage(width = 1, height = 1, pseudo ="xc:red") as red:
palette.sequence.append(red)
with WandImage(width = 1, height = 1, pseudo ="xc:black") as black:
palette.sequence.append(black)
with WandImage(width = 1, height = 1, pseudo ="xc:white") as white:
palette.sequence.append(white)
palette.concat()
img.remap(affinity=palette, method='floyd_steinberg')
red = img.clone()
black = img.clone()
red.opaque_paint(target='black', fill='white')
black.opaque_paint(target='red', fill='white')
red_image = Image.open(io.BytesIO(red.make_blob("bmp")))
black_image = Image.open(io.BytesIO(black.make_blob("bmp")))
red_bytes = io.BytesIO(red.make_blob("bmp"))
black_bytes = io.BytesIO(black.make_blob("bmp"))
except Exception as ex:
print ('traceback.format_exc():\n%s',traceback.format_exc())
return (red_image, black_image, red_bytes, black_bytes)
if __name__ == "__main__":
print("Running...")
file_path = "testimage-tree.png"
with open(file_path, "rb") as f:
image_data = f.read()
red_image, black_image, red_bytes, black_bytes = getImagesToDisplay(file_path)
print("bw: ", red_bytes)
print("red: ", black_bytes)
black_image.save("output/bw.bmp")
red_image.save("output/red.bmp")
print("BW file size:", len(black_image.tobytes()))
print("Red file size:", len(red_image.tobytes()))
根据要求,如果它可能对未来的读者有用,我会更广泛地写下我在评论中所说的内容(并被证实确实是问题的原因)。
电子墨水显示屏通常需要黑白图像。即每像素图像 1 位。不是灰度(每像素 1 通道字节),更不是 RGB(每像素 3 通道/字节)。
我不熟悉红/黑双色显示屏。但看起来很合乎逻辑的是,它的行为就像 2 个二进制显示器(一个黑白显示器,一个黑白红显示器)。共享同一位置。
您的代码似乎所做的是从 RGB 图像中删除所有黑色像素,并将其用作红色图像,并从同一 RDB 图像中删除所有红色像素,并将其用作黑色图像。但由于这些图像是使用
clone
获得的,因此它们仍然是 RGB 图像。 RGB 图像碰巧只包含黑白像素,或红白像素,但仍然是 RGB 图像。
使用 PIL,它是控制图像在内存中表示方式以及如何将它们保存到文件的模式。 相关模式为
RGB
、L
(灰度又称为每像素 1 个线性字节/通道)和 1
(二进制又称为每像素 1 位)。
所以你需要的是转换为模式
1
。在两个图像上使用 .convert('1')
方法。
请注意,400x300×3(图像的未压缩 RGB 数据)是 360000,这就是您得到的。 400×300(同一图像的L模式)是120000,400×300/8(1模式,1位/像素)是15000,这正是您提到的预期大小。因此,这是另一个确认,确实需要 1 位/像素图像。
我已经编写了一个工具来完成此操作 ->
https://github.com/bitbank2/epd_image
它允许您为各种电子墨水显示器生成正确的图像数据,并将其以准备编译到代码中的形式输出。