将图像转换为 3 色电子墨水显示屏时出现问题

问题描述 投票:0回答:2

我正在尝试将图像文件处理为可以在黑/白/红电子墨水显示器上显示的内容,但我遇到了输出分辨率的问题。

根据显示的示例代码,它需要两个字节数组(一个用于黑/白,一个用于红色),每个 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 但我似乎找不到问题。

Input Image BW Red

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()))
python image-processing esp32 dithering e-ink
2个回答
4
投票

根据要求,如果它可能对未来的读者有用,我会更广泛地写下我在评论中所说的内容(并被证实确实是问题的原因)。

电子墨水显示屏通常需要黑白图像。即每像素图像 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 位/像素图像。


1
投票

我已经编写了一个工具来完成此操作 ->

https://github.com/bitbank2/epd_image

它允许您为各种电子墨水显示器生成正确的图像数据,并将其以准备编译到代码中的形式输出。

© www.soinside.com 2019 - 2024. All rights reserved.