如何用Python挽救鑒黃師的職業生涯

首發:[Python] 如何挽救鑒黃師的職業生涯 - 集智

作者:Kaiser

01. ASCII藝術

ASCII的全稱是American Standard Code for Information Interchange,即美國信息交換標準碼。是由軍用電報編碼發展而來,並成為最通用的現代計算機編碼系統。

在顯卡還不能摧毀航母戰鬥群的年代,計算機還主要用來計算導彈彈道和衛星軌道,其圖形處理能力是非常弱的,甚至還不如今天高級一點的示波器。但這並不能阻止人類對美的追求,正如四萬年前的莽荒也沒有耽誤拉斯科洞窟壁畫的誕生。

在我剛上網那陣,有個流傳很廣的帖子,是教你觀看命令行里的《星球大戰》,而這部星戰正是由ASCII編碼中的字元構成的,這被稱作ASCII art

在斗圖代替打字、點播變成直播甚至VR/AR的今天,圖形的處理已經不再是瓶頸,反而成為了新的增長點。道高一尺魔高一丈,技術的進步也帶來了有害信息,比如廣大家長朋友們特別關注的色情信息。剛開始色情的鑒定是由人工完成的,李迪同志就是在《暴走大事件》中扮演鑒黃師唐馬儒而一炮走紅。

但是,基於人工智慧的圖像識別也在飛速進步,自動鑒黃已經投入實用,鑒黃師的職業前景就面臨著嚴重的威脅!

02. 字元畫

把一張照片轉換為字元畫,大致需要三步:

  1. 將圖片尺寸壓縮到字元畫所能接受的量級;
  2. 彩色圖轉換為灰度圖,灰度是一個0-255的數值;
  3. 建立灰度值與字符集之間的映射關係。

早年間以上步驟還需要專門做一個小軟體來完成,而現在只需要簡單的代碼就可以直接在瀏覽器中實現。

因為字元畫的本質是「字元」,可以用文本編輯器打開,對於計算機來說,他們和其他的字元沒有任何區別,「畫」的性質只是由人類的想像力後天賦予的。所以,如果你用字元畫的形式傳播春宮圖,還是需要唐馬儒。

03. Python擴展庫

針對字元畫生成的基礎功能,Python已經內置了很多優秀的擴展庫,可以在此基礎上直接調用,而無需重複製造輪子。

  • 圖庫PIL(Python Imaging Library)

    基本的圖像處理功能。

  • 網庫urllib

    獲取網路資源,如下載網上的圖片。

from PIL import Image # 圖像處理模塊nfrom urllib import request #網路請求模塊n

沒有必要把0-255的灰度值一一對應為不同的字元,一般十幾個也就足夠了。這裡做如下定義:

ASCII_CHARS = [ , #, ?, %, ., +, ., *, :, ,, @]n

這裡將最低的灰度段映射為 (空格),也就是原圖中空白或接近空白的部分,在字元畫中也會會變成空白;而原圖的黑點則變成@。

讀者朋友可以在後文的開放代碼環境中想要定義自己的字元,並可以傳入任意網路圖片做實驗。

04. 圖片預處理

4K屏已經逐漸普及,現在差不多的電腦顯示器也能支持2K解析度,如果把每個像素點都變成一個字元,那出來的圖片實在是太大了。

所以首先要對源圖片進行壓縮,再轉換為灰度模式,即拋出色彩信息。

# 壓縮圖片ndef scale_image(image, new_width=60):n (original_width, original_height) = image.size # 獲取原圖尺寸n aspect_ratio = original_height/float(original_width) * 0.5 # 計算高寬比,因為輸出文本有2倍行距,所以乘0.5維持高寬比n new_height = int(aspect_ratio * new_width)n new_image = image.resize((new_width, new_height))n return new_imagenn# 灰度模式ndef convert_to_grayscale(image):n return image.convert(L) # 調用image對象自己的.convert()方法n

05. 圖片到字元

然後是建立圖片(壓縮後)像素點到字符集的映射關係。

def map_pixels_to_ascii_chars(image, range_width=25):nn # 將每個像素根據其灰度值映射為一個字元,每個字元對應25個灰度值n pixels_in_image = list(image.getdata()) # 獲取原圖灰度值列表 n pixels_to_chars = [ASCII_CHARS[int(pixel_value/range_width)] for pixel_value in pixels_in_image]n # 對於每個像素點,將其灰度值轉換為列表ASCII_CHARS的索引n return "".join(pixels_to_chars)n

最後綜合前面幾個函數,以文本形式輸出字元畫。

def convert_image_to_ascii(image, new_width=60):n image = scale_image(image, new_width) # 調用scale_image()函數,壓縮圖片n image = convert_to_grayscale(image) # convert_to_grayscale()函數,轉換為灰度圖nn pixels_to_chars = map_pixels_to_ascii_chars(image) # 映射至字符集n len_pixels_to_chars = len(pixels_to_chars) # 獲取字符集長度nn image_ascii = [pixels_to_chars[index: index + new_width] for index in range(0, len_pixels_to_chars, new_width)]nn return "n".join(image_ascii)nnndef handle_image_conversion(image_filepath, new_width=60):n image = Image.open(image_filepath) # Image.open()打開源圖片n image_ascii = convert_image_to_ascii(image) # 調用上面的convert_image_to_ascii()函數n print(image_ascii) # 輸出字元畫n

06. 圖源採集

接下來我們可以將任意圖片轉換為字元畫看看效果,為了充分發揚互聯網精神,目前僅支持具有網路地址的圖片(其實是圖片上傳系統還沒做好)。

下面來看一個實例,將一張QQ企鵝的圖標轉換為字元畫。

from urllib import requestnnimage_file_path = image2ascii.jpg # 圖片的本地名稱nimage_url = "http://upload.wikimedia.org/wikipedia/en/thumb/9/9c/Tencent_QQ.png/64px-Tencent_QQ.png" # 圖片的網路地址nrequest.urlretrieve(image_url, image_file_path) # 將網路圖片下載到本地,並重命名nhandle_image_conversion(image_file_path) # 啟動handle_image_conversion()這個總函數n

原文的在線運行效果圖

07. 開放空間

上節的例子仍然保留了默認的字符集和默認圖像寬度60,接下來的部分留給讀者自由發揮,可以通過修改如下參數獲得自己的字元畫:

  • new_width:字元畫的尺寸(寬的字元數)
  • ASCII_CHARS:字符集
  • image_url:網路圖片地址,就是你想要轉換的圖片

操作示例:當你在網上看到一張圖片,右鍵-複製圖片地址。

將圖片地址賦值予變數image_url,點擊運行(知乎上點不了)即可。

生成字元畫粘貼到Sublime里的效果圖:

最後的在線調試運行代碼部分需訪問原文,地址:[Python] 如何挽救鑒黃師的職業生涯 - 集智

推薦閱讀:

TAG:Python | ASCII | 字符画 |