惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Latest news
Latest news
T
Troy Hunt's Blog
V
Vulnerabilities – Threatpost
L
LINUX DO - 热门话题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
V
V2EX
博客园 - 司徒正美
B
Blog RSS Feed
AWS News Blog
AWS News Blog
MyScale Blog
MyScale Blog
Scott Helme
Scott Helme
Cisco Talos Blog
Cisco Talos Blog
Last Week in AI
Last Week in AI
NISL@THU
NISL@THU
博客园 - Franky
P
Proofpoint News Feed
博客园_首页
C
CERT Recently Published Vulnerability Notes
雷峰网
雷峰网
S
Schneier on Security
P
Proofpoint News Feed
Hugging Face - Blog
Hugging Face - Blog
G
GRAHAM CLULEY
博客园 - 三生石上(FineUI控件)
月光博客
月光博客
WordPress大学
WordPress大学
The Hacker News
The Hacker News
T
Threatpost
阮一峰的网络日志
阮一峰的网络日志
A
Arctic Wolf
Microsoft Azure Blog
Microsoft Azure Blog
T
The Exploit Database - CXSecurity.com
Engineering at Meta
Engineering at Meta
罗磊的独立博客
T
The Blog of Author Tim Ferriss
D
Darknet – Hacking Tools, Hacker News & Cyber Security
I
Intezer
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
K
Kaspersky official blog
SecWiki News
SecWiki News
云风的 BLOG
云风的 BLOG
美团技术团队
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - 【当耐特】
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Security Latest
Security Latest
C
Cyber Attacks, Cyber Crime and Cyber Security
B
Blog
S
Security Affairs

VnYzm的博客

游戏玩后感:ReLief:献给亲爱的你 我的周边(谷子)分享 游戏玩后感:Kanon 简谱:致真实的你 《Rust中常见的有关生命周期的误解》学习笔记 简谱:StarMap 简谱:かく咲きたらばいと恋ひめやも 简谱:东风 简谱:无法诉说的思念 简谱:Girlish 游戏玩后感:时钟机关的Layline 简谱:风之琶音 简谱:星空的记忆 简谱:因为遇见了你 简谱:月童 番茄简谱脚本转调器 游戏玩后感:青空下的约定:Refine 游戏玩后感:在这苍穹展翅 书籍读后感:控制论与科学方法论 游戏玩后感:恋爱表达式 游戏玩后感:樱之诗 MLIR-tutorial学习笔记 游戏玩后感:潜伏之赤途 游戏玩后感:纯爱咖啡厅:帕露菲重制版 游戏玩后感:智以泪聚 游戏玩后感:初雪樱 游戏玩后感:告别回忆:从今以后 游戏玩后感:梦灯花 游戏玩后感:金辉恋曲四重奏 游戏玩后感:五彩斑斓的世界 昇腾310P使用记录 游戏玩后感:AIR 游戏玩后感:弹丸论破 游戏玩后感:流景之海的艾佩莉亚 Xilinx_HLS上板过程记录 游戏玩后感:告别回忆2 游戏玩后感:恋爱绮谭 Faiss和Rapidsai_Raft使用记录 游戏玩后感:近月少女的礼仪 游戏玩后感:樱色之云,绯色之恋 游戏玩后感:幸运草的约定 游戏玩后感:星之梦、候鸟和丸子与银河龙 游戏玩后感:白色相簿2 Windows上使用VTune分析PyTorchExtension调用的Cpp程序 SpinalHDL上板过程记录 游戏玩后感:仰望夜空的星辰 最简单的算卦方法之一:梅花易数法 游戏玩后感:苍之彼方的四重奏 krkr引擎解包工具介绍 自定义CUDA实现PyTorch算子的四种简单方法 游戏玩后感:星空的记忆 游戏玩后感:9nine 游戏玩后感:AtriMyDearMoments 游戏玩后感:极限脱出 游戏玩后感:魔女的夜宴 SSH实现多跳代理 动漫观后感:向山进发 flv重封装H264、AAC流 动漫观后感:夏日重现 CSP模板 游戏玩后感:海沙风云 动漫观后感:灵能百分百 游戏玩后感:交响乐之雨 游戏玩后感:爱上火车LastRun 游戏玩后感:LittleBustersEX 游戏玩后感:SummerPockets 游戏玩后感:逆转裁判 Ultra96V2开发板简单使用 SpinalWorkshop实验笔记(三) SpinalWorkshop实验笔记(二) SpinalWorkshop实验笔记(一) PYNQ开发板上使用USB声卡+OSS兼容层播放音频 TestOS移植K210开发板 rCore-Tutorial-Book-v3学习笔记(七) 动漫观后感:凉宫春日的忧郁 rCore-Tutorial-Book-v3学习笔记(♭七) rCore-Tutorial-Book-v3学习笔记(六) rCore-Tutorial-Book-v3学习笔记(五) rCore-Tutorial-Book-v3学习笔记(四) rCore-Tutorial-Book-v3学习笔记(三) rCore-Tutorial-Book-v3学习笔记(二) rCore-Tutorial-Book-v3学习笔记(一) 游戏玩后感:RewritePlus MIT-6.S081-2020实验(xv6-riscv64)十一:net MIT-6.S081-2020实验(xv6-riscv64)十:mmap MIT-6.S081-2020实验(xv6-riscv64)九:fs MIT-6.S081-2020实验(xv6-riscv64)八:lock MIT-6.S081-2020实验(xv6-riscv64)七:thread MIT-6.S081-2020实验(xv6-riscv64)六:cow MIT-6.S081-2020实验(xv6-riscv64)五:lazy MIT-6.S081-2020实验(xv6-riscv64)四:traps MIT-6.S081-2020实验(xv6-riscv64)三:pgtbl MIT-6.S081-2020实验(xv6-riscv64)二:syscall 动漫观后感:吹响吧上低音号 MIT-6.S081-2020实验(xv6-riscv64)一:util 快速生成网络mp4视频缩略图技术 用plantuml画图示例 QQ缩略图和大图不同实现 动漫观后感:命运石之门 使用OpenCV对图片进行特征点检测和匹配
Python制作字符图片
VnYzm · 2020-08-17 · via VnYzm的博客

