首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >图片转ASCII字符图案的原理(可调整亮度对比度 宽高度)

图片转ASCII字符图案的原理(可调整亮度对比度 宽高度)

原创
作者头像
仁扬
发布于 2023-06-22 09:25:42
发布于 2023-06-22 09:25:42
3930
举报
文章被收录于专栏:仁扬笔记仁扬笔记

来, 先看效果哈哈哈哈!

演示地址: http://ascii-picture.imlht.com/

代码语言:txt
AI代码解释
复制
            "\` """        . "\`"""""""""""""""""""w$@w"""""""""""""""""""                                      
                   """""""       \`""""""""""""$$$$$$$$$00$$0"""""""""""""""""""                                
                            """"""""""""""""$$$$$$$$$$$$$$$$$$$$0""""""""""""""""""""                          
                                    """""""$$$$$$$$$$$$$$$$$$$$$$$$""""""0(""""""""""""""""                    
                                          $$$$$$$$$$$$$$$$$$$$$$$$$$00&0("""""""""""""""""""""""               
                         \`               $$$$$$$$$$$$$$$$$$$$$$$$$$$$$&hLLLL(~~"""""""""""""""""""             
""".                             """""" $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$@0000000L""""""""""""""\`           
""""""""""""""""                     ""0$$$$$$$$$0("(0$$$$$$$$$$$$$$$$$$$$$$$$$$$@&&h0000v"""""""""".          
"""""""""""""""""""""""""".          ""$$$$$$$$0"""""v00$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$000(""""""""            
"""""""""""""""""""""""""""""""""""""""$$$$$$0""""""""""(00h$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$w0"""               
"""""""""""""""""""""""""""""""""""""""$$$$00$$0""($$$$$$$"""$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$h"            
""""""""""""""""""""""""""""""""""""""0$$$$$$$$0"v$$$$0"(&0"""$$$$$$$$$$$$$&""$$$$$$$0""h$$$&h0w&$$$$"         
"""""""""""""""(vv~~"""""""""""""""""00&$$"0""0&0"$$$$$$$""""""$$$$$$$$$$$$$""$"$$$$$v0""$0$$$$$h$$$$$""""w"""0
"""""""""""""""0"0(0000v"0000"""""""0w0w$$""$$$""""""v""~"""\`"""$$$$$$$$$$$(""""$$$$$$$""00"0$$h$&"~$$v""""""$@
   """""""""""("0"000"0"0000v"""""""0$$w$0 ""$"""\` ""      """""$$$$$$$$$$$""\`"""$$$$$$$0""0$$$($$(&$h"""""""$h
       """"""""~"""""0(0v0"00"""""""L$$h0     \`   ""0"    .""""""0$$$v$$$$$""  "0""$$$$0"""w$$$$$w"~""\`  """ @"
      """"""""""""~"""0v0000"""""""""$h&$    0 """"  $$""""""""""w$$0"$$$$$""""""0"" " """"v$$$$$$ .       " w"
      """""""""""0""""""""0""""""""""0$$@"""$$$$$$$$$""0&@&&"""""&0""$$$$$$$$$$$$$$$$$0"""L0"&$@""         " 0L
      ""  """"""""(0"""L~"""""""""""""0w$""L0"""$$" \`"~0$$$&"""""$$$$$$$$$&$$$$$$$$$$$$$$$$$$"@""             "
      """""""""""""0""""""""""""""""""""""""""($$$$$$$00$hL~"""""$$$$$$$$$w@$$$$$$$$$$&$$$$$$0$&"              
""""""""""""""""""""""""""""""""""""""""""""""$$0@$$$$0w&0~vw&hwh@$$$$$$$""h$$ $$ $$$$"$$$$$~$"@"              
 """"""""""""""""""""""""""""""""""""""""""""" v"""""~"0h0$$$$@~v($$$$$$$""w$$$$   $$$0"$$$$&"h$"              
"""""""""""""""""""""""""""""""""""""""""""""""0"(@$$$wh&$$$$$@v""~$$$$$""""$$$$$jj$$$ "$$$$. 0 "      ;       
""""""""""""""""""""""""""""""""""""""""""\` """~$$$0"""(&$$$$$$$"""$$$"     0$$$$$$$$$$ 0$$$$" ""     ;$$;"""""
"""""""""""""""""""""""""""""""""""""""""""" """""""L0$$$$$$$$$$$0""$               "L00w$$$$$.$L" """"$$,"""""
""""""""""""""""""""""""""""""""""""""""""""\` "0w$$$$$$$$$$$$$$$$@"""                           "" """"$$$"$"\`"
""""""""""""""""""""""""""""""""""""""""""""""  ""$$$Lh$$$$$$$$$$$&""                             "("0@@"""""""
"""""""""""""""""""""""""""""""""""""""""""""""   ." ""&$$$$$$$$$$$$$                              $$0"$$""""""
""""""""""""""""""""""""""""""""""""""""""""""""  .   "&$$$$$$$$$$$$$                              $$$$$$$""("$
"""""""""""""""""""""""""""""""""""""""""""""""""     "L$$$$$$$$$$$$w                               $$$$$$"@$$$
"""""""""""""""""""""""""""""""""""""""""""""          "$$$$$$$$$$$$"                                &$$$""@$$$
""""""""""""""""""""""""""""""""""""""""0""             $$$$$$$$$$$$                                 "$$~"""$$$
"""""""""""""""""""""""""""""""""""""""""              ."$$$$$$$$$$h                                  &$,$##$$0
"""""""""""""""""""""""""""""""""""""""                 ""$$$$$$$$@"                                   0~$-,$$$
"""""""""""""""""""""""""""""""""""""            ".     ..$$$$$$000"                         "     "   "$h""$0$
"""""""""""""""""""""""""""""""""""              ""        $$$$0h0$                         "" ""  "    $$$ """
""""""""""""""""""""""""""""""""""               ""        "$$$$$$$          "              """"  ""    $$$$0""
"""""""""""""""""""""""""""""""""""       "      ""         $$$$$$$         "              """  """     "$$$""0
"""""""""""""""""""""""""""&"""""""              ""         "$$$$$$       ""              ."".  .".      $$$00h

平时看代码会看到很多标点符号的字符拼起来的图案, 特别有趣, 像kong(一个高性能API网关), 除了源代码里面有图案, 命令行也藏了彩蛋:

代码语言:txt
AI代码解释
复制
Kong, the biggest ape in town

    /\  ____
    <> ( oo )
    <>_| ^^ |_
    <>   @    \
   /~~\ . . _ |
  /~~~~\    | |
 /~~~~~~\/ _| |
 |[][][]/ / [m]
 |[][][[m]
 |[][][]|
 |[][][]|
 |[][][]|
 |[][][]|
 |[][][]|
 |[][][]|
 |[][][]|
 |[][][]|
 |[|--|]|
 |[|  |]|
 ========
==========
|[[    ]]|
==========

上面这个图案, 只是停留在外形轮廓上, 而我今天要玩的会深入一点: 基于图片的灰度值来生成图案. 此时的图片不单单有轮廓, 还有光影效果, 也就是素描中提及的黑白灰.

原理实际上挺简单的, 在白色背景下, 字符 $ 会有比较大面积的黑, 而字符 + 相对就淡了很多, 毫无疑问, 空格就是纯白了. 所以, 只要把一些字符按照 , , 排序, 并把这些字符映射为 0-255 的灰度值, 就可以根据图片生成更生动的字符画了.

至于这些字符按照灰度排序, 已经有人帮我们做好了, 具体可以查看这个Demo, 是用 Python 写的:

代码语言:Python
AI代码解释
复制
ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")

看到这里, 是时候拿起 Python 干起来了! 可以照着链接在自己电脑跑一下, 制作一些白色背景的表情包, 但如果是照片的话会发现很糊, 根本看不清, 于是我拿出神器 Photoshop 调整了 亮度对比度, 尽量调高点, 生成的图案会清晰一些.

每次都去 Photoshop 调整真是繁琐, 每次失败了, 得重新用命令行生成, 然后看生成的图案怎么样, 一直重复这个步骤...而且宽度和高度都需要手工指定...所以萌生了这个想法: 把这些重复繁琐的操作, 交给界面去处理好了! 所以后面的代码都是用 JavaScript 实现的.

OK, 我们先扯回来, 说下灰度的映射算法, 也是很容易理解的, 上面的字符一共有 69 个, 0-255 一共有 256 个字符, 计算出比率 ratio 然后直接把字符取出来即可:

代码语言:JavaScript
AI代码解释
复制
/**
 * ASCII Charset
 *
 * @type {String}
 */
const charset = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ";

/**
 * 69/256
 *
 * @type {Number}
 */
const ratio = charset.length / 256;

/**
 * 颜色值转换为 ASCII 字符
 *
 * @param  {Number}   r        R
 * @param  {Number}   g        G
 * @param  {Number}   b        B
 * @param  {Number}   a        A
 * @param  {Number}   type     类型
 * @return {String}            ASCII 字符
 */
export const rgba_to_char = (r, g, b, a, type) => {
  if (a === 0) return ' ';
  r = Math.round(a / 255 * r);
  g = Math.round(a / 255 * g);
  b = Math.round(a / 255 * b);
  return charset[ Math.round( ratio * rgb_to_gray(r, g, b, type) ) ] || ' ';
};

根据灰度生成字符, 那灰度怎么来的? 扒了挺多资料, 总体来说有几个公式, 具体可以看这篇文章

Gray = R*0.299 + G*0.587 + B*0.114

上面的 Python 代码用的是这个公式, 参考知乎:

Gray = 0.2126 R' + 0.7152 G' + 0.0722 B'

还有另一种, 这个是我实验后发现的, 用这个方法生成的图案细节会多一些, 大家也可以试试看. 算法是比较复杂的, 基本原理是将 RGB 色彩转为 XYZ 色彩, 再从 XYZ 转到 Lab. Lab颜色空间中的L分量用于表示像素的亮度, 最小值是0(纯黑), 最大值是100(纯白), 而a表红绿, b表黄蓝. 我们需要的是灰度值算法, 所以只需L分量就可以了.

再加上平均值, 最大值, 只取绿色通道, 一共就有6种算法, 代码实现如下:

代码语言:JavaScript
AI代码解释
复制
/**
 * 颜色值转换为灰度
 *
 * @param  {Number} r    R
 * @param  {Number} g    G
 * @param  {Number} b    B
 * @param  {Number} type 类型
 * @return {Number}      灰度值
 */
const rgb_to_gray = (r, g, b, type) => {
  switch (type) {
    case 1:
      return g;
    case 2:
      return Math.max(r, g, b);
    case 3:
      return Math.round((r + g + b) / 3);
    case 4:
      return Math.round(0.299 * r + 0.587 * g + 0.114 * b);
    case 5:
      return Math.round(0.2126 * r + 0.7152 * g + 0.0722 * b);
    case 6:
      // https://github.com/antimatter15/rgb-lab/blob/master/color.js
      // https://github.com/markusn/color-diff/blob/master/lib/convert.js
      r /= 255;
      g /= 255;
      b /= 255;
      r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
      g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
      b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
      let x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
      let y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000;
      let z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
      x = (x > 0.008856) ? Math.pow(x, 1 / 3) : (7.787 * x) + 16 / 116;
      y = (y > 0.008856) ? Math.pow(y, 1 / 3) : (7.787 * y) + 16 / 116;
      z = (z > 0.008856) ? Math.pow(z, 1 / 3) : (7.787 * z) + 16 / 116;
      return Math.round(255 / 100 * ((116 * y) - 16));
  }
};

OK, 目前我们已经实现了彩色的像素值变成ASCII字符, 接下来要解决一个问题, 调整图像的亮度和对比度, 同样也是有公式的, 参考链接:

代码语言:JavaScript
AI代码解释
复制
bitmap() {
  return this.data.map((x, i) => {
    if ((i+1) % 4 === 0) {
      // alpha
      return x;
    }
    // http://blog.csdn.net/hbaizj/article/details/17376857
    const B = this.brightness / 100;
    const c = this.contrast / 100;
    const k = Math.tan( (45 + 44 * c) / 180 * 3.1416 );
    return [x - 127.5 * (1 - B)] * k + 127.5 * (1 + B);
  });
}

最后, 我们只需把用户选择的图片, 转换为 RGB 值, 加上亮度对比度, 宽度高度的变换, 就大功告成了:

代码语言:JavaScript
AI代码解释
复制
onchange() {
  const files = document.getElementById('file').files;
  if (!files || files.length === 0) return;
  const that = this;
  let fr = new FileReader();
  fr.onload = function (event) {
    let img = new Image();
    img.onload = function () {
      let c = document.createElement('canvas');
      if (!that.width && !that.height) {
        that.width = img.width;
        that.height = img.height;
      } else if (!that.width) {
        that.width = Math.round(img.width * (that.height / img.height));
      } else if (!that.height) {
        that.height = Math.round(img.height * (that.width / img.width));
      }
      c.width = that.width;
      c.height = that.height;
      let ctx = c.getContext('2d');
      ctx.drawImage(img, 0, 0, that.width, that.height);
      that.data = ctx.getImageData(0, 0, that.width, that.height).data;
    }
    img.src = event.target.result;
  }
  fr.readAsDataURL(files[0]);
}

完整的源码, 我放到 GitHub 上了, 求Star求Star求Star! 代码是用 Vue2 写的(上面的代码都是再里面摘出来的), 结合了饿了么前端框架做界面, 目前先这样, 有时间再调整下界面吧.

演示地址: http://ascii-picture.imlht.com/

文章来源于本人博客,发布于 2017-12-28,原文链接:https://imlht.com/archives/93/

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android开发:使用Java对手机截图图片进行任意区域的颜色对比度处理操作
开发项目过程中,对于手机屏幕截图,需要对获取到的截图的任意部分进行区域颜色对比度的识别操作,由此判定任意指定区域是否满足某对比度基本标准,但是该功能在网上任何地方都没有找到过Java方面的代码,于是根据RGB转换测试的原理:即获取每个像素点的RGB,通过RGB对比度定义公式进行像素点的集合换取。
程序员洲洲
2024/06/06
1760
Python3:图片转字符画
参考:https://www.shiyanlou.com/courses/370/labs/1191/document
py3study
2020/01/06
1.3K0
python 图片转字符串
鲸可落 python 图片转字符串 # -- coding=utf-8 -- from PIL import Image import argparse #命令行输入参数处理 parser = argparse.ArgumentParser() parser.add_argument('--file') #输入文件 parser.add_argument('-o', '--output') #输出文件 parser.add_argument('--width', type = int, def
AngelNH
2020/04/16
6100
python 小工具—图片转为字符txt
matinal
2023/10/13
3470
python 小工具—图片转为字符txt
Rust Wasm 图片转 ASCII 艺术
Image Crate 将图片加载完后,默认输出的 bytes 是一个解码后的原始数据,传递给 JS 后是无法正常使用的,需要对原始数据进行编码后,输出才行。
MikeLoveRust
2022/11/28
6330
Rust Wasm 图片转 ASCII 艺术
文字背景对比度contrast ratio的计算公式
MD规范里说:文本应该保持至少 4.5:1 (基于亮度值计算)的对比度以保持文本清晰;最佳对比度为 7:1。
Daotin
2022/05/09
1.7K0
文字背景对比度contrast ratio的计算公式
python3实现图片转字符画
用练习学习python3. #!/usr/bin/env python3 #-*- coding:utf-8 -*- from PIL import Image import argparse ''' argparse模块使得编写用户友好的命令行接口非常容易。程序只需定义好它要求的参数,然后argparse将负责如何从sys.argv中解析出这些参数。argparse模块还会自动生成帮助和使用信息并且当用户赋给程序非法的参数时产生错误信息。 使用步骤: 1、导入模块 import argparse 2、
py3study
2020/01/03
8500
图片:“给你五十行代码把我变成字符画!” 程序:“太多了,一半都用不完!”
哈喽,努力赚钱买生发水的大灰狼又来了,今天和大家分享一个简单又好玩的Python项目–“图片转字符画”。废话不多说,先上一个效果图迷惑一下众生。
灰小猿
2020/09/23
1.1K0
图片:“给你五十行代码把我变成字符画!” 程序:“太多了,一半都用不完!”
[UWP]使用Writeable​Bitmap创建HSV色轮
HSV都是一种将RGB色彩模型中的点在圆柱坐标系中的表示法,这种表示法试图做到比RGB基于笛卡尔坐标系的几何结构更加直观。HSV即色相、饱和度、明度(英语:Hue, Saturation, Value),又称HSB,其中B即英语:Brightness。
dino.c
2019/01/18
1.1K0
[UWP]使用Writeable​Bitmap创建HSV色轮
Java实现图片转字符输出示例demo
前面几篇博文介绍了使用jdk来对图片做一些有意思的转换,接下来我们再介绍一个有意思的玩法,直接根据图片,输出一个二维字符数组,实现用字符来实现绘画的场景
一灰灰blog
2021/12/06
9450
切片不够技术来凑
随着数据经度的提升,18级的切片有些场景已经不够用了,但是大部分在线的栅格切片最大级别还是18级,如果地图继续放大,有的框架(leaflet会,openlayers和mapboxGL不会)会存在没有底图的情况。为处理这种情况,本文通过node实现在级别大于18级的时候将18级的切片进行裁切,解决没有底图的问题。
牛老师讲GIS
2023/10/25
3170
切片不够技术来凑
震惊!字符还可以这样玩……
首先你想象一下,给你一张图片,然后用字符串表示出来,将图片隐藏在字符之中,再经过字符的某种规律才能显示出这副图片,是不是很激动,我们来看:
大家一起学编程
2021/03/29
4060
分享一个从图片中提取色卡的实现
最近在做“在线地图样式配置”的功能的时候,发现百度地图有个功能时上传一张图片,从图片中提取颜色并进行配图。本文就简单实现一下如何从图片中提取色卡。
牛老师讲GIS
2024/12/30
1620
分享一个从图片中提取色卡的实现
听说你用JavaScript写代码?本文是你的机器学习指南
选自GitHub 作者:Robin Wieruch 机器之心编译 JavaScript 是一种流行的高级编程语言,它被世界上的绝大多数网站所使用,也被所有主流浏览器所支持。随着深度学习的火热,越来越多
机器之心
2018/05/10
1.3K0
图片转字符画
字符画是一系列字符的组合,我们可以把字符看作是比较大块的像素,一个字符能表现一种颜色(暂且这么理解吧),字符的种类越多,可以表现的颜色也越多,图片也会更有层次感。
王强
2018/08/09
2.8K0
图片转字符画
小玩意|图片转ASCII
今天,我们来完成一个小玩意,将图片转成ASCII,最后使用Base64转换成灰色图。如,将图
孟君
2022/11/21
1.5K0
小玩意|图片转ASCII
Python简单又好玩的项目推荐!【持续更新】
最近在做Python项目开发的时候愣是发现了好多好玩的小项目,并且都是代码量较少容易上手的,所以今天就来和小伙伴分享一些Python从一行代码到三十行代码都有哪些好玩的项目。之后大灰狼也会在这里持续更新更多好玩的项目。
灰小猿
2020/09/23
1.2K0
Python简单又好玩的项目推荐!【持续更新】
基于 OpenCV 与 Java 两个语言版本实现获取某一图片特定区域的颜色对比度
对比度是指图像中不同区域之间的明暗差异程度,它是图像质量中的重要指标之一。除了颜色对比度之外,常见的对比度包括:
程序员洲洲
2024/06/07
5480
基于 OpenCV 与 Java 两个语言版本实现获取某一图片特定区域的颜色对比度
python【图片转字符画】,图片灰度值处理
理论很简单,就是对图片操作,这里需要用到PIL的python包,里面有很好用的图像处理功能。
全栈程序员站长
2021/04/07
1.2K0
2022年新年焰火代码
一、2022年新年焰火代码 本代码的所有者是海拥✘和海瞳✘ 1、2022年新年焰火用html+css+js代码写成的,非常的炫酷,想要源码,往下划。👇麻烦大家给我点个赞吧!有问题的话请私信我哦!!! <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>海拥 | 新年焰火</title> <link rel="shortcut icon" href="http://haiyong.site/wp-c
海曈
2022/11/14
7120
2022年新年焰火代码
相关推荐
Android开发:使用Java对手机截图图片进行任意区域的颜色对比度处理操作
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档