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) |