成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【正經(jīng)的AI on Python入門系列】1.1斗圖工具的優(yōu)化——實(shí)現(xiàn)文本居中(還混進(jìn)了一些語法基礎(chǔ)

Luosunce / 3025人閱讀

摘要:大家還記得上一篇文章來學(xué)點(diǎn)吧從一個(gè)斗圖小工具開始中最后提到的幾個(gè)問題么,我們這次就來解決一下其中難度最大的一個(gè)文本居中看,我把代碼優(yōu)化了上次之后,我偷偷把代碼優(yōu)化了,現(xiàn)在的方法長(zhǎng)這樣創(chuàng)建表情圖調(diào)試用生成表情包對(duì)的,我把那些老長(zhǎng)老長(zhǎng)

大家還記得上一篇文章0.來學(xué)點(diǎn)Python吧!從一個(gè)斗圖小工具開始中最后提到的幾個(gè)問題么,我們這次就來解決一下其中難度最大的一個(gè):文本居中!

看,我把代碼優(yōu)化了!

上次之后,我偷偷把代碼優(yōu)化了,現(xiàn)在的main方法長(zhǎng)這樣:

# -*- coding:utf-8 -*-
#__author__ = "akers"
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
import sys,platform,operators.image,operators.clipboard


def main(argv):
    # 創(chuàng)建表情圖
    image = operators.image.draw_emo("./resources/background/pander/default.png", "./resources/face/jgz/laugth.png", argv[1])
    output = BytesIO()
    image.save(output, format="BMP")
    operators.clipboard.add_bmp(output)
    image.save("output/facing.png")

    # 調(diào)試用
    # plt.figure("生成表情包")
    # plt.imshow(target)
    # plt.show()

if __name__ == "__main__":
    main(sys.argv)

對(duì)的,我把那些老長(zhǎng)老長(zhǎng)的代碼藏到別的包里了,下面是一點(diǎn)題外話,順便介紹一下Python的包與模塊

Python的包與模塊

以我們重構(gòu)后的項(xiàng)目為例,一個(gè)項(xiàng)目的結(jié)構(gòu)大致如下

python中的包就是一個(gè)包含了__init__.py文件的文件夾,包下可有子包

模塊

python的模塊就是一個(gè)py文件,其中可包括類、函數(shù)、變量等等內(nèi)容

導(dǎo)入包

python中使用import關(guān)鍵字引入模塊,import的使用分以下幾種

import package[.sub_package].model

導(dǎo)入指定的模塊,調(diào)用時(shí)需使用模塊全名,例如

import operators.image

operators.image.draw_emo
from package[.sub_package] import model

導(dǎo)入指定模塊,調(diào)用時(shí)直接使用模塊名

from operators import image

image.draw_emo()
import package[.sub_package].model import function

導(dǎo)入模塊中的函數(shù)或成員、類、變量等

from operators.image import draw_emo

draw_emo()

Python的包跟模塊的內(nèi)容還有很多,更詳細(xì)的就先不贅述了,然后讓我們繼續(xù)主題,咳咳

表情包文本居中

首先,我們來實(shí)現(xiàn)文本的居中,我們先來回顧一下我們是如何插入文本的:

#底圖上的10,200位置寫入文字
draw.text((10, 200), argv[1],fill="black", font=font)

text函數(shù)的第一個(gè)參數(shù)需要個(gè)元組,而元組中的0、1兩個(gè)元素分別代表的x和y的坐標(biāo)(以像素為單位),那實(shí)現(xiàn)居中就很簡(jiǎn)單了,我們只需要根據(jù)插入文本的具體寬度計(jì)算出一個(gè)合適的x坐標(biāo)就可以了。
于是請(qǐng)看大屏幕,啊呸,請(qǐng)看下圖,


從圖中我們可以看到,文本的插入坐標(biāo)可以用這樣的公式進(jìn)行計(jì)算:(底圖寬-文本寬) / 2,那問題又來了,文本寬我們?cè)趺吹玫侥兀?br>在PIL中,我們可以用draw.textsize獲取文本所占的大小,返回是個(gè)元組:(寬,高),像這樣:

txtSize = draw.textsize(text, imageFont)

