File size: 8,507 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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
"""
bottom_lip.py

open_mouthの一部 下唇レイヤーの生成
単独ではまだ動かない。


著者: Akihito Miyazaki
作成日: 2024-04-23
更新履歴:
  - 2024-04-23: 最初のリリース

"""

import cv2
import numpy as np
from PIL import Image
from lip_utils import *
import lip_utils
from scipy.ndimage import binary_dilation, gaussian_filter

def process_lip_image(img,landmarks_list, crop_image_margin, open_size_y, open_size_x):
    """
    唇画像を処理する関数

    open_size_x  最終画像で端をカットしている
    side_tipsに値をコピーしている。side_tips
    """
    # 画像の読み込み
    
    side_tips = 0 # remove cropped pixel
    edge_x =0 # remove side pixel from final image
 
    
    # 口の開きに応じて、中心を下げようとしたが、真ん中が下がるのは極めて不自然なのでやめた。
    # そのうち、5分割の中心を変形するのに使いたい
    mid_lip_move_ratio = open_size_y/80.0 if open_size_y>0 else 0
    mid_lip_move_ratio = 0

    if open_size_x>0:# ここ謎コード? そのうち検証したい
       print("only support shorten use minus open")
       side_tips = open_size_x
       edge_x = int(open_size_x*1.5) #som magic number
       #edge_x = 0
       open_size_x = 0 # TODO move (some transform broken)

    # 不自然にはみ出す、サイドのカット用だが、いまいち機能しないので使用停止
    # TOP と HOLEが未対応なのでOFF
    side_tips = 0 # remove cropped pixel
    edge_x =0 # remove side pixel from final image


    img_h, img_w = lip_utils.get_image_size(img)
    
    # 唇領域の抽出と処理 (マージンが追加される。透明化処理が怪しい)
    gaus = 4
    box = lip_utils.get_points_box(landmarks_list, lip_utils.POINTS_BOTTOM_LIP, crop_image_margin)
    align_points = lip_utils.get_bottom_lip_align_points(landmarks_list)
    alpha_image, rec = get_alpha_image(img, landmarks_list, lip_utils.POINTS_BOTTOM_LIP, crop_image_margin, crop_image_margin, gaus)

    
    # 最後に返す画像の元を作成
    h, w = lip_utils.get_image_size(alpha_image)
    if lip_utils.DEBUG:
      cv2.imwrite("debug/bottom_lip_alpha.png",alpha_image)
    print(f"bottom-lip cropped w = {w} h = {h}")
    bottom_lip_final_image=lip_utils.create_rgba(w,h+open_size_y+1)# some how transform image expand TODO まだ必要か確認
    bottom_lip_final_image_h,bottom_lip_final_image_w = lip_utils.get_image_size(bottom_lip_final_image)
    print(f"bottom_lip_final_image:w = {bottom_lip_final_image_w} h = {bottom_lip_final_image_h}")


    #local_align_points = lip_utils.offset_points(align_points,box[0])
    #print(align_points)


    # 唇の位置、いまだ検討中 https://github.com/akjava/lip_recognition_tools/issues/2
    mid_left = int(w/5*2)
    mid_left = int(w/3)

    mid_right = bottom_lip_final_image_w - mid_left
    print(f"image width = {bottom_lip_final_image_w} mid_left = {mid_left} mid_right ={mid_right}")

    mid_center = int((mid_right+mid_left)/2) # 過去に真ん中下げに使っていたが必要ないと思っている。
    mid_move_y_divided = 5 # 0 means no move

    # 真ん中左の唇の変形 中心さげのに、無駄に2分割している。 https://github.com/akjava/lip_recognition_tools/issues/3

    mid_image_left = lip_utils.crop_image(alpha_image,mid_left,0,mid_center,h)
    mid_image_left_h,mid_image_left_w = lip_utils.get_image_size(mid_image_left)
    max_w = mid_image_left_w
    max_h = mid_image_left_h
    opend_mid_lip_left = lip_utils.create_moved_image(mid_image_left, 
                    [(0,0),(max_w,0),
                    (0,max_h),(max_w,max_h)],

                    [(-0,-0),(max_w,int(max_h*mid_lip_move_ratio)),#int(max_h/2)
                    (0,max_h),(max_w,max_h)]
                    )
    # 予定外にサイズが伸びると、エラーになるので避けたいが、もう少し検証が必要
    #opend_mid_lip_left = cv2.resize(opend_mid_lip_left, (max_w, max_h), interpolation=cv2.INTER_AREA)
    lip_utils.print_width_height(mid_image_left,"mid-left")
    lip_utils.print_width_height(opend_mid_lip_left,"moved-mid-left")
    

    # 真ん中右の唇の変形 
    mid_image_right = lip_utils.crop_image(alpha_image,mid_center,0,mid_right,h)
    mid_image_right_h,mid_image_right_w = lip_utils.get_image_size(mid_image_right)
    max_w = mid_image_right_w
    max_h = mid_image_right_h
    
    opend_mid_lip_right = lip_utils.create_moved_image(mid_image_right, 
                    [(0,0),(max_w,0),
                    (0,max_h),(max_w,max_h)],

                    [(-0,int(max_h*mid_lip_move_ratio)),(max_w,0),#int(max_h/2)
                    (0,max_h),(max_w,max_h)]
                    )
    
    #opend_mid_lip_right = cv2.resize(opend_mid_lip_right, (max_w, max_h), interpolation=cv2.INTER_AREA)
    lip_utils.print_width_height(mid_image_right,"mid-right")
    lip_utils.print_width_height(opend_mid_lip_right,"moved-mid-right")


    #no remove side-tip area
    left_image = lip_utils.crop_image(alpha_image,side_tips,0,mid_left,h)
    right_image = lip_utils.crop_image(alpha_image,mid_right,0,w-side_tips,h)

    # 左の唇を下げる 左側は固定
    left_lip_image_h,left_lip_image_w = lip_utils.get_image_size(left_image)
    print(f"left-image:w = {left_lip_image_w} h = {left_lip_image_h}")

    max_w = left_lip_image_w
    max_h = left_lip_image_h
    opend_lip_left = lip_utils.create_moved_image(left_image, 
                    [(0,0),(max_w,0),
                    (0,max_h),(max_w,max_h)],

                    [(0,-0),(max_w+open_size_x,open_size_y),
                    (0,max_h-0),(max_w+open_size_x,max_h+open_size_y)]
                    )
    left_lip_image_h,left_lip_image_w = lip_utils.get_image_size(opend_lip_left)
    max_w = left_lip_image_w
    max_h = left_lip_image_h

    new_h,new_w = lip_utils.get_image_size(opend_lip_left)
    print(f"left-image moved:w = {new_w} h = {new_h}")
    if lip_utils.DEBUG:
      cv2.imwrite("open_botto_lip_left.png",opend_lip_left)


    # 右の唇を下げる 右側は固定
    right_lip_image_h,right_lip_image_w = lip_utils.get_image_size(right_image)
    max_w = right_lip_image_w
    max_h = right_lip_image_h
    opend_lip_right = lip_utils.create_moved_image(right_image, 
                    [(0,0),(max_w,0),
                    (0,max_h),(max_w,max_h)],

                    [(0,open_size_y),(max_w+open_size_x,-0),
                    (0,max_h+open_size_y),(0+max_w+open_size_x,max_h-0)]
                    )
    new_h,new_w = lip_utils.get_image_size(opend_lip_right)
    print(f"right-image moved :w = {new_w} h = {new_h}")
    if lip_utils.DEBUG:
      cv2.imwrite("open_botto_lip_right.png",opend_lip_right)




    # 変形後の各画像を描く alpha含めた全コピーなので注意(元画像のAlphaは無視)
    #is this ok?
    #lip_utils.copy_image(bottom_lip_final_image,mid_image,mid_left-1,open_size_y)
    #lip_utils.copy_image(bottom_lip_final_image,mid_image,mid_left,open_size_y)
    ## 中央部分
    lip_utils.copy_image(bottom_lip_final_image,opend_mid_lip_left,mid_left,open_size_y)
    lip_utils.copy_image(bottom_lip_final_image,opend_mid_lip_right,mid_center,open_size_y)


    print(lip_utils.get_image_size(opend_lip_left))
    print(lip_utils.get_image_size(bottom_lip_final_image))
   
    ## 左右の端 side_tips
    lip_utils.copy_image(bottom_lip_final_image,opend_lip_left,open_size_x+side_tips,0) 
    lip_utils.copy_image(bottom_lip_final_image,opend_lip_right,mid_right,0)


    #edge_x=22 #for40 #テスト中

    # 両端の処理 https://github.com/akjava/lip_recognition_tools/issues/6
    lip_utils.fade_in_x(bottom_lip_final_image,edge_x*2)
    lip_utils.fade_out_x(bottom_lip_final_image,edge_x*2)

    # 最終的な画像の作成と保存
    if lip_utils.DEBUG:
      cv2.imwrite("bottom_lip_opend.png", bottom_lip_final_image)
    face_size_image = lip_utils.create_rgba(img_w, img_h)
    lip_utils.copy_image(face_size_image, bottom_lip_final_image, box[0][0], box[0][1])
    if lip_utils.DEBUG:
      cv2.imwrite("bottom_lip_layer.png", face_size_image)
    return face_size_image


if __name__ == "__main__":
  # 画像ファイルのパス
  img_path = "straight.jpg"
  # パラメータ
  crop_image_margin = 16
  open_size_y = 10
  open_size_x = -10

  # 関数の呼び出し
  process_lip_image(img_path, crop_image_margin, open_size_y, open_size_x)