Files

174 lines
7.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
from PIL import Image
from json import JSONEncoder
import numpy as np
from .util import tensor_to_pil, pil_to_tensor, hex_to_rgba
import folder_paths
class InsightFaceBBOXDetect:
def __init__(self):
self.models = {}
@classmethod
def INPUT_TYPES(self):
return {
"required": {
"image": ('IMAGE', {}),
"shape": (['rectangle', 'circle', ], {'default': 'rectangle'}),
"shape_color": ('STRING', {'default': '#FF0000'}),
"show_num": ("BOOLEAN", {'default': False}),
},
"optional": {
"num_color": ('STRING', {'default': '#FF0000'}),
"num_pos": (['center', 'left-top', 'right-top', 'left-bottom', 'right-bottom', ], {}),
"num_sort": (['origin', 'left-right', 'right-left', 'top-bottom', 'bottom-top', 'small-large', 'large-small'], {}),
"INSIGHTFACE": ('INSIGHTFACE', {})
}
}
RETURN_TYPES = ("IMAGE", "STRING", "INT", "INSIGHTFACE",)
RETURN_NAMES = ("bbox_image", "bbox", "face_size", "INSIGHTFACE",)
FUNCTION = "detect"
OUTPUT_NODE = False
CATEGORY = "EasyApi/Detect"
# INPUT_IS_LIST = False
# OUTPUT_IS_LIST = (False, False)
DESCRIPTION = "检测图片中的人脸,bbox是一个包含所有人脸的json字符串,格式是每个人脸区域的左上角和右下角角坐标: [[x1_1,y1_1,x1_2,y1_2],[x2_1,y2_1,x2_2,y2_2],...]"
def detect(self, image, shape, shape_color, show_num, num_color='#FF0000', num_pos=None, num_sort=None,
INSIGHTFACE=None):
model = INSIGHTFACE
import cv2
if model is None:
if 'insightface' not in self.models:
from insightface.app import FaceAnalysis
INSIGHTFACE_DIR = os.path.join(folder_paths.models_dir, "insightface")
model = FaceAnalysis(name="buffalo_l", root=INSIGHTFACE_DIR,
providers=['CUDAExecutionProvider', 'CPUExecutionProvider', ])
model.prepare(ctx_id=0, det_size=(640, 640))
self.models['insightface'] = model
else:
model = self.models['insightface']
img = cv2.cvtColor(np.array(tensor_to_pil(image)), cv2.COLOR_RGB2BGR)
faces = model.get(img)
if num_sort == 'reactor' or num_sort == 'left-right':
faces = sorted(faces, key=lambda x: x.bbox[0])
if num_sort == "right-left":
faces = sorted(faces, key=lambda x: x.bbox[0], reverse=True)
if num_sort == "top-bottom":
faces = sorted(faces, key=lambda x: x.bbox[1])
if num_sort == "bottom-top":
faces = sorted(faces, key=lambda x: x.bbox[1], reverse=True)
if num_sort == "small-large":
faces = sorted(faces, key=lambda x: (x.bbox[2] - x.bbox[0]) * (x.bbox[3] - x.bbox[1]))
if num_sort == "large-small":
faces = sorted(faces, key=lambda x: (x.bbox[2] - x.bbox[0]) * (x.bbox[3] - x.bbox[1]), reverse=True)
r, g, b, a = hex_to_rgba(shape_color)
n_r, n_g, n_b, n_a = hex_to_rgba(num_color)
img_with_bbox, bbox = draw_on(img, faces, shape=shape, show_num=show_num, num_pos=num_pos, shape_color=(b, g, r), font_color=(n_b, n_g, n_r))
img_with_bbox = Image.fromarray(cv2.cvtColor(img_with_bbox, cv2.COLOR_BGR2RGB))
bbox_json = JSONEncoder().encode(bbox)
return pil_to_tensor(img_with_bbox), bbox_json, len(bbox), model
def draw_on(img, faces, shape=None, show_num=False, num_pos=None, shape_color=(0, 0, 255), font_color=(0, 255, 0), font_scale=1):
import cv2
dimg = img.copy()
bbox = []
for i in range(len(faces)):
face = faces[i]
box = face.bbox.astype(int)
s_x = box[0]
s_y = box[1]
e_x = box[2]
e_y = box[3]
bbox.append(box.tolist())
if shape == 'rectangle':
# (图片,长方形框左上角坐标, 长方形框右下角坐标, 颜色(BGR),粗细)
cv2.rectangle(dimg, (s_x, s_y), (e_x, e_y), shape_color, 2)
elif shape == 'circle':
# img:输入的图片data
# center:圆心位置
# radius:圆的半径
# color:圆的颜色
# thickness:圆形轮廓的粗细(如果为正)。负厚度表示要绘制实心圆。
# lineType: 圆边界的类型。cv2.LINE_AA--更平滑
# shift:中心坐标和半径值中的小数位数。
c_x = s_x + round((e_x - s_x) / 2)
c_y = s_y + round((e_y - s_y) / 2)
radius = round(pow(pow(e_x - s_x, 2) + pow(e_y - s_y, 2), 0.5)/2)
cv2.circle(dimg, (c_x, c_y), radius, shape_color, thickness=2, lineType=cv2.LINE_AA)
# if face.kps is not None:
# kps = face.kps.astype(int)
# #print(landmark.shape)
# for l in range(kps.shape[0]):
# color = (0, 0, 255)
# if l == 0 or l == 3:
# color = (0, 255, 0)
# cv2.circle(dimg, (kps[l][0], kps[l][1]), 1, color, 2)
if show_num is True:
# 图片, 要添加的文字, 文字添加到图片上的位置, 字体的类型, 字体大小(font scale), 字体颜色, 字体粗细,
# font_scale = 2
thickness = 2
# BGR
# width和height是基于字体base line位置的长高,bottom是base line下方字体的高度,按css中文字对齐方式的思想理解
text = '%d' % i
(width, height), bottom = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, font_scale, thickness)
offset_top_y = height + 4
offset_bottom_y = bottom + 2
offset_x = 2
if num_pos == 'center':
c_x = s_x + round((e_x - s_x) / 2)
c_y = s_y + round((e_y - s_y) / 2)
cv2.putText(dimg, text, (c_x - round(width / 2), c_y + round((height + bottom) / 2)),
cv2.FONT_HERSHEY_COMPLEX, font_scale, font_color, thickness)
elif num_pos == 'left-top':
cv2.putText(dimg, text, (s_x + offset_x, s_y + offset_top_y), cv2.FONT_HERSHEY_COMPLEX, font_scale,
font_color, thickness)
pass
elif num_pos == 'right-top':
cv2.putText(dimg, text, (e_x - width - offset_x, s_y + offset_top_y), cv2.FONT_HERSHEY_COMPLEX,
font_scale,
font_color, thickness)
elif num_pos == 'left-bottom':
cv2.putText(dimg, text, (s_x + offset_x, e_y - offset_bottom_y), cv2.FONT_HERSHEY_COMPLEX, font_scale,
font_color, thickness)
elif num_pos == 'right-bottom':
cv2.putText(dimg, text, (e_x - width - offset_x, e_y - offset_bottom_y), cv2.FONT_HERSHEY_COMPLEX,
font_scale, font_color, thickness)
# cv2.putText(dimg, '%s,%d' % (face.sex, face.age), (box[0], box[1]), cv2.FONT_HERSHEY_COMPLEX, 0.7,
# (0, 255, 0), 1)
# for key, value in face.items():
# if key.startswith('landmark_3d'):
# # print(key, value.shape)
# # print(value[0:10,:])
# lmk = np.round(value).astype(int)
# for l in range(lmk.shape[0]):
# color = (255, 0, 0)
# cv2.circle(dimg, (lmk[l][0], lmk[l][1]), 1, color, 2)
return dimg, bbox
NODE_CLASS_MAPPINGS = {
"InsightFaceBBOXDetect": InsightFaceBBOXDetect,
}
# A dictionary that contains the friendly/humanly readable titles for the nodes
NODE_DISPLAY_NAME_MAPPINGS = {
"InsightFaceBBOXDetect": "InsightFaceBBOXDetect",
}