File size: 5,526 Bytes
81e69dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

"""
create_hole_image.py

open_mouth.pyの一部


著者: Akihito Miyazaki
作成日: 2024-04-23
更新履歴:
  - 2024-04-23: 最初のリリース
  - 2024-09-15:slide_amountを追加
"""

import cv2
import numpy as np
from PIL import Image
import lip_utils



def vertical_slide(image, slide_amount):
    height, width = image.shape[:2]

    # スライド量が画像の高さより大きい場合、画像の高さに制限する
    slide_amount = min(slide_amount, height)
    slide_amount = max(slide_amount, -height)

    slide_image = np.zeros_like(image)  # 入力画像と同じサイズと型の画像を作成

    if slide_amount > 0:  # 下にスライド
        slide_image[slide_amount:, :] = image[:height - slide_amount, :]
    elif slide_amount < 0:  # 上にスライド
        slide_image[:height + slide_amount, :] = image[-slide_amount:, :]
    else:
        slide_image = image.copy()

    return slide_image


def file_name_check(path):
    max_name_limit = 50
    check = True
    if path.find("..")!=-1:
        check = False
    if path.find("/")!=-1:
        check = False
    if path.find("\\")!=-1:
        check = False
    if path.find(":")!=-1:
        check = False
    if len(path)>max_name_limit:
        print(f"name is limited {max_name_limit}")
        check = False
    if not check:
        ValueError(f"Invalid Name {path}")
        


def process_create_hole_image(img,landmarks_list,open_size_y = 0,open_size_x=0,hole_offset=0,hole_image_name="dark01.jpg"):
    file_name_check(hole_image_name)
    img_h, img_w = lip_utils.get_image_size(img)

    # 画像を複製して、アラインポイントを描画する。アラインは、傾きも考慮した唇の範囲
    img_lined = np.copy(img)
    
    points = lip_utils.get_top_lip_align_points(landmarks_list)
    img_lined1 = np.copy(img)
    print(points)
    cv2.polylines(img_lined1, [np.array(points)], isClosed=True, color=(0,255,0), thickness=1)
    if lip_utils.DEBUG:
        cv2.imwrite("create_hole_top_lip_align_line.jpg",img_lined1)


    print(f"align point = {points}")
    diff_align_x = points[0][0]-points[2][0]
    print(f"diff_align_x = {diff_align_x}")
    np_points = np.array(points)
    
    diff_left = np_points[2] - np_points[0] #left-bottom ,left-up
    diff_right = np_points[3] - np_points[1] #right-bottom,right-up
    print(f"diff left-y = {diff_left},diff right-y ={diff_right}")

    top_lip_thicks = lip_utils.get_top_lip_thicks(landmarks_list) # this ignore rotation
    top_lip_thicks2 = lip_utils.get_top_lip_thicks(landmarks_list,True) # this ignore rotation

    lip_thick = np.mean(top_lip_thicks)
    lip_thick2 = np.mean(top_lip_thicks2)

    base_mouth_size = lip_thick2*1.5
    
    mouth_angle=lip_utils.calculate_clockwise_angle(points[2],points[3])
    angled_point=lip_utils.calculate_new_point((0,0),base_mouth_size,mouth_angle+90)
    angled_mouth_size = angled_point[1] + open_size_y
    #print(f"lip_thick2={lip_thick2}")

    print(f"lip thick2 ={lip_thick2} base_mouth_size={base_mouth_size} mouth_angle={mouth_angle} angled_mouth_size={angled_mouth_size}")
    #上唇の範囲を元に、口全体を定義するため、根拠ないけど1.x倍にしている。 https://github.com/akjava/lip_recognition_tools/issues/8
    diff_left[1] = angled_mouth_size
    diff_right[1] = angled_mouth_size
    diff_left[0] *=0
    diff_right[0] *=0
    expand_left =  np_points[2] + diff_left
    expand_right =  np_points[3] + diff_right

    # X座標も拡大するが、基本使わないので無視してもいい。
    expand_points = np.array([np_points[0],np_points[1],expand_left,expand_right])  
    print(f"expand_points = {[np_points[0],np_points[1],expand_left,expand_right]}")
    cv2.polylines(img_lined, [expand_points], isClosed=True, color=(0,255,0), thickness=1)
    if lip_utils.DEBUG:
        cv2.imwrite("create_hole_image_top-align_line.jpg",img_lined)


    # これまた、hole用の画像をなんとなく、サイズに合わせている。
    # そのため、画像の位置調整が非常に微妙になる
    # TODO 画像の指定引数 https://github.com/akjava/lip_recognition_tools/issues/9
    # https://github.com/akjava/lip_recognition_tools/issues/10
    #hole_image = cv2.imread("hole_images/hole_01_light_dark.jpg")
    hole_image = cv2.imread(f"hole_images/{hole_image_name}")
    hole_image = vertical_slide(hole_image,hole_offset)
    if lip_utils.DEBUG:
        cv2.imwrite("create_hole_image-slided_hole_image.jpg",hole_image)
    #exit(0)

    hole_image_h,hole_image_w = lip_utils.get_image_size(hole_image)
    max_w = hole_image_w
    max_h = hole_image_h
    expand_list = expand_points.tolist()
    aligned_hole_image = lip_utils.create_moved_image(hole_image, [(0,0),(max_w,0),
                    (0,max_h),(max_w,max_h)],
                    expand_list
                    
                    )
    if lip_utils.DEBUG:
        cv2.imwrite("create_hole_image_top-align_image.jpg",aligned_hole_image)

    img_face = np.copy(img)
    lip_utils.copy_image(img_face,aligned_hole_image,expand_list[0][0] - diff_align_x,(expand_list[0][1]+expand_list[1][1])//2)
    if lip_utils.DEBUG:
        cv2.imwrite("create_hole_image_top-align_face.jpg",img_face)
    return img_face


if __name__ == "__main__":
  # 画像ファイルのパス
  img_path = "00012245.jpg" #"straight.jpg"
  img = cv2.imread(img_path)
  landmarks_list = lip_utils.image_to_landmarks_list(img)
  process_create_hole_image(img,landmarks_list)