想获取本文完整代码和数据的下载链接,可关注微信公众号"R语言和Python学堂",并回复发文日期"20181129"。
所谓字符画,就是将图片中的像素用相应字符来代替,这样就是字符画了。
现在网上有很多小工具可实现这个功能,主要是基于Java和Python的。目前好像还没人用R来实现,因此在这篇博客,我将带领大家学习如何用R来生成字符画。
再来看个字符动画:
原动画
字符动画
1. 基本原理
将彩色图片转化为灰度图(像素值从0到255,其中0为黑色,255为白色)
设计一套字符集来对应各像素值,一般原则是:黑色对应最复杂字符(比如
&
或@
);白色对应最简单字符(比如.
或空格)根据彩色图片的RGB各通道的像素值来给字符上色
RGB色彩模式是通过对红(R)、绿(G)、蓝(B)三个颜色通道的叠加来得到各式各样的颜色的,常用的是8位图(各通道均为256等级,数值从0, 1, 2, ...直到255)。灰度图只含一个通道,不含色彩信息,就是我们平时看到的黑白照片,通常也划分为0到255共256个级别,其中0最暗(全黑),255最亮(全白)。在ImageMagick中,从彩色图片中的RGB值到灰度值Gray转换公式默认为:
Gray = 0.212656*R + 0.715158*G + 0.072186*B
比如我们用{'&', '#', 'w', 's', 'k', 'd', 't', 'j', 'i', '.', ' '}这11字符来作为我们的字符集,你也可以根据自己的喜好来选择。我们的字符集容量为11,一个字符对应的像素区间宽度为 256/11≈23。
灰度值与字符集的对应关系为:
[0, 23) '&' [23, 46) '#' [46, 69) 'w' ...... ...... [209, 232) '.' [232, 255] ' '
2. R实现
对于图片处理,我们用R的Magick
包来处理,其功能非常强大,它实际上是ImageMagick的功能接口。ImageMagick可能是当今最全面的开源图像处理库,支持许多常见格式( png、JPEG、tiff、pdf等)和操作(旋转、缩放、裁剪、修剪、翻转、模糊等)。
对于图片转字符画的R实现,我将其封装成一个叫image2chars
的函数,其使用说明可参考函数内部的注释,函数代码如下:
library(magick) # 加载magick包image2chars <- function(pathIn='', pathOutTxt=NULL, pathOutImg=NULL, jpg_quality=80, width=100, chars=c('&','#','w','s','k','d','t','j','i','.', ' '), isColor=FALSE){ ##### 参数 # pathIn: 原始图片的路径,支持各种格式 # pathOutTxt: 字符文本的输出路径,默认与原始图片在同一文件夹下,只是后缀为.txt;你也可指定其他路径 # pathOutImg: 字符图片的输出路径,默认与原始图片在同一文件夹下,只是后缀为.jpg;你也可指定其他路径 # jpg_quality: 字符图片的质量,范围0-100,越大图片越清晰,默认为80 # width: 字符文本的宽度,默认为100,即一行100个字符;字符图片的尺寸也与其成正比 # chars: 字符集,可自定义;默认为'&','#','w','s','k','d','t','j','i','.', ' '共11个字符 # isColor: 字符图片是否为彩色,默认为黑白字符图片 ##### 返回值 # 无 img <- image_read(pathIn) # 读入图片 gray <- image_convert(img, colorspace='gray') # 转为灰度图 rgb <- image_convert(img, colorspace='rgb') # 转为rgb图 ## 修改图片尺寸 gray <- image_resize(gray, paste0(width,'x')) rgb <- image_resize(rgb, paste0(width,'x')) ## 获取图片灰度值矩阵,并将各像素值对应于相应字符 gray <- as.integer(image_data(gray))[, , 1] w <- ncol(gray) # 图片宽度 h <- nrow(gray) # 图片高度 index <- findInterval(c(gray), seq(0, 255, length.out=length(chars)+1), rightmost.closed=T) labels <- chars[index] labels_mat <- matrix(labels, ncol=w) ## 输出字符文本,并保存成文件 if(is.null(pathOutTxt)) pathOutTxt <- paste0(pathIn,'.txt') # 文本文件名,与输入图片文件名一致,只是后缀为.txt write.table(labels_mat, pathOutTxt, quote=F, row.names=F,col.names=F) ## 绘制字符图片,给相应字符着色,并保存成文件 if(isColor){ rgb <- as.integer(image_data(rgb)) r <- rgb[, , 1] # red通道像素矩阵 g <- rgb[, , 2] # green通道像素矩阵 b <- rgb[, , 3] # blue通道像素矩阵 cols <- rgb(c(r), c(g), c(b), maxColorValue=255) # 转化为颜色表示 } if(is.null(pathOutImg)) pathOutImg <- paste0(pathIn,'.jpg') # 图片文件名,与输入图片文件名一致,只是后缀为.jpg jpeg(pathOutImg, width=16*w, height=16*h, quality=jpg_quality) op <- par(mar=c(0, 0, 0, 0)) plot(0, xlab='', ylab='', asp=1, xlim=c(0,w), ylim=c(0,h), xaxs="i", yaxs="i", type='n', axes=FALSE) grid <- expand.grid(y=h:1-0.5, x=1:w-0.5) # 各字符位置 if(isColor){ text(grid$x, grid$y, labels, cex=1.5, col=cols) # 绘制彩色字符 } else { text(grid$x, grid$y, labels, cex=1.5) # 绘制黑白字符 } par(op) dev.off() }
来测试一下:
黑白字符图片
pathIn <- 'messi.jpg'image2chars(pathIn, width=80)
代码运行后,将生成两个文件messi.jpg.txt
和messi.jpg.jpg
(见下图),分别为字符文本和字符图片。
其中字符图片为:
彩色字符图片
pathIn <- 'tiger.jpg'image2chars(pathIn, width=80, isColor=TRUE)
其原图为:
自定义字符
custom_chars <- c('@','%','M','G','a','l','-') ##自定义字符集pathIn <- 'cartoon.jpg'image2chars(pathIn, width=80, chars=custom_chars)
其原图为:
作者:R语言和Python学堂
链接:https://www.jianshu.com/p/c95c325749b1