RGB色转为灰度色算法-img2ascii_char

一、基础
  对于彩色转灰度,有一个很著名的心理学公式:
Gray = R0.299 + G0.587 + B0.114
二、整数算法
  而实际应用时,希望避免低速的浮点运算,所以需要整数算法。
  注意到系数都是3位精度的没有,我们可以将它们缩放1000倍来实现整数运算算法:
Gray = (R
299 + G587 + B114 + 500) / 1000
  RGB一般是8位精度,现在缩放1000倍,所以上面的运算是32位整型的运算。注意后面那个除法是整数除法,所以需要加上500来实现四舍五入。
  就是由于该算法需要32位运算,所以该公式的另一个变种很流行:
Gray = (R30 + G59 + B11 + 50) / 100
  但是,虽说上一个公式是32位整数运算,但是根据80x86体系的整数乘除指令的特点,是可以用16位整数乘除指令来运算的。而且现在32位早普及了(AMD64都出来了),所以推荐使用上一个公式。
三、整数移位算法
  上面的整数算法已经很快了,但是有一点仍制约速度,就是最后的那个除法。移位比除法快多了,所以可以将系数缩放成 2的整数幂。
  习惯上使用16位精度,2的16次幂是65536,所以这样计算系数:
0.299 * 65536 = 19595.264 ≈ 19595
0.587 * 65536 + (0.264) = 38469.632 + 0.264 = 38469.896 ≈ 38469
0.114 * 65536 + (0.896) = 7471.104 + 0.896 = 7472
  可能很多人看见了,我所使用的舍入方式不是四舍五入。四舍五入会有较大的误差,应该将以前的计算结果的误差一起计算进去,舍入方式是去尾法:
  写成表达式是:
Gray = (R
19595 + G38469 + B7472) >> 16
  2至20位精度的系数:
Gray = (R1 + G2 + B1) >> 2
Gray = (R
2 + G5 + B1) >> 3
Gray = (R4 + G10 + B2) >> 4
Gray = (R
9 + G19 + B4) >> 5
Gray = (R19 + G37 + B8) >> 6
Gray = (R
38 + G75 + B15) >> 7
Gray = (R76 + G150 + B30) >> 8
Gray = (R
153 + G300 + B59) >> 9
Gray = (R306 + G601 + B117) >> 10
Gray = (R
612 + G1202 + B234) >> 11
Gray = (R1224 + G2405 + B467) >> 12
Gray = (R
2449 + G4809 + B934) >> 13
Gray = (R4898 + G9618 + B1868) >> 14
Gray = (R
9797 + G19235 + B3736) >> 15
Gray = (R19595 + G38469 + B7472) >> 16
Gray = (R
39190 + G76939 + B14943) >> 17
Gray = (R78381 + G153878 + B29885) >> 18
Gray = (R
156762 + G307757 + B59769) >> 19
Gray = (R313524 + G615514 + B119538) >> 20
  仔细观察上面的表格,这些精度实际上是一样的:3与4、7与8、10与11、13与14、19与20
  所以16位运算下最好的计算公式是使用7位精度,比先前那个系数缩放100倍的精度高,而且速度快:
Gray = (R
38 + G75 + B15) >> 7
  其实最有意思的还是那个2位精度的,完全可以移位优化:
Gray = (R1 + G2 + B*1) >> 2


from PIL import Image

class Parse():

    def __init__(self, path, width=160, height=40):
        self._path = path
        self._width = width
        self._height = height
        self._text = ""

    def to_ascii_char(self, r, g, b):
        """ 将 RGB 转为灰度值,并且返回该灰度值对应的字符标记 """
        # 存储用于显示图片的字符种类。list 的最后一个元素是空格,表示将使用空格来代替原图片中灰度值最高的像素点
        # (在灰度图像中,灰度值最高为 255,代表白色,最低为 0,代表黑色)。
        ascii_char = list(r"$kB%8&WM#*oa&**@qwmZO0QLCJUYXzcvun<rjft/\|()1{}[]?-_+~<>i!lI;:,\ ^`'. ")
        # RGB 转为灰度值计算公式
        gray = int((19595 * r + 38469 * g + 7474 * b) >> 16)
        # ascii_char 中的一个字符所能表示的灰度值区间
        unit = 256.0 / len(ascii_char)
        return ascii_char[int(gray / unit)] #(gray/256.0)*len(ascii_char)
		# (gray/256.0)是ascii_char字符下标的比例系数

    def output(self):
        """ 输出结果 """
        image = Image.open(self._path)
        image = image.resize((self._width, self._height), Image.NEAREST)
        for h in range(self._height):
            for w in range(self._width):
                # [:3]表示取前三个值 R G B
                self._text += self.to_ascii_char(*image.getpixel((w, h))[:3])
            self._text += '\n'
        return self._text

    def save(self):
        """ 保存文件到本地 """
        with open("parse.txt", 'w') as f:
            f.write(self._text)

if __name__ == "__main__":
    parse = Parse("images\we.jpg")
    print("\n>> 你会挽着我的衣袖 我会把手揣进裤兜")
    print(parse.output())
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值