Python根據字體的大小獲取字符串像素長度並以表格的形式在圖片中顯示

在Python中常用的兩個圖像處理庫,一個opencv,一個是PIL。其中,opencv是不支持中文顯示的,所以只能顯示英文。詳細實現如下代碼:

# -*- coding: utf-8 -*-#
# Author:      weiz
# Date:        2020/1/13 下午6:26
# Name:        testFont.py
# Description: 讓文字信息以表格的形式在圖片中顯示
import numpy as np
from PIL import Image, ImageDraw, ImageFont
import cv2

def is_chinese(uchar):
    """
    判斷一個unicode是否是漢字
    :param uchar:
    :return:
    """
    if uchar >= u'\u4e00' and uchar<=u'\u9fa5':
        return True
    else:
        return False


def fitImageSize_pil(img, fontsize, font_w, font_h, row, longestChn, gap):
    """
    適配圖片大小
    :param img:
    :param fontsize:
    :param font_w:
    :param font_h:
    :param row:
    :param longestChn:
    :param gap:
    :return:
    """
    img_h, img_w = img.shape[:2]

    h_rate = (font_h * row) / img_h
    w_rate = font_w / img_w

    while (max(h_rate, w_rate) <= 0.7) or (max(h_rate, w_rate) >= 0.9):
        if max(h_rate, w_rate) <= 0.7:
            fontsize = fontsize + 1
            font = ImageFont.truetype("simhei.ttf", fontsize, encoding="utf-8")
            font_w, font_h = font.getsize(longestChn)
            font_w = font_w + 2 * gap
            font_h = font_h + 2 * gap
            h_rate = (font_h * row) / img_h
            w_rate = font_w / img_w
        if max(h_rate, w_rate) >= 0.9:
            fontsize = fontsize - 1
            font = ImageFont.truetype("simhei.ttf", fontsize, encoding="utf-8")
            font_w, font_h = font.getsize(longestChn)
            font_w = font_w + 2 * gap
            font_h = font_h + 2 * gap
            h_rate = (font_h * row) / img_h
            w_rate = font_w / img_w

    font = ImageFont.truetype("simhei.ttf", fontsize, encoding="utf-8")
    return font, font_w, font_h


def showChn4table_pil(img, chnList, fontsize=None, gap=None, start_x=None, start_y=None):
    """
    以表格的形式在圖片的居中(默認是居中)顯示中文或者英文字符
    :param img:
    :param chnList:
    :param fontsize:
    :param gap:表格和字體之間的距離
    :param start_x:
    :param start_y:
    :return:
    """
    row = len(chnList)
    if gap == None:
        gap = 2
    if fontsize == None:
        fontsize = 20
    longestChn = ""
    longestChn_count = 0
    # 涉及到中文漢字,一個漢字佔兩個字節。但是len()函數只計算字符串的個數,而顯示涉及到像素
    for chnStr in chnList:
        count = 0
        for chn in chnStr:
            if is_chinese(chn):
                count += 1
        count = (len(chnStr) - count) + count * 2
        if count > longestChn_count:
            longestChn = chnStr
            longestChn_count = count
    img_h, img_w = img.shape[:2]

    pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(pil_img)
    # 如果是在Linux系統下運行,可能需要把simhei.ttf字體放到當前運行腳本同路徑下
    font = ImageFont.truetype("simhei.ttf", fontsize, encoding="utf-8")
    font_w, font_h = font.getsize(longestChn)
    font_w = font_w + 2 * gap
    font_h = font_h + 2 * gap

    font, font_w, font_h = fitImageSize_pil(img, fontsize, font_w, font_h, row, longestChn, gap)

    # 修改start_x和start_y就可以在圖片的任意位置顯示
    if start_x == None:
        start_x = (img_w - font_w) // 2
    if start_y == None:
        start_y = (img_h - font_h * row) // 2
    end_x = start_x + font_w
    end_y = start_y + font_h * row

    for i, chnStr in enumerate(chnList):
        line_spacing = i * font_h
        draw.text((start_x+gap, start_y+line_spacing+gap), chnStr, (0, 0, 0), font)
        draw.line((start_x, start_y+line_spacing, end_x, start_y+line_spacing), 'red')

    draw.line((start_x, end_y, end_x, end_y), 'red')
    draw.line((start_x, start_y, start_x, end_y), 'red')
    draw.line((end_x, start_y, end_x, end_y), 'red')

    img = cv2.cvtColor(np.asarray(pil_img), cv2.COLOR_RGB2BGR)
    return img


def showEng4table_cv(img, engList, fontScale=None, gap=None, start_x=None, start_y=None):
    """
    以表格的形式在圖片的居中(默認是居中)顯示英文字符(opencv不支持中文)
    :param img:
    :param engList:
    :param fontScale:
    :param gap:表格和字體之間的距離
    :param start_x:
    :param start_y:
    :return:
    """
    row = len(engList)
    if gap == None:
        gap = 2
    if fontScale == None:
        fontScale = 1
    longestEng = ""
    for engStr in engList:
        if len(engStr) > len(longestEng):
            longestEng = engStr
    img_h, img_w = img.shape[:2]

    (font_w, font_h), baseline = cv2.getTextSize(longestEng, cv2.FONT_HERSHEY_TRIPLEX, fontScale, 1)
    font_h = font_h + baseline + 2 * gap
    font_w = font_w + 2 * gap


    if start_x == None:
        start_x = (img_w - font_w) // 2
    if start_y == None:
        start_y = (img_h - (font_h * row)) // 2
    end_x = start_x + font_w
    end_y = start_y + font_h * row

    for i, engStr in enumerate(engList):
        line_spacing = i * font_h
        cv2.rectangle(img, (start_x, start_y+line_spacing), (end_x, start_y+line_spacing+font_h), (0, 0, 0))
        cv2.putText(img, engStr, (start_x+gap, start_y+line_spacing+font_h-baseline-gap), cv2.FONT_HERSHEY_TRIPLEX, fontScale, (0, 0, 0), 1)

    return img


if __name__ == "__main__":
    img = np.ones([600, 1000, 3], dtype=np.uint8) * 188

    chnList = ['沒有,不是,別亂說!', '產品型號|CCF| 符合標推| GB7251.3', '額定工作電壓:220V/380V  額定工作電流', '額定絕緣電壓:400V額定工作頻率:50HZ', '出廠編號|| 出廠日期||年| |月', '河 南 西 西弗  電 氣 有 限 公 司', 'abcdetfghidjkkdjddekdjieiij']
    img_pil = showChn4table_pil(img, chnList, 20, 5)
    cv2.imshow("img_pil", img_pil)

    engList = ["How old are you?", "How are you!", "How are you!", "Of course the longest string is me!", "How are you!", "How are you!", "hello,world!", "No, no, don't talk nonsense!"]
    img_cv = showEng4table_cv(img, engList, 0.8, 5)
    cv2.imshow("img_cv", img_cv)

    cv2.waitKey()

效果圖片:

使用PIL
使用opencv

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章