TFT_espi图片转换脚本

在用Ardunio的TFT_espi这个库时每次想显示图片都要用某些已有的工具软件转换成bitmap或者数组,但是我见过的工具都只能一张一张的转换,如果想转换GIF或者视频真的太麻烦了,所以就写了两个脚本。

完整代码在图像转换脚本,这里只记录一些关键的地方。

关键点

许多图形库提供的接口都是显示bitmap或者图像数组是,所以我先把常见格式的图片或者动图转成bmp,然后再把RGB888的bmp转成RGB565的数组。

按系统顺序读取目录下所有图片文件

像os.listdir()或者glob.glob()返回地顺序是乱的,对于文件名有规律地可以自己实现排序,但是对于没有规律的自己排序还是比较麻烦的。

natsort这个包可以对文件名排序,非常方便地排成和我们在资源管理器看到的文件顺序一样。

1
2
3
4
5
6
7
8
def get_image_files(folder_path):
pattern = r".*\.(jpg|jpeg|png|bmp|gif|webp|ico|pbm|pgm|ppm|mp4)$"
image_files = []
files = os.listdir(folder_path)
for file_name in natsorted(files,alg=ns.PATH):
if re.match(pattern, file_name, re.IGNORECASE):
image_files.append(os.path.join(folder_path, file_name))
return image_files

读取GIF

缩放指定大小,均匀采样指定帧数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def read_gif(gif: Image.Image, dsize: tuple[int, int], maximum_frames=0) -> list[Image.Image]:
'''
@param gif: Image 源GIF
@param dsize: (int,int) 目标图像的(宽度,高度)
@param maximum_frames: int 保留帧数
@return [Image.Image,...]
'''
frames = gif.n_frames
gif.info['frames'] = frames
f = min(frames, maximum_frames) if maximum_frames > 0 else frames
step = math.ceil(frames/f)
counter = 0
aframes = []
for frame in ImageSequence.Iterator(gif):
if counter % step == 0:
aframes.append(frame.resize(dsize))
counter += 1
return aframes

读取mp4

跟GIF类似,但是PIL没找到读取时视频文件的方法,这里用了opencv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def read_mp4(file: str, dsize: tuple[int, int], maximum_frames=0):
'''
@param file: str MP4文件路径
@param dsize: (int,int) 目标图像的(宽度,高度)
@param maximum_frames: int 保留帧数
@return [Image.Image(), ...]
'''
aframes = []
cap = cv.VideoCapture(file)
if not cap.isOpened():
print("无法打开视频文件:", file)
cap.release()
return aframes
frames = int(cap.get(cv.CAP_PROP_FRAME_COUNT))
f = min(frames, maximum_frames) if maximum_frames > 0 else frames
step = math.ceil(frames/f)
ret = True
counter = 0
while ret:
ret, frame = cap.read()
if frame is not None:
frame = cv.cvtColor(frame,cv.COLOR_BGR2RGB)
if counter % step == 0:
aframes.append(Image.fromarray(cv.resize(frame,dsize)))
counter+=1
cap.release()
return aframes

bmp转RGB565 hex数组

1
2
3
4
5
6
7
8
9
10
11
12
def bmp_to_hex_RGB565(filepath,head='',tail='') ->str:
image = Image.open(filepath)
image = image.convert("RGB")
width, height = image.size
image_data = []
for y in range(height):
for x in range(width):
r, g, b = image.getpixel((x, y))
pixel = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)
image_data.append(pixel)
hex_data = [hex(pixel) for pixel in image_data]
return head+str(hex_data).replace('\'','').replace('[', '{').replace(']', '}')+tail

脚本使用说明

tobmp.py

输入输出如下

  • GIF/mp4👉文件目录下创建同名目录存放bmp
  • 图片文件/图片文件目录👉文件目录下创建输出目录存放bmp

options:

  • -h, –help
  • -F FOLDERPATH, –folderpath FOLDERPATH
    图片所在文件夹
  • -W WIDTH, –width WIDTH
    缩放后图像的宽度
  • -H HEIGHT, –height HEIGHT
    缩放后图像的高度
  • -f FRAMES, –frames FRAMES
    GIF文件保留帧数
  • -v FRAMENUM, –framenum FRAMENUM
    查看文件帧数

gege.gif

>>python .\tobmp.py -F .\imgs\gege.gif -W 64 -H 64 -v 1

>>文件帧数:212

>>python .\tobmp.py -F .\imgs\gege.gif -W 64 -H 64 -f 106

就会在imgs目录下生成bmps目录,bmps目录里有gege目录,gege目录里有106张64×64 bmp图像并且文件名为0-105。

bmptohex_RGB565.py

输入输出如下

  • bmp文件👉一维数组
  • bmp所在目录👉n维数组

options:

  • -h, –help show this help message and exit
  • -F PATH, –path PATH bmp图片或bmp图片目录路径

>>python .\bmptohex_RGB565.py -F .\imgs\bmps\gege\

就会在imgs\bmps\gege下生成hexRGB565.txt文件,复制此内容到Ardunio稍加修改即可食用。


TFT_espi图片转换脚本
https://zy946.github.io/posts/fdd48e00/
作者
zy
发布于
2023年7月22日
许可协议