PIL画图 透明色的圆、框,虚线

PIL画图

功能
  1. 画带透明度的圆,调整透明度
  2. 画虚线
  3. 画直线,直线没有锯齿
# coding:utf-8
from PIL import Image, ImageDraw
import aggdraw
import time
import cv2
import numpy as np

TRANSPARENT_RED_COLOR = (255, 114, 114, 80)  ## RGB 红色透明色
TRANSPARENT_WHITE_COLOR = (255, 255, 255, 80)  ## RGB 白色透明色
RED_COLOR = (255, 114, 114)  ## RGB 红色
WHITE_COLOR = (255, 255, 255)  ## RGB 白色

KEYPOINT_EDGE = [(3, 4),(5, 7),(7, 9),(6, 8),(8, 10),(5, 6),(5, 11),(6, 12),(11, 12),(11, 13),(13, 15),(12, 14),(14, 16)]

KEYPOINT_EDGE_SIDE = [
    (4, 6),(6, 12),(12, 14),(14, 16)
]

POSTURE_POINTS = {
    "head_tilt": [3,4],
    "uneven_shoulders": [5,6],
    "scoliosis": [5,6,11,12],
    "X_legs": [11,12,13,14,15,16],
    "O_legs": [11,12,13,14,15,16],

    "neck_tilt": [4,6],
    "hunchback": [4,6,12],
}

POSTURE_LINES = {
    "head_tilt": [[3, 4]],
    "uneven_shoulders": [[5, 6]],
    "scoliosis": [[5, 6],[11, 12],[5, 11],[6, 12]],
    "X_legs": [[11,13],[13,15]],
    "O_legs": [[12,14],[14,16]],

    "neck_tilt": [[4, 6]],
    "hunchback": [[4, 6],[6,12]],
}

side_postures = ['neck_tilt', 'hunchback']
front_postures = ['head_tilt', 'uneven_shoulders', 'scoliosis', 'X_legs', 'O_legs']

def draw_dash_line(draw,start_point,end_point,line_width,line_color):
    # 定义虚线的样式
    dash_length = 8  # 每段虚线的长度
    gap_length = 5  # 每段空白的长度
    # s = time.time()
    # 计算总长度
    total_length = ((end_point[0] - start_point[0]) ** 2 + (end_point[1] - start_point[1]) ** 2) ** 0.5

    # 计算单位方向向量
    dx = (end_point[0] - start_point[0]) / total_length
    dy = (end_point[1] - start_point[1]) / total_length

    # 绘制虚线
    current_length = 0
    while current_length < total_length:
        # 计算当前线段的起点和终点
        segment_start = (
            int(start_point[0] + current_length * dx),
            int(start_point[1] + current_length * dy)
        )
        segment_end = (
            int(start_point[0] + (current_length + dash_length) * dx),
            int(start_point[1] + (current_length + dash_length) * dy)
        )
        # 绘制线段
        draw.line([segment_start, segment_end], fill=line_color, width=line_width)
        # 更新当前长度
        current_length += dash_length + gap_length
    # e = time.time()
    # print('t', e - s)
    return draw

def draw_circel(draw,circle_center,circle_radius,circle_color):
    # 绘制圆形
    draw.ellipse([circle_center[0] - circle_radius, circle_center[1] - circle_radius,
                  circle_center[0] + circle_radius, circle_center[1] + circle_radius],
                 fill=circle_color, outline=None, width=2)
    return draw

def draw_line(draw,start_point,end_point,line_color,line_width,is_dash=False):

    start_point = (int(start_point[0]),int(start_point[1]))
    end_point = (int(end_point[0]),int(end_point[1]))
    # 绘制直线
    if is_dash:
        draw.line([start_point, end_point], fill=line_color, width=line_width, joint='curve')
    else:
        pen = aggdraw.Pen(line_color, width=line_width)  # 蓝色,线宽为 2
        draw.line([start_point[0],start_point[1], end_point[0],end_point[1]], pen)
    return draw


