目录
1. 简介
这是一个基于Python的图片转为ASCII字符的系统,话不多说,先看效果:
2. 技术介绍
(1) Pillow
Pillow 是 Python 图像处理库,是由 PIL(Python Imaging Library)库开发者创建的一个友好的 PIL 分支库,它提供了许多以 PIL 为基础的接口和许多新的功能。Pillow 库可以帮助您处理各种图像操作,如图像缩放、裁剪、旋转、转换格式等等。
Pillow 支持的图像文件格式非常多,包括 BMP、GIF、JPEG、PNG、TIFF、WebP 等,同时还支持处理 GIF 动图,以及图像信息的获取等功能。此外,Pillow 提供了一些图像增强的方法,比如颜色调整、对比度调整、滤波器等。
(2) PySide2
PySide2 是 Qt5 的 Python 绑定库,可以让开发者使用 Python 语言轻松地构建跨平台(包括 Windows、macOS、Linux、Android 和 iOS)的图形界面应用程序。PySide2 采用了 BSD 许可证,因此可以免费使用和分发。
PySide2 可以调用 Qt5 中的各种功能,包括界面控件、布局管理器、事件处理、绘图等等。除此之外,它还提供了很多 Qt5 无法提供的高效便捷的 Pythonic API,如信号槽机制的 pyqtSignal 和 pyqtSlot、虚函数覆盖的 Python 装饰器、命令行参数解析等等。
3. 系统实现
由于系统代码行数较多,这里只粘贴了部分关键代码:
(1) 图片转字符图实现
try:
# 将图片转换为ASCII字符
with Image.open(self.image_path) as im:
# 获取原图的高度与宽度
width, height = im.size
# 原图的高宽之比
t = width/height
# 设置转换出的字符图的高度,设置的值越小,转换出的字符图就越小,细节程度也低,该值不建议太大也不建议太小,介于50-200之间的整数即可
# 这里我根据图片的高度来确定字符图的高度
char_height = int(height/2)
char_width = int(char_height*t*2) # 通过图片高宽比例计算字符图的宽度,乘2是因为转换后宽度被压缩为原来的1/2
# 将图片转换为单通道灰度图并调整为字符图的大小
im = im.convert('L').resize((char_width, char_height))
# 将像素映射为ASCII字符
char_lst = ['@', '#', '8', 'M', '&', 'N', '9', 'H', 'Q', '4', 's', 'r',
'1', 'i', '*', ';', '~', ':', ',', '.', ' ']
result = ''
for j in range(im.size[1]):
for i in range(im.size[0]):
gray = im.getpixel((i, j))
idx = int(gray / (256 / len(char_lst)))
result += char_lst[idx]
result += '\n'
if result:
# 根据图片名称将字符保存到文件
file_path, ext = os.path.splitext(self.image_path)
filename = os.path.basename(file_path) + '.txt'
file_path = os.path.join('./data', filename)
with open(file_path, 'w') as f:
f.write(result)
self.update_progress.emit(100) # 发送完成进度信号
else:
self.update_progress.emit(0) # 发送失败进度信号
except:
self.update_progress.emit(0) # 发送失败进度信号
(2) GUI界面实现
def __init__(self):
super().__init__()
# 设置窗口标题和图标
self.setWindowTitle('图片转字符')
self.setWindowIcon(QIcon('./icon/icon.ico'))
# 设置图片显示标签
self.image_label = QLabel() # 创建图片显示标签
self.image_label.setAlignment(Qt.AlignCenter) # 居中对齐
self.image_label.setFixedSize(400, 400) # 设置固定大小
self.image_label.setStyleSheet('border: 1px solid black;') # 添加边框样式
# 设置上传图片按钮
self.upload_button = QPushButton('上传图片') # 创建上传图片按钮
self.upload_button.clicked.connect(self.upload_image) # 绑定点击事件
# 设置开始转换按钮
self.convert_button = QPushButton('开始转换') # 创建开始转换按钮
self.convert_button.setDisabled(True) # 初始状态禁用
self.convert_button.clicked.connect(self.start_conversion) # 绑定点击事件
# 设置查看结果按钮
self.result_button = QPushButton('查看结果') # 创建查看结果按钮
self.result_button.setDisabled(True) # 初始状态禁用
self.result_button.clicked.connect(self.show_result) # 绑定点击事件
# 设置进度标签
self.progress_label = QLabel('') # 创建进度标签
self.progress_label.setAlignment(Qt.AlignCenter) # 居中对齐
# 设置标题
title_layout = QHBoxLayout() # 创建水平布局
title_layout.addWidget(self.image_label) # 将图片标签添加到布局中
# 设置按钮
button_layout = QHBoxLayout() # 创建水平布局
button_layout.addWidget(self.upload_button) # 添加上传图片按钮
button_layout.addWidget(self.convert_button) # 添加开始转换按钮
button_layout.addWidget(self.result_button) # 添加查看结果按钮
# 设置主布局
main_layout = QVBoxLayout() # 创建垂直布局
main_layout.addLayout(title_layout) # 添加标题布局
main_layout.addLayout(button_layout) # 添加按钮布局
main_layout.addWidget(self.progress_label) # 添加进度标签
# 设置窗口布局
self.setLayout(main_layout) # 设置主布局
self.setFixedSize(450, 520) # 设置固定大小,增加高度避免遮挡进度标签
def upload_image(self):
# 选择并显示图片
image_path, _ = QFileDialog.getOpenFileName(self, '上传图片', '/', 'Images (*.jpg *.jpeg *.png *.bmp)')
if image_path:
self.image_label.setPixmap(QPixmap(image_path).scaled(400, 400, Qt.KeepAspectRatio))
self.convert_button.setEnabled(True)
self.upload_button.setText('重新上传')
self.image_path = image_path
def start_conversion(self):
# 转换图片为字符并保存到文件
self.convert_button.setDisabled(True)
self.result_button.setDisabled(True)
self.convert_button.setText('转换中...')
self.image2ascii = Image2ASCII(self.image_path)
self.image2ascii.update_progress.connect(self.update_progress)
self.image2ascii.start()
def update_progress(self, progress):
# 更新进度标签
if progress == 100:
self.progress_label.setText('转换完成')
self.result_button.setEnabled(True)
self.convert_button.setText('开始转换')
else:
self.progress_label.setText(f'转换进度:{progress}%')
self.convert_button.setEnabled(False)
def show_result(self):
file_name, _ = QFileDialog.getOpenFileName(self, '查看结果', './data/', 'Text Files (*.txt)')
if file_name:
with open(file_name, 'r') as f:
result = f.read()
# 使用 os.startfile 打开文件
os.startfile(file_name)
4. 运行效果
运行效果如下图所示: