• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • Python極客項目編程之ASCII文本圖形

    標簽: 文本圖形  python


    前言

    ??ASCII文本圖形源頭是19世紀后期出現的打字機文本圖形。在20世紀60年代,計算機有了較弱的圖形處理硬件,ASCII被用于表示圖形。今天,ASCII文本圖形繼續作為因特網上的一種表現形式,你可以在網上找到各種創意的例子。


    一、學習目標及步驟

    ??這個項目用Python創建一個程序,從圖像生成ASCII文本圖形。該程序讓你指定輸出文本序列的寬度,并設置垂直比例因子。它也支持兩種灰度值到ASCII字符的映射:稀疏的10級映射和更精細校正的70級映射。
    ??要從圖像生成ASCII文本圖像,需要學習如何做到以下幾點:

    • 用Pillow將彩色圖像轉換成灰度圖像,它是Python的圖像庫(PIL)的一個分支;
    • 使用numpy計算灰度圖像的平均亮度;
    • 用一個字符串作為灰度值的快速查找表。
      下面是程序生成ASCII文本圖形的步驟:

      1.?將輸入的圖形裝成灰度;
      2.?將圖像分成M×N個小塊;
      3.?修正M(行數),以匹配圖像和字體的橫縱比;
      4.?計算每一個小塊圖像的平均亮度,然后為每個小塊查找合適的ASCII字符;
      5.?匯集各行的ASCII字符串,將他們打印到文件,形成最終圖像。

    二、代碼

    1.引入庫

    代碼如下(示例):

    import argparse
    import numpy as np
    from PIL import Image

    2.定義灰度等級和網格

    ??先定義兩種灰度等級作為全局值,分別是70級,10級,這兩個值保存為字符串,從最黑暗變到最亮,用于將亮度值轉換為ASCII字符。

    # 70 levels of gray
    gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^.y' "
    
    # 10 leves of gray
    gscale2 = "@%#*+=-:. "

    ??既然有了灰度梯度,就可以準備圖像了。下面的代碼打開圖像,并分割成網格:

    # 打開圖像并轉換為灰度
    image = Image.open(filename).convert('L')
    # 存儲圖像尺寸
    W, H = image.size[0], image.size[1]
    # 計算平鋪寬度
    w = W/cols
    # 根據字體的縱橫比和比例計算平鋪高度
    h = w/scale
    # 計算要在最終網格中使用的行數
    rows = int(H/h)

    ??比例系數確定每個小塊的大小,以匹配用于顯示文字的字體的橫縱比,這樣最終圖像不會失真。scale的值可以作為參數傳入,或者設置位默認值0.43,在用Courier顯示結果時,效果最好。

    3.計算平均亮度

    ??計算灰度圖像中每一小塊的平均亮度。函數getAverageL()完成。

    def getAverageL(image):
        # 以numpy數組的形式獲取圖像
        im = np.array(image)
        # 得到尺寸
        w, h = im.shape
        # 獲得平均值
        return np.average(im.reshape(w*h))

    ??圖像小塊作為PIL Image對象傳入,將 image轉換成一個numpy數組,此時 im成為一個二維數組,包含每個像素的亮度。保存該圖像的尺寸(寬度和高度)。numpy.average()計算該圖像中的亮度平均值,做法是用numpy.reshape()先將維度為寬和高(w,h)的二維數組轉換成扁平的一維,其長度是寬度乘以高度(w*h)。然后numpy.average()調用對這些數組值求和并計算平均值。

    4.從圖像生成ASCII內容

    # ASCII圖像是字符串的列表
    aimg = []
    # 生成平鋪尺寸列表
    for j in range(rows):
        y1 = int(j * h)
        y2 = int((j + 1) * h)
        # 更正最后一個平鋪方塊
        if j == rows - 1:
            y2 = H
        # 追加一個空字符串
        aimg.append("")
        for i in range(cols):
        	# 裁剪圖像以適合平鋪
            x1 = int(i * w)
            x2 = int((i + 1) * w)
            # 更正最后一個平鋪方塊
            if i == cols - 1:
                x2 = W
            # 裁剪圖像以將其平鋪提取到另一個圖像對象中
            img = image.crop((x1, y1, x2, y2))
            # 獲得平均亮度
            avg = int(getAverageL(img))
            # 在ascii字符中查找平均灰度值
            if moreLevels:
                gsval = gscale1[int((avg * 69) / 255)]
            else:
                gsval = gscale2[int((avg * 9) / 255)]
            # 將ascii字符附加到字符串
            aimg[j] += gsval

    ??在程序的這一部分,ASCII圖像先作為一個字符串列表保存并初始化。接下來,按計算好的圖像小塊行數迭代遍歷,計算每個圖像小塊的起始和結束y坐標。雖然這些是浮點運算,但在傳給圖像裁剪方法之前,將它們截斷為整數。接著,因為只有當圖像的寬度是列數的整數倍時,圖像分割成小塊時,邊緣的小塊才有相同的大小,所以在最后一行校正小塊的y坐標,將y坐標設置為圖像的實際高度。這樣做確保了圖像頂部的邊緣不被截斷。然后為ASCII 圖像添加一個空字符串,作為一種緊湊的方式來表示圖像的當前行。接下來會填充這個字符串(將字符串作為字符的列表)。
    ??計算每個小塊的左、右x坐標,為最后一小塊校正x坐標,原因和校正y坐標時一樣。然后用 image.crop()提取圖像小塊,然后將該小塊傳入getAverageL()函數,取得小塊的平均亮度。將平均亮度值從[0,255]縮小至[0,9](默認10級灰度梯度值的范圍)。然后,用 gscale2(保存的梯度字符串)作為查找表,找到對應的ASCII 值。然后類似,不同之處在于,只有命令行標志設置為使用70級梯度時,才會用它。最后,在文本行中添加找到的ASCII 值 gsval,代碼循環,直到處理完所有行。

    5.類初始化定義

    descStr = "This program converts an image into ASCII art."
    # 添加預期參數
    parser = argparse.ArgumentParser(description=descStr)
    parser.add_argument('--file', dest='imgFile', required=False)
    parser.add_argument('--scale', dest='scale', required=False)
    parser.add_argument('--out', dest='outFile', required=False)
    parser.add_argument('--cols', dest='cols', required=False)
    parser.add_argument('--morelevels', dest='moreLevels', action='store_true')

    ??指定圖像文件輸入的選項(唯一必須的參數),設置垂直比例因子,設置輸出文件名,設置ASCII輸出中的文本列數。在行,添加–morelevels選項,讓用戶選擇更多層次的灰度梯度。

    6.將ASCII文本圖形字符串寫入文本文件

    # 打開一個新文件
    f = open(outFile, 'w')
    # 將列表中的每個字符串寫入新文件
    for row in aimg:
        f.write(row + '\n')
    # 關閉文件
    f.close()

    ??使用內置的 open()方法,打開一個新的文本文件用于寫入。然后迭代遍歷列表中的每個字符串,將它寫入文件,關閉文件對象,釋放系統資源。

    三、完整代碼

    import argparse
    from PIL import Image
    import numpy as np
    # 70 leves of gray
    gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^.y' "
    # 10 leves of gray
    gscale2 = "@%#*+=-:. "
    def getAverageL(image):
        # 以numpy數組的形式獲取圖像
        im = np.array(image)
        # 得到尺寸
        w, h = im.shape
        # 獲得平均值
        return np.average(im.reshape(w*h))
    def covertImageToAscii(filename, cols, scale, moreLevels):
        global gscale1, gscale2
        # 打開圖像并轉換為灰度
        image = Image.open(filename).convert('L')
        # 存儲圖像尺寸
        W, H = image.size[0], image.size[1]
        # print("input image dims: %d * %d" % (W, H))
        # 計算平鋪寬度
        w = W/cols
        # 根據字體的縱橫比和比例計算平鋪高度
        h = w/scale
        # 計算要在最終網格中使用的行數
        rows = int(H/h)
        # print("col: %d, row: %d" % (cols, rows))
        # print("tile dims: %d * %d" % (w, h))
        if cols > W or rows > H:
            # print("Image too small for specified cols!")
            exit(0)
        # ASCII圖像是字符串的列表
        aimg = []
        # 生成平鋪尺寸列表
        for j in range(rows):
            y1 = int(j * h)
            y2 = int((j + 1) * h)
            # 更正最后一個平鋪方塊
            if j == rows - 1:
                y2 = H
            # 追加一個空字符串
            aimg.append("")
            for i in range(cols):
                # 裁剪圖像以適合平鋪
                x1 = int(i * w)
                x2 = int((i + 1) * w)
                # 更正最后一個平鋪方塊
                if i == cols - 1:
                    x2 = W
                # 裁剪圖像以將其平鋪提取到另一個圖像對象中
                img = image.crop((x1, y1, x2, y2))
                # 獲得平均亮度
                avg = int(getAverageL(img))
                # 在ascii字符中查找平均灰度值
                if moreLevels:
                    gsval = gscale1[int((avg * 69) / 255)]
                else:
                    gsval = gscale2[int((avg * 9) / 255)]
                # 將ascii字符附加到字符串
                aimg[j] += gsval
        return aimg
    def main(imgFile, scale=0.52, cols=65, outFile='out.txt'):
        descStr = "This program converts an image into ASCII art."
        # 添加預期參數
        parser = argparse.ArgumentParser(description=descStr)
        parser.add_argument('--file', dest='imgFile', required=False)
        parser.add_argument('--scale', dest='scale', required=False)
        parser.add_argument('--out', dest='outFile', required=False)
        parser.add_argument('--cols', dest='cols', required=False)
        parser.add_argument('--morelevels', dest='moreLevels', action='store_true')
        args = parser.parse_args()
        if args.outFile:
            outFile = args.outFile
        if args.scale:
            scale = float(args.scale)
        if args.cols:
            cols = int(args.cols)
        # print('generating ASCII art ...')
        aimg = covertImageToAscii(imgFile, cols, scale, args.moreLevels)
        # 打開一個新文件
        f = open(outFile, 'w')
        # 將列表中的每個字符串寫入新文件
        for row in aimg:
            print(row)
            f.write(row + '\n')
        # 關閉文件
        f.close()
        # print("ASCII art written to %s" % outFile)
    if __name__ == '__main__':
        main('fxp.jpg')

    四、運行結果

    在這里插入圖片描述

    在這里插入圖片描述

    ??在這個項目中,我們學習了如何從任意的輸入圖像生成ASCII文本圖形,還學習了計算平均亮度值,將圖片轉換成灰度,以及如何基于灰度值用字符替換一小塊圖像,對比原圖和運行結果圖,代碼基本運行成功。(其實代碼也是閑著沒事給某個小姑娘寫的,順便學習一下python語法)

    參考代碼:https://github.com/electronut/pp/blob/master/ascii/ascii.py

    版權聲明:本文為weixin_45616399原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/weixin_45616399/article/details/109493034

    智能推薦

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    requests實現全自動PPT模板

    http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    Linux C系統編程-線程互斥鎖(四)

    互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...

    猜你喜歡

    統計學習方法 - 樸素貝葉斯

    引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...

    styled-components —— React 中的 CSS 最佳實踐

    https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...

    基于TCP/IP的網絡聊天室用Java來實現

    基于TCP/IP的網絡聊天室實現 開發工具:eclipse 開發環境:jdk1.8 發送端 接收端 工具類 運行截圖...

    19.vue中封裝echarts組件

    19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...

    劍指Offer39-調整數組順序使奇數位于偶數前面

    一開始想著用冒泡排序的方法來做,但是bug還是很多,后來看了評論區答案,發現直接空間換時間是最簡單的,而且和快排的寫法是類似的。...

    精品国产乱码久久久久久蜜桃不卡