def draw_front_image(image,kpts,posture_results):
    abnormal_type = []
    abnormal_points = []
    abnormal_lines = []
    for k in front_postures:
        pos_res = posture_results[k]
        if pos_res:
            abnormal_type.append(k)
    for posture in abnormal_type:
        points = POSTURE_POINTS[posture]
        lines = POSTURE_LINES[posture]
        abnormal_points.extend(points)
        for line in lines:
            if line not in abnormal_lines:
                abnormal_lines.append(line)
    abnormal_points = set(abnormal_points)

     ## 增加透明度
    # bbox = kpts_res[img_name]['bbox']
    # kpts = np.array(kpts)
    # image = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), cv2.IMREAD_COLOR)  #### 忽略透明度
    img_shape = image.shape
    ## 转成PIL
    radius = max(4, int(max(img_shape) / 250))
    transparent_circle_radius = radius * 2 + 2  ## 透明圆的半径
    # image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)).convert("RGBA")
    image = Image.fromarray(image).convert("RGBA")
    ## 开一个图层
    overlay = Image.new('RGBA', image.size, (0, 0, 0, 0))  # 初始化为完全透明
    draw = ImageDraw.Draw(overlay)
    ## 画上白色的底圆,半径大,透明
    for idx, landmark in enumerate(kpts[3:]):
        circle_center = list(map(int, landmark))
        draw_circel(draw, circle_center, transparent_circle_radius, TRANSPARENT_WHITE_COLOR)
    ## 有异常是,画上红色的底圆,半径大,透明
    # for idx, landmark in enumerate(kpts[3:5]):
    for idx in abnormal_points:
        landmark = kpts[idx]
        circle_center = list(map(int, landmark))
        draw_circel(draw, circle_center, transparent_circle_radius, TRANSPARENT_RED_COLOR)
    ### 画标准线 正面的
    for i in [4, 6, 12, 14, 16]:
        y = int(kpts[i][1])
        start_point = [0, y]
        end_point = [img_shape[1], y]
        draw_dash_line(draw, start_point, end_point, line_width=max(radius - 4, 2),
                       line_color=TRANSPARENT_WHITE_COLOR)
    ## 将透明的圆和标准线加到原图上去
    result = Image.alpha_composite(image, overlay)
    # 创建一个绘图对象
    draw = ImageDraw.Draw(result)
    ## 画上白色的圆,更小,不透明
    for idx, landmark in enumerate(kpts[3:]):
        circle_center = list(map(int, landmark))
        draw_circel(draw, circle_center, radius, WHITE_COLOR)
    ## 异常体态 画上红色的圆,更小,不透明
    # for idx, landmark in enumerate(kpts):
    for idx in abnormal_points:
        landmark = kpts[idx]
        # if not (idx in [3, 4]):
        #     continue
        circle_center = list(map(int, landmark))
        draw_circel(draw, circle_center, radius, RED_COLOR)
    ## 用于画光滑的直线
    # 使用 aggdraw 绘制抗锯齿的线
    ## 正常情况的连线
    draw = aggdraw.Draw(result)
    for line_pairs in KEYPOINT_EDGE:
        start_point = kpts[line_pairs[0]]
        end_point = kpts[line_pairs[1]]
        draw = draw_line(draw, start_point, end_point, line_color=WHITE_COLOR,
                         line_width=max(radius - 4, 2), is_dash=False)
    ## 异常情况的连线
    for line_pairs in abnormal_lines:
        start_point = kpts[line_pairs[0]]
        end_point = kpts[line_pairs[1]]
        draw = draw_line(draw, start_point, end_point, line_color=RED_COLOR, line_width=max(radius - 4, 2),
                         is_dash=False)
    draw.flush()

    img = cv2.cvtColor(np.asarray(result), cv2.COLOR_RGBA2BGR)
    return img
    # cv2.imshow("OpenCV", img)
    # cv2.waitKey(0)
    # result.show()



