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