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