所以我們修改一下draw_text方法:對(duì)x坐標(biāo)進(jìn)行計(jì)算

def draw_text_v1(text, image, off_set=200):
    """強(qiáng)化版繪制文字v1,讓文字在x軸上居中
    Args:
        text: 顯示在圖片上的文本
        image: 當(dāng)前正使用的Image
        off_set: 縱向偏移量

    Returns:
        Image

    Raises:

    """
    # 加入文字
    # ImageDraw為PIL的繪圖模塊
    _DEFAULT_FONT_SIZE = 30
    draw = ImageDraw.Draw(image)
    imageFont = ImageFont.truetype("./resources/msyh.ttc", _DEFAULT_FONT_SIZE)
    _MAX_TXT_HEIGH = 32
    txtSize = draw.textsize(text, imageFont)
    pos_x = (CONST_IMG_WIDTH - txtSize[0]) / 2 if CONST_IMG_WIDTH > txtSize[0] else 0
    print("當(dāng)前X坐標(biāo)", pos_x)
    # 默認(rèn)顯示位置
    pos = (pos_x, off_set)
    draw.text(pos, text, fill="black", font=imageFont)
    del draw
    return image

相信眼尖的強(qiáng)迫癥患者可能會(huì)發(fā)現(xiàn),這里面混著一個(gè)很奇怪的寫法:

(CONST_IMG_WIDTH - txtSize[0]) / 2 if CONST_IMG_WIDTH > txtSize[0] else 0

這個(gè)if跟else是不是有點(diǎn)調(diào)皮,其實(shí)這個(gè)在python 里類似于c語系里的 ? :三目運(yùn)算符:如果if后的條件成立,則取if前的表達(dá)式進(jìn)行返回,否則取else后的表達(dá)式,上面的代碼實(shí)際等同于:

CONST_IMG_WIDTH > txtSize[0] ? (CONST_IMG_WIDTH - txtSize[0]) / 2 : 0

這個(gè)細(xì)節(jié)又暴露了Python的哲學(xué):我已經(jīng)有了if else了,還要? :干嘛,關(guān)鍵字的數(shù)量也要最簡(jiǎn);而個(gè)語法應(yīng)該也是從C語系轉(zhuǎn)過來的小伙伴覺得最別扭的語法之一了吧....

好廢話不多說,來讓我們看看效果,很中對(duì)不對(duì):

正所謂要精益求精,既然都做了居中,索性把對(duì)齊做個(gè)參數(shù)好了,跟居中一樣的原理,我把左對(duì)齊跟右對(duì)齊也做了,只需要對(duì)draw_text_v1做一點(diǎn)點(diǎn)潤色:

def draw_text_v2(text, image, off_set=(0, 200), allign="center"):
    """強(qiáng)化版繪制文字v2,左中右,想放哪里放哪里
    Args:
        text: 顯示在圖片上的文本
        image: 當(dāng)前正使用的Image
        off_set: 偏移量,用于保留最小編劇,(x, y)以像素未單位
        allign: 排版,left左對(duì)齊,center居中,right右對(duì)齊

    Returns:
        Image

    Raises:

    """
    # 加入文字
    # ImageDraw為PIL的繪圖模塊
    _DEFAULT_FONT_SIZE = 30
    draw = ImageDraw.Draw(image)
    imageFont = ImageFont.truetype("./resources/msyh.ttc", _DEFAULT_FONT_SIZE)
    _MAX_TXT_HEIGH = 32
    txtSize = draw.textsize(text, imageFont)
    imageFont = ImageFont.truetype("./resources/msyh.ttc", 30)

    # 計(jì)算x坐標(biāo)
    pos_x = {
        # 居中對(duì)齊
        "center": lambda max_width, txt_len, off: (max_width / 2 - txt_len / 2 if max_width > txt_len else 0) + off,
        # 左對(duì)齊
        "left": lambda max_width, txt_len, off: (off if max_width > txt_len else 0),
        # 右對(duì)齊
        "right": lambda max_width, txt_len, off: (max_width - txt_len if max_width > txt_len else 0)
    }[allign if allign in ("center", "left", "right") else "center"](CONST_IMG_WIDTH - 2*off_set[0], txtSize[0], off_set[0])

    # 默認(rèn)顯示位置
    pos = (pos_x, off_set[1])

    # 底圖上的10,200位置寫入文字
    draw.text(pos, text, fill="black", font=imageFont)
    del draw
    return image