def draw_side_image(image,kpts,posture_results):
    abnormal_type = []
    abnormal_points = []
    abnormal_lines = []
    for k in side_postures:
        pos_res = posture_results[k]
        if pos_res:
            abnormal_type.append(k)
    for posture in abnormal_type:
        points = POSTURE_POINTS[posture]
        lines = POSTURE_LINES[posture]
        abnormal_points.extend(points)
        for line in lines:
            if line not in abnormal_lines:
                abnormal_lines.append(line)
    abnormal_points = set(abnormal_points)

     ## 增加透明度
    # bbox = kpts_res[img_name]['bbox']
    # kpts = np.array(kpts)
    # image = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), cv2.IMREAD_COLOR)  #### 忽略透明度
    img_shape = image.shape
    ## 转成PIL
    radius = max(4, int(max(img_shape) / 250))
    transparent_circle_radius = radius * 2 + 2  ## 透明圆的半径
    # image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)).convert("RGBA")
    image = Image.fromarray(image).convert("RGBA")
    ## 开一个图层
    overlay = Image.new('RGBA', image.size, (0, 0, 0, 0))  # 初始化为完全透明
    draw = ImageDraw.Draw(overlay)
    ## 画上白色的底圆,半径大,透明
    for idx, landmark in enumerate(kpts):
        if idx not in [4,6,12,14,16]:
            continue
        circle_center = list(map(int, landmark))
        draw_circel(draw, circle_center, transparent_circle_radius, TRANSPARENT_WHITE_COLOR)
    ## 有异常是,画上红色的底圆,半径大,透明
    # for idx, landmark in enumerate(kpts[3:5]):
    for idx in abnormal_points:
        landmark = kpts[idx]
        circle_center = list(map(int, landmark))
        draw_circel(draw, circle_center, transparent_circle_radius, TRANSPARENT_RED_COLOR)
    ### 画标准线 正面的
    # for i in [4, 6, 12, 14, 16]:
    #     y = int(kpts[i][1])
    #     start_point = [0, y]
    #     end_point = [img_shape[1], y]
    #     draw_dash_line(draw, start_point, end_point, line_width=max(radius - 4, 2),
    #                    line_color=TRANSPARENT_WHITE_COLOR)

    idx = 16
    x = int(kpts[idx][0])
    start_point = [x,0 ]
    end_point = [x, img_shape[0]]
    draw_dash_line(draw, start_point, end_point, line_width=max(radius - 4, 2),
                                      line_color=TRANSPARENT_WHITE_COLOR)

    ## 将透明的圆和标准线加到原图上去
    result = Image.alpha_composite(image, overlay)
    # 创建一个绘图对象
    draw = ImageDraw.Draw(result)
    ## 画上白色的圆,更小,不透明
    for idx, landmark in enumerate(kpts):
        if idx not in [4,6,12,14,16]:
            continue
        circle_center = list(map(int, landmark))
        draw_circel(draw, circle_center, radius, WHITE_COLOR)
    ## 异常体态 画上红色的圆,更小,不透明
    # for idx, landmark in enumerate(kpts):
    for idx in abnormal_points:
        landmark = kpts[idx]
        # if not (idx in [3, 4]):
        #     continue
        circle_center = list(map(int, landmark))
        draw_circel(draw, circle_center, radius, RED_COLOR)
    ## 用于画光滑的直线
    # 使用 aggdraw 绘制抗锯齿的线
    ## 正常情况的连线
    draw = aggdraw.Draw(result)
    for line_pairs in KEYPOINT_EDGE_SIDE:
        start_point = kpts[line_pairs[0]]
        end_point = kpts[line_pairs[1]]
        draw = draw_line(draw, start_point, end_point, line_color=WHITE_COLOR,
                         line_width=max(radius - 4, 2), is_dash=False)
    ## 异常情况的连线
    for line_pairs in abnormal_lines:
        start_point = kpts[line_pairs[0]]
        end_point = kpts[line_pairs[1]]
        draw = draw_line(draw, start_point, end_point, line_color=RED_COLOR, line_width=max(radius - 4, 2),
                         is_dash=False)

    draw.flush()

    img = cv2.cvtColor(np.asarray(result), cv2.COLOR_RGBA2BGR)
    return img
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值