使用PIL生成ASCII艺术脚本报错:'str' object has no attribute 'size'
解决AttributeError: 'str' object has no attribute 'size'问题
问题根源
- 文件名不匹配:你用
cv2.imwrite(f"frame{count}.jpg", image)保存的是frame{count}.jpg,但调用ascii函数时传入的是f"image{count}.jpg",导致PIL找不到文件,image变量保持为字符串路径,进而传给resize函数引发错误。 - 错误处理不完整:
ascii函数中,若PIL.Image.open失败,没有终止后续逻辑,依然将原始字符串传入resize函数,而字符串没有size属性。 - resize参数类型错误:计算
new_height得到的是浮点数,但image.resize要求尺寸为整数,会引发隐性错误。
修复方案
1. 修正文件名匹配
修改调用代码中的文件名,确保和保存的文件一致:
with open(f"ascii{count}.txt", "w") as f: f.write(ascii(f"frame{count}.jpg")) # 改为frame开头,和保存的文件名对应
2. 完善错误处理逻辑
在ascii函数中,打开失败时直接返回空字符串,避免后续错误执行:
def ascii(image_path): try: image = PIL.Image.open(image_path) except Exception as e: print(f"{image_path} 无法打开,错误信息: {e}") return "" # 打开失败时返回空,终止后续流程 image = resize(image) greyscale_image = to_greyscale(image) ascii_str = pixel_to_ascii(greyscale_image) img_width = greyscale_image.width ascii_str_len = len(ascii_str) ascii_img="" for i in range(0, ascii_str_len, img_width): ascii_img += ascii_str[i:i+img_width] + "\n" return ascii_img
(注:将参数名从image改为image_path,更清晰区分路径字符串和Image对象)
3. 修正resize函数的尺寸类型
将计算出的new_height转为整数,符合resize方法的参数要求:
def resize(image, new_width = 100): old_width, old_height = image.size new_height = int(new_width * old_height / old_width) # 转为整数 return image.resize((new_width, new_height))
完整修正后的get_ascii.py代码
import PIL.Image ASCII_CHARS = ["@", "#", "$", "%", "?", "*", "+", ";", ":", ",", "."] def pixel_to_ascii(image): pixels = image.getdata() ascii_str = "" for pixel in pixels: ascii_str += ASCII_CHARS[pixel//25] return ascii_str def to_greyscale(image): return image.convert("L") def resize(image, new_width = 100): old_width, old_height = image.size new_height = int(new_width * old_height / old_width) return image.resize((new_width, new_height)) def ascii(image_path): try: image = PIL.Image.open(image_path) except Exception as e: print(f"{image_path} 无法打开,错误信息: {e}") return "" image = resize(image) greyscale_image = to_greyscale(image) ascii_str = pixel_to_ascii(greyscale_image) img_width = greyscale_image.width ascii_str_len = len(ascii_str) ascii_img="" for i in range(0, ascii_str_len, img_width): ascii_img += ascii_str[i:i+img_width] + "\n" return ascii_img
修正后的调用代码片段
while success: success, image = vidcap.read() if not success: # 读取失败时退出循环,避免无效操作 break frame_filename = f"frame{count}.jpg" cv2.imwrite(frame_filename, image) print ("Saved frame ", count) with open(f"ascii{count}.txt", "w") as f: f.write(ascii(frame_filename)) print("Saved ascii frame ", count) count += 1 time.sleep(0.2)
内容的提问来源于stack exchange,提问作者Lava
相关产品推荐
相关产品推荐