效果好像還不錯(cuò):

估計(jì)又有眼尖的小伙伴發(fā)現(xiàn)有個(gè)代碼不對(duì)了,怎么pos_x的計(jì)算實(shí)現(xiàn)是如此的奇葩,我都看不懂了!

    pos_x = {
        # 居中對(duì)齊
        "center": lambda max_width, txt_len, off: (max_width / 2 - txt_len / 2 if max_width > txt_len else 0) + off,
        # 左對(duì)齊
        "left": lambda max_width, txt_len, off: (off if max_width > txt_len else 0),
        # 右對(duì)齊
        "right": lambda max_width, txt_len, off: (max_width - txt_len if max_width > txt_len else 0)
    }[allign if allign in ("center", "left", "right") else "center"](CONST_IMG_WIDTH - 2*off_set[0], txtSize[0], off_set[0])

其實(shí)這里嘛,是Python實(shí)現(xiàn)switch功能的一個(gè)奇技淫巧...對(duì)的,你猜的沒錯(cuò),Python是沒有switch結(jié)構(gòu)的,因?yàn)椋骸拔覀円呀?jīng)有了完美的if...else...要switch干嘛”,所以如果按照官方建議,這段代碼應(yīng)該是這樣的:

    max_width = CONST_IMG_WIDTH - 2*off_set[0]
    txt_len = txtSize[0]
    if allign == "center":
        pos_x = (max_width / 2 - txt_len / 2 if max_width > txt_len else 0) + off_set[0]
    else if allign == "left":
        pos_x = off_set[0] if CONST_IMG_WIDTH - 2*off_set[0] > txt_len else 0
    else if allign == "right":
        pos_x = max_width - txt_len if max_width > txt_len else 0
    else:
        pos_x = ((max_width / 2 - txt_len / 2 if max_width > txt_len else 0) + off_set[0]

而我在實(shí)現(xiàn)上是采用了字典結(jié)構(gòu)加上lamada表達(dá)式進(jìn)行實(shí)現(xiàn)的,這里再多嘴一句,python的lamada表達(dá)式只支持單行只支持單行!因?yàn)楣俜接X得如果一個(gè)lamada表達(dá)式需要多行才能解決問題,那你還是去定義個(gè)函數(shù)吧!
?。磕阏f上面的代碼還是沒搞懂?嗯...好吧,那我把代碼好好講講。
首先,代碼是使用了一些簡(jiǎn)寫的,我們把它拆出來:

    def center(max_width, txt_len, off):
        return (max_width / 2 - txt_len / 2 if max_width > txt_len else 0) + off

    def left(max_width, txt_len, off):
        return off if max_width > txt_len else 0

    def right(max_width, txt_len, off):
        return max_width - txt_len if max_width > txt_len else 0
    
    dict_temp = {
        # 居中對(duì)齊
        "center": center,
        # 左對(duì)齊
        "left": left,
        # 右對(duì)齊
        "right": right
    }

    pos_x_func = dict_temp[allign if allign in ("center", "left", "right") else "center"]
    pos_x = pos_x_func(CONST_IMG_WIDTH - 2*off_set[0], txtSize[0], off_set[0])

得益于python動(dòng)態(tài)語言的特性,我們可以把所有的中間變量都去掉,就形成了樣例中的那種代碼結(jié)構(gòu)了,這個(gè)屬于加大閱讀難度的(但代碼看上去簡(jiǎn)潔了?。。┐蠹腋悴欢囊矡o所謂,我就主要簡(jiǎn)單介紹一下lamada表達(dá)式了。
從上面分解的代碼可以看出,lamada實(shí)際上也是函數(shù),有入?yún)⒂蟹祷刂?,但就是沒了個(gè)名字,所以他實(shí)際上是一個(gè)匿名函數(shù),其構(gòu)成是這樣的:

lamada 參數(shù)1 [, 參數(shù)n] : 表達(dá)式

記住了,Python不支持多行l(wèi)amada!

