在用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
查看文件帧数
>>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
输入输出如下
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稍加修改即可食用。