图片处理成字符组成的图

 

目录

一、环境配置

1.安装notepad++

2.安装python3.7

3.安装PIL(在Python3.7叫Pillow)

3.1先更新(或重新安装)一下pip

3.2然后安装Pillow(py图像处理库,包名开头是大写注意)

4.配置notepad++运行调试环境

5.使用notepad++的一些建议

5.1由于python不认tab符所以设置成按tab间的制表符换为四个空格

5.2如果不想这么做,也可以开启显示字符模式,查看tab和空格

5.3如果对python不熟悉经常要查文档的可以将

二、python的图片转文字

1.图片转字符图(方法一)

1.1探索过程

1.2其他

2.图片转文字图(方法二)

3.Gif处理


一、环境配置

1.安装notepad++

百度官网下载安装即可

2.安装python3.7

百度官网下载安装,要用就要用最新的

3.安装PIL(在Python3.7叫Pillow)

3.1先更新(或重新安装)一下pip

python -m pip install --upgrade pip

3.2然后安装Pillow(py图像处理库,包名开头是大写注意)

pip install Pillow

要是太慢Ctrl+c终止掉,使用清华的包源[-i https://pypi.tuna.tsinghua.edu.cn/simple]

C:\Users\Administrator>pip install -i https://pypi.tuna.tsinghua.edu.cn/simple n
umpy

4.配置notepad++运行调试环境

依次点击 运行(ps.菜单栏中的) -管理快捷键

把默认的F5快捷键去掉,或者换成其他的,推荐shift+F5,等下我们要用F5于是这一步是为了空出快捷键

然后运行(ps菜单栏上的)-运行输入

cmd /k cd "$(CURRENT_DIRECTORY)" & python "$(FILE_NAME)" &PAUSE&EXIT

保存快捷键为F5

cmd是运行命令提示符(也就是Windows的终端,win7以后还有个powershell),使用/k传递要执行的命令

cd "$(CURRENT_DIRECTORY)"是进入当前目录的意思,CURRENT_DIRECTORY是notepad++的一个内部变量,值是当前编辑文件的路径,为什么要进入文件当前路径呢,因为我们的py程序会用到相对路径,而cmd默认的启动路径是用户文件夹,如果不进到文件当前的路径,python程序使用的相对路径就会以用户文件夹作为标准进行运算,也就是"./test.jpg"这样的路径不会打开python文件同级下的test.jpg,而是打开用户路径(e.g.[例如,拉丁语,英文惯用法]C:\Users\Administrator)下的test.jpg导致文件没找到。"$(CURRENT_DIRECTORY)"表示变量部分是$(CURRENT_DIRECTORY),加双引号是为了防止路径有空格(e.g. cd "C:\Program Files" 可行,cd C:\Program Files不可行),&表示多条语句顺序执行,&&表示多条语句顺序执行但是前一个命令未通过则停止执行后面的命令,这个不举例子自行百度。

PAUSE是终端的等待(i.e.[也就是,拉丁语,英文惯用法] 请按任意键继续. . .)防止出错的程序一闪而过,EXIT这个都知道了退出终端。

5.使用notepad++的一些建议

5.1由于python不认tab符所以设置成按tab间的制表符换为四个空格

设置(主菜单里)-首选项-语言-替换为空格打上勾

5.2如果不想这么做,也可以开启显示字符模式,查看tab和空格

5.3如果对python不熟悉经常要查文档的可以将

python -m pydoc -b

写入notepad++快捷键,查阅文档用

二、python的图片转文字

1.图片转字符图(方法一)

from PIL import Image,ImageDraw,ImageFont

#因为这个需要不断调试,网上的算法千篇一律,出处https://blog.csdn.net/dpengwang/article/details/79076188
ascii_char  =list("/\|()1{}$@B%8&WM#ZO0QLCJUYX*hkbdpqwmoahkbdpqwmzcvunxrjft[]?-_+~<>i!lI;:,\"^`'. ")
imgname = "input.jpg" #需要处理的文件名
zoom=10       #图片缩放大小,精细度,越小越精细
fontsize=24    #文字大小
backspace=3    #文字负间距,因为没有这个文字间距离太远
#网上千篇一律的算法,也找不到出处了,可能是图像处理的一个算法
def get_char(r,g,b,alpha= 256):
    length = len(ascii_char)
    gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
    unitcount  = (256.0+1)/length
    return  ascii_char[int(gray/unitcount)]
	
img  = Image.open(imgname)#打开文件
width=int(img.width/zoom)#缩放图片宽度
height=int(img.height/zoom)#缩放图片高度
img  = img.resize((width,height),Image.NEAREST)#进行缩放
output = Image.new("RGB", (width*(fontsize-backspace), height*(fontsize-backspace)), (255, 255, 255))#新建空白画布
drawBrush = ImageDraw.Draw(output)#绑定画刷
font=ImageFont.truetype("simkai.ttf",fontsize)#定义字体

#循环处理缩放后input的每一个像素
for i in range(height):
    for j in range(width):
       drawBrush.text((j*(fontsize-backspace),i*(fontsize-backspace)), get_char(*img.getpixel((j,i))), (0,0,0),font=font)#在output画布上写字
	   
output.show()#使用默认工具打开图片
output.save("output.jpg")#保存生成的图片到当前路径的output.jpg

图片[input.jpg]

notepadd++ F5运行(之前我们配置好的)输出[output.jpg]

效果不怎么好,把zoom=3 就会很精细了,有待改进,总体的思路是计算RGB值,偏白色用较空的字符代替,偏黑用字符面积大的代替。程序框架有了,我们继续改进。

1.1探索过程

1.1.1先把ASCII码找出来

#去掉一些意义符,只显示显示符
for i in range(32, 127):
    print(chr(i),end="")

F5运行

1.1.2统计ASCII码的占黑比(我是这么叫的)

我们还得知道这些字符的长宽是否统一

from PIL import ImageFont
fontsize=24 #字体大小
font=ImageFont.truetype("simkai.ttf",fontsize)#定义字体
for i in range(32, 127):
    print(chr(i),font.getsize(chr(i)))

果然不统一,那么我们都按24来算吧

from PIL import Image,ImageDraw,ImageFont
fontsize=24#测试的字体大小
font=ImageFont.truetype("simkai.ttf",fontsize)#定义字体
canvas=Image.new("RGB", (fontsize,fontsize), (255, 255, 255))#用于实际作画统计
ncanvas=Image.new("RGB", (fontsize,fontsize), (255, 255, 255))#空白画布用于重置股覆盖
drawBrush = ImageDraw.Draw(canvas)#绑定画刷
list=[]#存储用于排序的结果
def statistics():
    for i in range(32, 127):#循环每个字符
        drawBrush.text((0,0),chr(i),(0,0,0),font)#花在画布上
        list.append([canvas.getcolors(255)[0][0],chr(i)])#获取所有的颜色统计,并输出白像素的个数
        canvas.paste(ncanvas)#清空画布
statistics()#调用函数因为调试的时候要中断,break只能退出一个for循环,于是写成函数,return终止
list.sort(reverse=True)#降序排序
for i in list:
    print(i[1],end="")#不换行输出这个降序字符数组
print()#换行

1.1.3调试程序

把这个字符串替换

from PIL import Image,ImageDraw,ImageFont

#因为这个需要不断调试,网上的算法千篇一律,出处https://blog.csdn.net/dpengwang/article/details/79076188
ascii_char  =list("MWN@QB%G$&8#ROgDKCH5S0EmdUAX693PZ2qVb4ewahkpF*Yosy[]cJ7un?f{LTx|}t<z)>v(1j=\+!Il/ri~-^;\",:`'._ ")
imgname = "input.jpg" #需要处理的文件名
zoom=5      #图片缩放大小,精细度,越小越精细
fontsize=24    #文字大小
backspace=4    #文字负间距,因为没有这个文字间距离太远
#网上千篇一律的算法,也找不到出处了,可能是图像处理的一个算法
def get_char(r,g,b,alpha= 256):
    length = len(ascii_char)
    gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
    unitcount  = (256.0+1)/length
    return  ascii_char[int(gray/unitcount)]
	
img  = Image.open(imgname)#打开文件
width=int(img.width/zoom)#缩放图片宽度
height=int(img.height/zoom)#缩放图片高度
img  = img.resize((width,height),Image.NEAREST)#进行缩放
output = Image.new("RGB", (width*(fontsize-backspace), height*(fontsize-backspace)), (255, 255, 255))#新建空白画布
drawBrush = ImageDraw.Draw(output)#绑定画刷
font=ImageFont.truetype("simkai.ttf",fontsize)#定义字体

#循环处理缩放后input的每一个像素
for i in range(height):
    for j in range(width):
       drawBrush.text((j*(fontsize-backspace),i*(fontsize-backspace)), get_char(*img.getpixel((j,i))), (0,0,0),font=font)#在output画布上写字
	   
output.show()#使用默认工具打开图片
img.convert("1").save("temp.jpg")#暂存文件
output.save("output.jpg")#保存生成的图片到当前路径的output.jpg

1.1.4结果

1.2其他

这样的是先缩放后排的,还有一种是统计原图的,就是按照统计字符大小的区块的平均占黑比,然后使用字符代替,不过效果不怎么好

from PIL import Image,ImageDraw,ImageFont
import numpy

#因为这个需要不断调试,网上的算法千篇一律,出处https://blog.csdn.net/dpengwang/article/details/79076188
ascii_char  =list("MWN@QB%G$&8#ROgDKCH5S0EmdUAX693PZ2qVb4ewahkpF*Yosy[]cJ7un?f{LTx|}t<z)>v(1j=\+!Il/ri~-^;\",:`'._ ")
imgname = "input.jpg" #需要处理的文件名
fontsize=15      #几个像素缩成像素点 fontsize*fontsize为一个像素点为一个字符
backspace=0    #文字负间距,因为没有这个文字间距离太远
#网上千篇一律的算法,也找不到出处了,可能是图像处理的一个算法
def get_char(r,g,b,alpha= 256):
    length = len(ascii_char)
    gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
    unitcount  = (256.0+1)/length
    return  ascii_char[int(gray/unitcount)]
img  = Image.open(imgname)#打开文件
fontnumx=int(img.width/fontsize)#一行几个字符
fontnumy=int(img.height/fontsize)#一列几个字符
#img.convert("1").save("temp.jpg")#暂存文件二值化
output = Image.new("RGB", (img.width-fontnumx*backspace,img.height-fontnumy*backspace), (255, 255, 255))#新建空白画布
temp = Image.new("RGB", (fontnumx,fontnumy), (255, 255, 255))#新建空白画布,保存运行中间数据,用于调试
drawBrush = ImageDraw.Draw(output)#绑定画刷
font=ImageFont.truetype("simkai.ttf",fontsize)#定义字体

#循环处理缩放后input的每一个像素
for i in range(fontnumx):
    for j in range(fontnumy):
        #统计字符块区域的特征值
        rgb=numpy.array((0,0,0))
        for k in range(fontsize):
            for l in range(fontsize):
                rgb+=numpy.array(img.getpixel((i*fontsize+k,j*fontsize+l)));
        rgb=(int(rgb[0]/fontsize/fontsize),int(rgb[1]/fontsize/fontsize),int(rgb[2]/fontsize/fontsize))
        temp.putpixel((i,j),rgb)#每个字符特征储存起来
        drawBrush.text((i*(fontsize-backspace),j*(fontsize-backspace)), get_char(*rgb), (0,0,0),font=font)#在output画布上写字
temp.save("temp.jpg")
output.show()#使用默认工具打开图片
output.save("output.jpg")#保存生成的图片到当前路径的output.jpg

2.图片转文字图(方法二)

from PIL import Image,ImageDraw,ImageFont
import numpy as np
import matplotlib.pyplot as stage

#增加pyplot的中文支持
from pylab import *
mpl.rcParams['font.sans-serif'] = ['FangSong'] 

imgname = "input.jpg" #需要处理的文件名
zoom=1#缩放大小
fontsize=20      #几个像素缩成像素点 fontsize*fontsize为一个像素点为一个字符
backspace=2    #文字负间距,因为没有这个文字间距离太远
str="咖啡加两斤糖"

img  = Image.open(imgname)#打开文件
#加到舞台中
stage.figure("图片转文字图",figsize=(15,8))#舞台名字
stage.subplot(1,2,1),stage.title("原图"),stage.imshow(img)#显示原图到舞台
outputx=int(img.width*zoom)#输出图像的大小
outputy=int(img.height*zoom)
fontnumx=int(outputx/(fontsize-backspace))+1#一行几个字符
fontnumy=int(outputy/(fontsize-backspace))+1#一列几个字符
img=img.resize((outputx,outputy),Image.NEAREST)#缩放
output = Image.new("RGBA",(outputx,outputy), (0, 0, 0,0))#新建输出画布
drawBrush = ImageDraw.Draw(output)#绑定画刷
font=ImageFont.truetype("simkai.ttf",fontsize)#定义字体

for i in range(fontnumx):
    for j in range(fontnumy):
        drawBrush.text((i*(fontsize-backspace),j*(fontsize-backspace)),str[i%len(str)], (255,255,255,255),font=font)#在output画布上写字
output.paste(img,mask=output)#混合两张图片
#使用矩阵快速替换颜色(0,0,0,0)白色,为(255,255,255,255)透明色
data = np.array(output)#化为矩阵
r,g,b,a=data.T#获取RGB值
needreplace=(r == 0) & (g == 0) & (b == 0) & (a == 0)#取得交矩阵
data[...][needreplace.T] = (0,0,0,0)#符合条件替换
output =Image.fromarray(data)#读出数据

stage.subplot(1,2,2),stage.title("输出"),stage.imshow(output)#显示处理结果到舞台
stage.show(True)
#output.show()#使用默认工具打开图片
output.save("output.png")#保存生成的图片到当前路径的output.jpg

很快发现了ImageDraw.Text方法不是打印的纯色导致合成颜色有损失,于是改进

from PIL import Image,ImageDraw,ImageFont
import numpy as np
import matplotlib.pyplot as stage

#增加pyplot的中文支持
from pylab import *
mpl.rcParams['font.sans-serif'] = ['FangSong'] 

#Config配置
imgname = "input.jpg" #需要处理的文件名
zoom=1#缩放大小
fontsize=20      #几个像素缩成像素点 fontsize*fontsize为一个像素点为一个字符
fontweight=0     #这个没什么用(或者是我不知道具体用法,还是字体没有粗体)
backspace=2    #文字负间距,因为没有这个文字间距离太远
str="给我的咖啡来两斤糖"  #构成输出图片的字
fontname="simkai.ttf"  #字体名称,在C://windows/fonts下
isshow=True    #是否展示舞台

img  = Image.open(imgname)#打开文件
#加到舞台中
if (isshow):
    stage.figure("图片转文字图",figsize=(15,8))#舞台名字
    stage.subplot(1,2,1),stage.title("原图"),stage.imshow(img)#显示原图到舞台
outputx=int(img.width*zoom)#输出图像的大小
outputy=int(img.height*zoom)
fontnumx=int(outputx/(fontsize-backspace))+1#一行几个字符
fontnumy=int(outputy/(fontsize-backspace))+1#一列几个字符
img=img.resize((outputx,outputy),Image.NEAREST)#缩放
output = Image.new("RGBA",(outputx,outputy), (0, 0, 0,0))#新建输出画布 000黑色 0全透明
drawBrush = ImageDraw.Draw(output)#绑定画刷
font=ImageFont.truetype(fontname,fontsize,index=fontweight)#定义字体

for i in range(fontnumx):
    for j in range(fontnumy):
        drawBrush.text((i*(fontsize-backspace),j*(fontsize-backspace)),str[i%len(str)], (255,255,255,255),font=font)#在output画布上写字
#因为text画的字不纯,我们还要二值化
imgdata = np.array(img)#图片化为矩阵
outdata = np.array(output)#输出化为矩阵
r,g,b,a=outdata.T#获取rgba矩阵
needreplace=(r != 0) & (g != 0) & (b != 0) & (a != 0)#进行条件矩阵运算
imgdata=np.insert(imgdata,3,255,axis=2)#因为原来的图没有透明通道插个0当alpha
outdata[...][needreplace.T] = imgdata[...][needreplace.T]#替换字体部分
output =Image.fromarray(outdata)#写入输出图片
if (isshow):
    stage.subplot(1,2,2),stage.title("输出"),stage.imshow(output)#显示处理结果到舞台
    stage.show(True)
#output.show()#使用默认工具打开图片
output.save("output.png")#保存生成的图片到当前路径的output.jpg

3.Gif处理

看着来吧。。反正读帧处理保存就行了

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值