感覺這次文章基礎(chǔ)語法扯的有點(diǎn)多了,之后的文章對(duì)基礎(chǔ)語法的介紹會(huì)進(jìn)一步減少的!
本次的代碼樣例同樣在我的GitHub上可以找到

好的,那么接下來

額...好吧,下次我們就來解決上面這個(gè)問題!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/42126.html

相關(guān)文章

  • 正經(jīng)AI on Python入門系列】1.2 斗圖工具優(yōu)化——文本寬度自適應(yīng)(來做點(diǎn)小數(shù)據(jù)分析

    摘要:在上一篇文章圖工具的優(yōu)化實(shí)現(xiàn)文本居中中,我們已經(jīng)實(shí)現(xiàn)了對(duì)插入字體的左中右對(duì)齊顯示,那因?yàn)樯掀谖恼禄爝M(jìn)去了不少語法講解,所以后面的內(nèi)容就順延到這啦,哈哈哈。 showImg(https://segmentfault.com/img/bVbeIu4?w=250&h=250); 在上一篇文章【圖工具的優(yōu)化——實(shí)現(xiàn)文本居中】中,我們已經(jīng)實(shí)現(xiàn)了對(duì)插入字體的左中右對(duì)齊顯示,那因?yàn)樯掀谖恼禄爝M(jìn)去了不...

    fireflow 評(píng)論0 收藏0
  • 正經(jīng)AI on Python入門系列】0.來學(xué)點(diǎn)Python吧!從一個(gè)斗圖工具開始

    摘要:因此,本文將會(huì)以一些正經(jīng)的嚴(yán)謹(jǐn)?shù)挠猩疃鹊拇蟾虐傻恼n題,慢慢的接觸人工智能的相關(guān)知識(shí)。 Before The Beginning ????近年,技術(shù)圈炒的最火的兩個(gè)話(ba)題(gua)不外乎就是人工智障智能以及炒幣區(qū)塊鏈了,這個(gè)系列文章我主要以一個(gè)小菜鳥的角度一步一步的對(duì)人工智能的相關(guān)知識(shí)做一點(diǎn)了解,也算是一個(gè)顫顫巍巍追著AI浪潮公交車的社會(huì)主義五好青年,咳咳,扯遠(yuǎn)了...其實(shí)對(duì)于人工...

    趙連江 評(píng)論0 收藏0
  • [原創(chuàng)]nim與rust特點(diǎn)比較

    摘要:與的特點(diǎn)比較這兩個(gè)目前都是小眾語言做了些時(shí)間的研究寫了點(diǎn)東西有了點(diǎn)心得相似點(diǎn)有衛(wèi)生宏區(qū)別與的不衛(wèi)生宏在類或定義體之外定義函數(shù)代碼沒有分成頭與實(shí)現(xiàn)體例如的頭與實(shí)現(xiàn)的與定義的接口定義與實(shí)現(xiàn)定義是分開的而與是不分開的運(yùn)用函數(shù)式編程高階函數(shù)目前是新 nim與rust的特點(diǎn)比較 這兩個(gè)目前都是小眾語言,做了些時(shí)間的研究,寫了點(diǎn)東西有了點(diǎn)心得 相似點(diǎn): 有衛(wèi)生宏.區(qū)別與C++的(不衛(wèi)生)宏 在類...

    DevTalking 評(píng)論0 收藏0
  • 重磅 | 完備 AI 學(xué)習(xí)路線,最詳細(xì)資源整理!

    摘要:是你學(xué)習(xí)從入門到專家必備的學(xué)習(xí)路線和優(yōu)質(zhì)學(xué)習(xí)資源。的數(shù)學(xué)基礎(chǔ)最主要是高等數(shù)學(xué)線性代數(shù)概率論與數(shù)理統(tǒng)計(jì)三門課程,這三門課程是本科必修的。其作為機(jī)器學(xué)習(xí)的入門和進(jìn)階資料非常適合。書籍介紹深度學(xué)習(xí)通常又被稱為花書,深度學(xué)習(xí)領(lǐng)域最經(jīng)典的暢銷書。 showImg(https://segmentfault.com/img/remote/1460000019011569); 【導(dǎo)讀】本文由知名開源平...

    荊兆峰 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<