Hello ! 我是小恒不会java
背景
阅读国外一书《python playground》之中写道:将图片图像转化为ASCII文本图像,很有意思,以前都是用文字生成ASCII文本艺术,比如:
_
| |__ ___ _ __ __ _
| '_ \ / _ \ | '_ \ / _` |
| | | | | __/ | | | | | (_| |
|_| |_| \___| |_| |_| \__, |
|___/
图片生成ASCII
直接上Mahesh的代码,我稍微修改汉化了一下哈
# ascii.py
# 一个将图像转换为ASCII艺术的Python程序。
import sys, random, argparse
import numpy as np
import math
from PIL import Image
# 来自:http://paulbourke.net/dataformats/asciiart/
# 70级灰度值
gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
# 10级灰度值
gscale2 = '@%#*+=-:. '
def getAverageL(image):
"""
给定PIL Image对象,返回其灰度平均值
"""
# 将图像转换为NumPy数组
im = np.array(image)
# 获取图像形状
w, h = im.shape
# 计算平均值
return np.average(im.reshape(w * h))
def covertImageToAscii(fileName, cols, scale, moreLevels):
"""
给定图像文件名及尺寸(行数,列数),返回一个由ASCII字符组成的m*n二维列表
"""
# 声明全局变量
global gscale1, gscale2
# 打开图像并将其转换为灰度模式
image = Image.open(fileName).convert('L')
# 存储原始尺寸
W, H = image.size[0], image.size[1]
print("输入图像尺寸: %d x %d" % (W, H))
# 计算每列的宽度
w = W / cols
# 根据比例和缩放因子计算每行的高度
h = w / scale
# 计算所需的行数
rows = int(H / h)
print("列数: %d, 行数: %d" % (cols, rows))
print("每个单元格尺寸: %d x %d" % (w, h))
# 检查图像尺寸是否小于指定的列数
if cols > W or rows > H:
print("对于指定的列数,图像太小了!")
exit(0)
# ASCII图像是一个由字符字符串构成的列表
aimg = []
# 生成一组维度数据
for j in range(rows):
y1 = int(j * h)
y2 = int((j + 1) * h)
# 对于最后一行单元格进行纠正
if j == rows - 1:
y2 = H
# 添加一个空字符串
aimg.append("")
for i in range(cols):
# 计算当前单元格左上角和右下角的坐标
x1 = int(i * w)
x2 = int((i + 1) * w)
# 对于最后一列单元格进行纠正
if i == cols - 1:
x2 = W
# 截取图像中的对应区域
img = image.crop((x1, y1, x2, y2))
# 计算该区域的平均亮度
avg = int(getAverageL(img))
# 查找对应的ASCII字符
if moreLevels:
gsval = gscale1[int((avg * 69) / 255)]
else:
gsval = gscale2[int((avg * 9) / 255)]
# 将ASCII字符添加到字符串中
aimg[j] += gsval
# 返回ASCII文本图像
return aimg
# 主函数
def main():
# 创建解析器
descStr = "此程序用于将图像转换为ASCII艺术形式。"
parser = argparse.ArgumentParser(description=descStr)
# 添加期望的参数
parser.add_argument('--file', dest='imgFile', required=True)
parser.add_argument('--scale', dest='scale', required=False)
parser.add_argument('--out', dest='outFile', required=False)
parser.add_argument('--cols', dest='cols', required=False)
parser.add_argument('--morelevels', dest='moreLevels', action='store_true')
# 解析参数
args = parser.parse_args()
imgFile = args.imgFile
# 设置输出文件默认名为'out.txt'
outFile = 'out.txt'
if args.outFile:
outFile = args.outFile
# 设置缩放因子默认值为0.43,适合Courier字体
scale = 0.43
if args.scale:
scale = float(args.scale)
# 设置列数默认值为80
cols = 80
if args.cols:
cols = int(args.cols)
print('正在生成ASCII艺术...')
# 将图像转换为ASCII文本
aimg = covertImageToAscii(imgFile, cols, scale, args.moreLevels)
# 打开文件
with open(outFile, 'w') as f:
# 将ASCII艺术写入文件
for row in aimg:
f.write(row + '\n')
# 清理操作
print("ASCII艺术已写入至 %s" % outFile)
# 当作为主脚本执行时调用main函数
if __name__ == '__main__':
main()
运行
python c:/Users/李恒/Desktop/pp-master/ascii/ascii.py --file "C:\Users\李恒\Desktop\图库\80.png"
这将确保文件路径被正确解析(这是我的py文件路径)。
如果还需要指定其他参数,例如--scale
、--out
和--cols
,请确保它们也用双引号括起来。
python c:/Users/李恒/Desktop/pp-master/ascii/ascii.py --file "C:\Users\李恒\Desktop\图库\80.png" --scale 0.43 --out "C:\Users\李恒\Desktop\output.txt" --cols 80
-
缩放因子或垂直比例系数
(--scale
):缩放因子会影响输出图像的大小。较小的缩放因子将导致输出图像较大,而较大的缩放因子将导致输出图像较小。请注意,缩放因子应根据所选字体的大小进行调整。 -
更改列数(
--cols
):列数会影响输出图像的宽度。增加列数将使输出图像更宽,而减少列数将使输出图像更窄。 -
使用更多的灰度级别(
--morelevels
):使用更多的灰度级别将提高输出图像的细节和对比度。请注意,这可能会导致输出图像的大小增加。
效果展示
基本原理
1.将图片转成灰度
定义灰度梯度,从10级到70级,也就是模拟从最亮到黑暗的变化过程
使用image.convert将打开的图片转化为灰度
2.将图片分成M*N小块,修正M以调整纵横比
设置列数(默认80),用--cols,再通过比例系数scale(默认0.43)计算对应行数
3.计算每小块亮度,并为小块寻找ASCII字符
使用getAverageL()函数实现每小块亮度计算
4.最后为程序定义命令行选项
5.汇集小块ASCII字符串,打印至文件
扩展
我准备扩展它的功能
-
色彩支持: 目前,程序仅处理灰度图像。如果要支持彩色图像,可以分别对红、绿、蓝三个通道计算平均亮度,并结合这三个通道的亮度选择合适的ASCII字符。
-
更精细的灰度映射: 现有的两个灰度等级表可以进一步优化,比如创建更多的级别,或者允许用户自定义灰度映射表。
-
自适应缩放: 程序目前要求用户提供列数和缩放因子。为了增加灵活性,您可以自动调整这些值以更好地适应图像的宽高比,确保输出的ASCII艺术具有较好的视觉效果。
-
动态字体大小: 考虑根据ASCII字符的实际宽度在终端或其他环境中显示,动态调整字符间距,使得输出的ASCII艺术更具可读性和美观性。
-
提供一个GUI界面