本文主要是介绍RGB色转为灰度色算法-img2ascii_char,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、基础
对于彩色转灰度,有一个很著名的心理学公式:
Gray = R0.299 + G0.587 + B0.114
二、整数算法
而实际应用时,希望避免低速的浮点运算,所以需要整数算法。
注意到系数都是3位精度的没有,我们可以将它们缩放1000倍来实现整数运算算法:
Gray = (R299 + 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 = (R19595 + G38469 + B7472) >> 16
2至20位精度的系数:
Gray = (R1 + G2 + B1) >> 2
Gray = (R2 + G5 + B1) >> 3
Gray = (R4 + G10 + B2) >> 4
Gray = (R9 + G19 + B4) >> 5
Gray = (R19 + G37 + B8) >> 6
Gray = (R38 + G75 + B15) >> 7
Gray = (R76 + G150 + B30) >> 8
Gray = (R153 + G300 + B59) >> 9
Gray = (R306 + G601 + B117) >> 10
Gray = (R612 + G1202 + B234) >> 11
Gray = (R1224 + G2405 + B467) >> 12
Gray = (R2449 + G4809 + B934) >> 13
Gray = (R4898 + G9618 + B1868) >> 14
Gray = (R9797 + G19235 + B3736) >> 15
Gray = (R19595 + G38469 + B7472) >> 16
Gray = (R39190 + G76939 + B14943) >> 17
Gray = (R78381 + G153878 + B29885) >> 18
Gray = (R156762 + G307757 + B59769) >> 19
Gray = (R313524 + G615514 + B119538) >> 20
仔细观察上面的表格,这些精度实际上是一样的:3与4、7与8、10与11、13与14、19与20
所以16位运算下最好的计算公式是使用7位精度,比先前那个系数缩放100倍的精度高,而且速度快:
Gray = (R38 + G75 + B15) >> 7
其实最有意思的还是那个2位精度的,完全可以移位优化:
Gray = (R1 + G2 + B*1) >> 2
from PIL import Imageclass Parse():def __init__(self, path, width=160, height=40):self._path = pathself._width = widthself._height = heightself._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 Bself._text += self.to_ascii_char(*image.getpixel((w, h))[:3])self._text += '\n'return self._textdef 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())
这篇关于RGB色转为灰度色算法-img2ascii_char的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!