字符图片,即纯使用字符构造出一幅图片。关于这个,网上的教程和程序已经非常多了,都是使用不同复杂程度的字符模拟图片的灰度(比如字符’@‘就比字符’,’复杂,但是我要做的是像这样的:(原图是星之卡比)

即使用斜杠、减号等符号围出图案的边缘构造图片,和Linux下的figlet、toilet等程序效果类似,但是这两个程序只能构造艺术字,这个程序能够处理任意图片,因此在此分享一下。

首先,要用符号围出图案的边缘,需要能够知道图案的边缘在哪。这个可以用OpenCV库里的Canny边缘检测函数检测出来。之后就是研究如何用字符围出来,我采用了像素比较的方法,将图片分成一定数量相同大小的子图片,对于每个子图片,我将其和用到的所有字符的图片计算一个“欧几里得距离”(即所有像素差值的平方和),选取一个差值最小的字符作为这个像素对应的字符。

程序中还有两点细节,一是我做边缘检测前后各做了一次放缩,第一次是为了方便边缘检测,第二次是适应不同的字符拟合需求,有的时候需要尽量少的字符,则需要在拟合前把图片缩小,有时希望拟合的效果更好,这时需要在拟合前把图片放大;二是为了防止子图片中边缘的像素点偏离图片中心,导致拟合出现错误,所以我在比较前把字符图片和边缘像素点都对齐到图片中心。

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

first_scale = 1 # 第一次放缩倍数
detection_strength = 80 # 边缘检测强度
second_scale = 1 # 第二次放缩倍数
block_width = 10 # 子图片宽
block_height = 25 # 子图片长,可以通过调整这两个参数适应不同显示环境字符的高矮胖瘦

img = cv2.imread('Kirby.jpg')
img = cv2.resize(img, (0, 0), fx=first_scale, fy=first_scale) # 第一次放缩
img = cv2.Canny(img, detection_strength, detection_strength * 3) # 边缘检测
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
img = cv2.dilate(img, kernel) # 膨胀边缘检测后的图片,让边缘清晰完整
img = cv2.resize(img, (0, 0), fx=second_scale, fy=second_scale) # 第二次放缩
chars = ['/', '\\', '(', ')', '|', '-', ' '] # 用到的字符
chart = {}
font = ImageFont.truetype('C:\\Windows\\Fonts\\simhei.ttf', 20) # 这里指定字符图片的字体为黑体,可换成别的
for i in chars:
    if i != ' ':
        chart[i] = np.zeros((20, 10), np.uint8)
        t = Image.fromarray(chart[i])
        draw = ImageDraw.Draw(t)
        draw.text((0, 0), i, font=font, fill=255) # 这里用PIL制作字符图片,其绘制字符的函数比OpenCV好控制
        chart[i] = np.array(t)
        chart[i] = cv2.resize(chart[i], (block_width, block_height)) # 把字符图片缩放为子图片的大小
        t = np.where(chart[i] > 0)
        y1, y2 = np.min(t[0]), np.max(t[0])
        x1, x2 = np.min(t[1]), np.max(t[1])
        w = x2 - x1 + 1
        ws = (block_width - w) // 2
        h = y2 - y1 + 1
        hs = (block_height - h) // 2
        t = np.zeros((block_height, block_width), np.int32)
        t[hs:hs + h, ws:ws + w] = chart[i][y1:y2 + 1, x1:x2 + 1] # 把字符实际像素对齐到图片中心
        chart[i] = t
    else:
        chart[i] = np.zeros((block_height, block_width), np.int32)
s = ''
for i in range(0, img.shape[0] - block_height, block_height):
    # 如果显示图片的地方默认有行距,比如单倍行距,则可以把上面这句话改成for i in range(0, img.shape[0] - block_height, block_height * 2):
    for j in range(0, img.shape[1] - block_width, block_width): # 枚举子图片
        mn = 0x3fffffff
        mx = ' '
        block = img[i:i + block_height, j:j + block_width]
        t = np.where(block > 0)
        if t[0].shape[0] != 0 or t[1].shape[0] != 0:
            y1, y2 = np.min(t[0]), np.max(t[0])
            x1, x2 = np.min(t[1]), np.max(t[1])
            w = x2 - x1 + 1
            ws = (block_width - w) // 2
            h = y2 - y1 + 1
            hs = (block_height - h) // 2
            t = np.zeros((block_height, block_width), np.int32)
            t[hs:hs + h, ws:ws + w] = block[y1:y2 + 1, x1:x2 + 1] # 将子图片边缘像素对齐到图片中心
            for k in chars:
                a = np.sum((t - chart[k]) ** 2) # 计算欧几里得距离(省略开方)
                if a < mn:
                    mn = a
                    mx = k
        s += mx
    s += '\n'
print(s)
pyplot.imshow(img, cmap='gray')
pyplot.show()