3 Commits
Author SHA1 Message Date
toto d9ade2e531 add two super node, simplify progress 2023-10-25 21:15:49 +08:00
toto 4abaf4cd92 retain face choose face 2023-10-25 11:50:21 +08:00
toto 60bebf7b02 add more info 2023-10-24 22:05:04 +08:00
9 changed files with 347 additions and 254 deletions
+12 -4
View File
@@ -1,6 +1,6 @@
# [Portrait-Maker](https://github.com/THtianhao/ComfyUI-Portrait-Maker)
This project is an adaptation of [EasyPhoto](https://github.com/aigc-apps/sd-webui-EasyPhoto), which breaks down the process of [EasyPhoto](https://github.com/aigc-apps/sd-webui-EasyPhoto) and will add a series of operations on human portraits in the future.
![](./images/easyphoto.png)
![](./images/easyphoto.jpg)
English | [简体中文](./README_zh-CN.md)
@@ -13,11 +13,18 @@ If you have any questions or suggestions, you can reach us through:
- QQ Group: 10419777
- WeChat Group: <img src="./images/wechat.jpg" width="200">
## V1.2.0 Update
1. Add PM_SuperColorTransfer node to simplify the color transfer process
2. Add PM_SuperMakeUpTransfer node to simplify the process of makeup transfer
## V1.1.0 Update
1. faceskin adds blur option
2. Add PM_FaceShapMatch node. See node introduction for details.
3. Add PM_MakeUpTransfer node. See node introduction for details.
3. Add a super-resolution model to the PM_PortraitEnhancement node. This super-resolution model can not highlight faces.
2. Add PM_FaceShapMatch node. same as easyphot faceshap match
3. Add PM_MakeUpTransfer node. same as easyphoto makeup transfer.
4. Add a super-resolution model to the PM_PortraitEnhancement node. This super-resolution model can not highlight faces.
5. Add v1.1.0 workflow
6. RetinaFace supports face selection
## V1.0.0 Update
1. Added log for model downloads.
@@ -67,6 +74,7 @@ Click "Load" in the right panel of ComfyUI and select the ./workflow/easyphoto_w
* RetainFace PM: Perform matting using models from Model Scope. [Link](https://www.modelscope.cn/models/damo/cv_resnet50_face-detection_retinaface/summary)
* image: Input image
* multi_user_facecrop_ratio: Multiplicative factor for extracting the head region.
* face_index : Choose which face
* FaceFusion PM: Merge faces from two images.
* image: Input image
+11 -4
View File
@@ -2,7 +2,7 @@
这个项目改编于[EasyPhoto](https://github.com/aigc-apps/sd-webui-EasyPhoto),对于[EasyPhoto](https://github.com/aigc-apps/sd-webui-EasyPhoto)进行了流程上的拆解,后续会加入其他项目处理人物头像上的系列操作。
![](./images/easyphoto.png)
![](./images/easyphoto.jpg)
English | [简体中文](./README_zh-CN.md)
@@ -15,11 +15,17 @@ English | [简体中文](./README_zh-CN.md)
- QQ 群:10419777
- 微信群: <img src="./images/wechat.jpg" width="200">
## V1.2.0 Update
1. 增加PM_SuperColorTransfer 节点,简化了颜色迁移的流程
2. 增加PM_SuperMakeUpTransfer 节点,简化了进行装扮迁移的流程
## v1.1.0 更新
1. faceskin 增加模糊选项
2. 增加 PM_FaceShapMatch节点 详情查看节点介绍
3. 增加 PM_MakeUpTransfer节点 详情查看节点介绍
3. PM_PortraitEnhancement节点增加一种超分模型,此超分模型可以对人脸不做高光
2. 增加 PM_FaceShapMatch节点 与easyphoto的FaceshapMatch一致
3. 增加 PM_MakeUpTransfer节点 与easyphoto的MakeupTransfer一致
4. PM_PortraitEnhancement节点增加一种超分模型,此超分模型可以对人脸不做高光
5. 增加v1.1.0 workflow
6. RetinaFace 支持选择人脸
## v1.0.0 更新
@@ -70,6 +76,7 @@ Easyphoto工作位置: [./workflow/easyphoto.json](./workflows/easyphoto.json )
* RetainFace PM:使用Model Scope中的模型进行抠图 [链接](https://www.modelscope.cn/models/damo/cv_resnet50_face-detection_retinaface/summary)
* image:输入图像
* multi_user_facecrop_ratio:提取头像区域的倍数
* face_index : 选择第几个人脸
* FaceFusion PM:将两张图像的人脸进行融合
* image:输入图像
* user_image:要融合的头像
+5 -1
View File
@@ -77,6 +77,8 @@ NODE_CLASS_MAPPINGS = {
"PM_GetImageInfo": GetImageInfoPM,
"PM_MakeUpTransfer": MakeUpTransferPM,
"PM_FaceShapMatch": FaceShapMatchPM,
"PM_SuperColorTransfer": SuperColorTransferPM,
"PM_SuperMakeUpTransfer": SuperMakeUpTransferPM,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"PM_RetinaFace": "RetinaFace PM",
@@ -95,7 +97,9 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"PM_ImageResizeTarget": "ImageResizeTarget PM",
"PM_GetImageInfo": "GetImageInfo PM",
"PM_MakeUpTransfer": "MakeUpTransfer PM",
"PM_FaceShapMatch":"FaceShapMatch PM"
"PM_FaceShapMatch": "FaceShapMatch PM",
"PM_SuperColorTransfer": "SuperColorTransfer PM",
"PM_SuperMakeUpTransfer": "SuperMakeUpTransfer PM",
}
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 754 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 280 KiB

+81 -9
View File
@@ -6,14 +6,16 @@ from .utils.face_process_utils import call_face_crop, color_transfer, Face_Skin
from .utils.img_utils import img_to_tensor, tensor_to_img, tensor_to_np, np_to_tensor, np_to_mask, img_to_mask, img_to_np
from .model_holder import *
# import pydevd_pycharm
# pydevd_pycharm.settrace('49.7.62.197', port=10090, stdoutToServer=True, stderrToServer=True)
import pydevd_pycharm
pydevd_pycharm.settrace('49.7.62.197', port=10090, stdoutToServer=True, stderrToServer=True)
class RetinaFacePM:
@classmethod
def INPUT_TYPES(s):
return {"required": {"image": ("IMAGE",),
"multi_user_facecrop_ratio": ("FLOAT", {"default": 1, "min": 0, "max": 10, "step": 0.01})
"multi_user_facecrop_ratio": ("FLOAT", {"default": 1, "min": 0, "max": 10, "step": 0.01}),
"face_index": ("INT", {"default": 0, "min": 0, "max": 10, "step": 1})
}}
RETURN_TYPES = ("IMAGE", "MASK", "BOX")
@@ -21,12 +23,14 @@ class RetinaFacePM:
FUNCTION = "retain_face"
CATEGORY = "protrait/model"
def retain_face(self, image, multi_user_facecrop_ratio):
def retain_face(self, image, multi_user_facecrop_ratio, face_index):
np_image = np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8)
image = Image.fromarray(np_image)
retinaface_boxes, retinaface_keypoints, retinaface_masks, retinaface_tensor = call_face_crop(get_retinaface_detection(), image, multi_user_facecrop_ratio)
crop_image = image.crop(retinaface_boxes[0])
return (img_to_tensor(crop_image), retinaface_tensor, retinaface_boxes[0])
retinaface_boxes, retinaface_keypoints, retinaface_masks, retinaface_mask_nps = call_face_crop(get_retinaface_detection(), image, multi_user_facecrop_ratio)
crop_image = image.crop(retinaface_boxes[face_index])
retinaface_mask = np_to_mask(retinaface_mask_nps[face_index])
retinaface_boxe = retinaface_boxes[face_index]
return (img_to_tensor(crop_image), retinaface_mask, retinaface_boxe)
class FaceFusionPM:
@@ -345,8 +349,6 @@ class MakeUpTransferPM:
CATEGORY = "protrait/model"
def makeup_transfer(self, source_image, makeup_image):
source_image = tensor_to_img(source_image).resize([256, 256])
makeup_image = tensor_to_img(makeup_image).resize([256, 256])
result = get_pagan_interface().transfer(source_image, makeup_image)
return (img_to_tensor(result),)
@@ -386,3 +388,73 @@ class FaceShapMatchPM:
input_image_uint8 = np.array(source_image) * face_skin_mask + np.array(match_image) * (1 - face_skin_mask)
return (np_to_tensor(input_image_uint8),)
class SuperColorTransferPM:
@classmethod
def INPUT_TYPES(s):
return \
{
"required": {
"main_image": ("IMAGE",),
"transfer_image": ("IMAGE",),
},
"optional": {
"avatar_box": ("BOX",),
},
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "super_color_transfer"
CATEGORY = "protrait/model"
def super_color_transfer(self, main_image, transfer_image, avatar_box=None):
origin_np = tensor_to_np(main_image)
if avatar_box is not None:
main_image = main_image[:, avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :]
transfer_image = transfer_image[:, avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :]
transfer_result = color_transfer(tensor_to_np(main_image), tensor_to_np(transfer_image)) # 进行颜色迁移
face_skin_img = get_face_skin()(Image.fromarray(transfer_result), get_retinaface_detection(), [[1, 2, 3, 4, 5, 10, 12, 13]])[0]
face_skin_np = img_to_np(face_skin_img)
face_skin_np = cv2.blur(face_skin_np, (32, 32)) / 255
masked_img_np = tensor_to_np(main_image) * (1 - face_skin_np) + transfer_result * face_skin_np
origin_np[avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :] = masked_img_np
return (np_to_tensor(origin_np),)
class SuperMakeUpTransferPM:
@classmethod
def INPUT_TYPES(s):
return \
{
"required": {
"main_image": ("IMAGE",),
"makeup_image": ("IMAGE",),
},
"optional": {
"avatar_box": ("BOX",),
},
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "super_makeup_transfer"
CATEGORY = "protrait/model"
def super_makeup_transfer(self, main_image, makeup_image, avatar_box=None):
box_width, box_height = avatar_box[2] - avatar_box[0], avatar_box[3] - avatar_box[1]
origin_np = tensor_to_np(main_image)
if avatar_box is not None:
main_image = main_image[:, avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :]
makeup_image = makeup_image[:, avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :]
resize_source_box_image = tensor_to_img(main_image).resize([256, 256])
resize_makeup_box_image = tensor_to_img(makeup_image).resize([256, 256])
transfer_image = get_pagan_interface().transfer(resize_source_box_image, resize_makeup_box_image)
box_size_transfer = transfer_image.resize([box_width, box_height], Image.Resampling.LANCZOS)
origin_np[avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :] = img_to_np(box_size_transfer)
return (np_to_tensor(origin_np),)
+4 -5
View File
@@ -65,9 +65,8 @@ def safe_get_box_mask_keypoints(image, retinaface_result, crop_ratio, face_seg,
retinaface_boxs = [retinaface_boxs[index] for index in argindex]
retinaface_keypoints = [retinaface_keypoints[index] for index in argindex]
retinaface_mask_pils = [retinaface_mask_pils[index] for index in argindex]
retinaface_mask_np = [retinaface_masks[index] for index in argindex]
mask_tensor = np_to_mask(retinaface_mask_np[0])
return retinaface_boxs, retinaface_keypoints, retinaface_mask_pils, mask_tensor
retinaface_mask_nps = [retinaface_masks[index] for index in argindex]
return retinaface_boxs, retinaface_keypoints, retinaface_mask_pils, retinaface_mask_nps
else:
retinaface_box = np.array([])
@@ -120,9 +119,9 @@ def call_face_crop(retinaface_detection, image, crop_ratio, prefix="tmp"):
# retinaface detect
retinaface_result = retinaface_detection(image)
# get mask and keypoints
retinaface_box, retinaface_keypoints, retinaface_mask_pil, retinaface_mask_tensor = safe_get_box_mask_keypoints(image, retinaface_result, crop_ratio, None, "crop")
retinaface_box, retinaface_keypoints, retinaface_mask_pil, retinaface_mask_nps = safe_get_box_mask_keypoints(image, retinaface_result, crop_ratio, None, "crop")
return retinaface_box, retinaface_keypoints, retinaface_mask_pil, retinaface_mask_tensor
return retinaface_box, retinaface_keypoints, retinaface_mask_pil, retinaface_mask_nps
def color_transfer(sc, dc):
"""
@@ -1,6 +1,6 @@
{
"last_node_id": 231,
"last_link_id": 419,
"last_link_id": 424,
"nodes": [
{
"id": 50,
@@ -443,7 +443,7 @@
"1": 46
},
"flags": {},
"order": 79,
"order": 77,
"mode": 0,
"inputs": [
{
@@ -486,7 +486,7 @@
"1": 46
},
"flags": {},
"order": 76,
"order": 74,
"mode": 0,
"inputs": [
{
@@ -620,7 +620,7 @@
"1": 82
},
"flags": {},
"order": 75,
"order": 73,
"mode": 0,
"inputs": [
{
@@ -663,7 +663,7 @@
"1": 246
},
"flags": {},
"order": 78,
"order": 76,
"mode": 0,
"inputs": [
{
@@ -724,7 +724,7 @@
"1": 166
},
"flags": {},
"order": 77,
"order": 75,
"mode": 0,
"inputs": [
{
@@ -793,7 +793,7 @@
"1": 166
},
"flags": {},
"order": 80,
"order": 78,
"mode": 0,
"inputs": [
{
@@ -856,7 +856,7 @@
"1": 474.0000305175781
},
"flags": {},
"order": 81,
"order": 79,
"mode": 0,
"inputs": [
{
@@ -907,33 +907,6 @@
"color": "#323",
"bgcolor": "#535"
},
{
"id": 145,
"type": "PreviewImage",
"pos": [
4959.059430539544,
2873.60691902383
],
"size": {
"0": 360.20330810546875,
"1": 542.2775268554688
},
"flags": {},
"order": 83,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 246
}
],
"properties": {
"Node name for S&R": "PreviewImage"
},
"color": "#323",
"bgcolor": "#535"
},
{
"id": 147,
"type": "LoraLoader",
@@ -1239,7 +1212,7 @@
"1": 86
},
"flags": {},
"order": 66,
"order": 64,
"mode": 0,
"inputs": [
{
@@ -1356,7 +1329,7 @@
"1": 272.66497802734375
},
"flags": {},
"order": 68,
"order": 66,
"mode": 0,
"inputs": [
{
@@ -1383,7 +1356,7 @@
"1": 312.9284362792969
},
"flags": {},
"order": 70,
"order": 68,
"mode": 0,
"inputs": [
{
@@ -1410,13 +1383,13 @@
"1": 46
},
"flags": {},
"order": 60,
"order": 58,
"mode": 0,
"inputs": [
{
"name": "image",
"type": "IMAGE",
"link": 403
"link": 420
},
{
"name": "box",
@@ -1483,7 +1456,7 @@
"1": 313.27972412109375
},
"flags": {},
"order": 72,
"order": 70,
"mode": 0,
"inputs": [
{
@@ -1510,7 +1483,7 @@
"1": 46
},
"flags": {},
"order": 62,
"order": 60,
"mode": 0,
"inputs": [
{
@@ -1554,7 +1527,7 @@
"1": 311.90179443359375
},
"flags": {},
"order": 64,
"order": 62,
"mode": 0,
"inputs": [
{
@@ -1812,51 +1785,6 @@
"color": "#323",
"bgcolor": "#535"
},
{
"id": 144,
"type": "VAEDecode",
"pos": [
4652.0594305395425,
2881.6069190238295
],
"size": {
"0": 210,
"1": 46
},
"flags": {},
"order": 82,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 244
},
{
"name": "vae",
"type": "VAE",
"link": 245
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
246,
271,
312
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "VAEDecode"
},
"color": "#323",
"bgcolor": "#535"
},
{
"id": 178,
"type": "PreviewImage",
@@ -1893,7 +1821,7 @@
],
"size": {
"0": 210,
"1": 26
"1": 58
},
"flags": {},
"order": 110,
@@ -1919,6 +1847,9 @@
"properties": {
"Node name for S&R": "PM_PortraitEnhancement"
},
"widgets_values": [
"pgen"
],
"color": "#2a363b",
"bgcolor": "#3f5159"
},
@@ -2061,13 +1992,13 @@
"1": 66
},
"flags": {},
"order": 69,
"order": 67,
"mode": 0,
"inputs": [
{
"name": "origin_image",
"type": "IMAGE",
"link": 402
"link": 421
},
{
"name": "box_area",
@@ -2112,7 +2043,7 @@
"1": 78
},
"flags": {},
"order": 71,
"order": 69,
"mode": 0,
"inputs": [
{
@@ -2158,7 +2089,7 @@
"1": 325.4287414550781
},
"flags": {},
"order": 74,
"order": 72,
"mode": 0,
"inputs": [
{
@@ -2185,7 +2116,7 @@
"1": 78
},
"flags": {},
"order": 73,
"order": 71,
"mode": 0,
"inputs": [
{
@@ -2378,7 +2309,7 @@
"1": 332.3785095214844
},
"flags": {},
"order": 61,
"order": 59,
"mode": 0,
"inputs": [
{
@@ -2672,7 +2603,7 @@
{
"name": "image",
"type": "IMAGE",
"link": 271
"link": 423
},
{
"name": "box",
@@ -2968,7 +2899,7 @@
"1": 26
},
"flags": {},
"order": 65,
"order": 63,
"mode": 0,
"inputs": [
{
@@ -3033,7 +2964,7 @@
"1": 82
},
"flags": {},
"order": 63,
"order": 61,
"mode": 0,
"inputs": [
{
@@ -3095,8 +3026,8 @@
"id": 6,
"type": "LoadImage",
"pos": [
683,
370
249.94248304953703,
302.33370767033864
],
"size": {
"0": 303.5721130371094,
@@ -3301,7 +3232,7 @@
"1": 289.9919128417969
},
"flags": {},
"order": 67,
"order": 65,
"mode": 0,
"inputs": [
{
@@ -3459,10 +3390,10 @@
2380,
1020
],
"size": [
374.8711860380299,
444.2354070414972
],
"size": {
"0": 374.8711853027344,
"1": 444.23541259765625
},
"flags": {},
"order": 44,
"mode": 0,
@@ -3845,7 +3776,7 @@
{
"name": "origin_image",
"type": "IMAGE",
"link": 312
"link": 424
},
{
"name": "box_area",
@@ -3932,10 +3863,10 @@
7570.006255877076,
1602.40493563089
],
"size": [
210,
246
],
"size": {
"0": 210,
"1": 246
},
"flags": {},
"order": 103,
"mode": 0,
@@ -4353,95 +4284,28 @@
"bgcolor": "#535"
},
{
"id": 61,
"type": "VAEDecode",
"id": 145,
"type": "PreviewImage",
"pos": [
3798,
-70
4605,
2907
],
"size": {
"0": 210,
"1": 46
"0": 360.20330810546875,
"1": 542.2775268554688
},
"flags": {},
"order": 55,
"order": 81,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 79
},
{
"name": "vae",
"type": "VAE",
"link": 142
}
],
"outputs": [
{
"name": "IMAGE",
"name": "images",
"type": "IMAGE",
"links": [
82,
419
],
"shape": 3,
"slot_index": 0
"link": 246
}
],
"properties": {
"Node name for S&R": "VAEDecode"
},
"color": "#323",
"bgcolor": "#535"
},
{
"id": 224,
"type": "PM_FaceShapMatch",
"pos": [
4244,
-66
],
"size": {
"0": 229.20001220703125,
"1": 66
},
"flags": {},
"order": 58,
"mode": 0,
"inputs": [
{
"name": "source_image",
"type": "IMAGE",
"link": 419
},
{
"name": "match_image",
"type": "IMAGE",
"link": 400
},
{
"name": "face_box",
"type": "BOX",
"link": 398
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
401,
402,
403
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "PM_FaceShapMatch"
"Node name for S&R": "PreviewImage"
},
"color": "#323",
"bgcolor": "#535"
@@ -4450,8 +4314,8 @@
"id": 223,
"type": "Reroute",
"pos": [
4088,
-28
5004,
2846
],
"size": [
75,
@@ -4484,19 +4348,158 @@
"color": "#323",
"bgcolor": "#535"
},
{
"id": 61,
"type": "VAEDecode",
"pos": [
3798,
-70
],
"size": {
"0": 210,
"1": 46
},
"flags": {},
"order": 55,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 79
},
{
"name": "vae",
"type": "VAE",
"link": 142
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
82,
420,
421
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "VAEDecode"
},
"color": "#323",
"bgcolor": "#535"
},
{
"id": 224,
"type": "PM_FaceShapMatch",
"pos": [
5097,
2791
],
"size": {
"0": 229.20001220703125,
"1": 66
},
"flags": {},
"order": 82,
"mode": 0,
"inputs": [
{
"name": "source_image",
"type": "IMAGE",
"link": 422
},
{
"name": "match_image",
"type": "IMAGE",
"link": 400
},
{
"name": "face_box",
"type": "BOX",
"link": 398
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
401,
423,
424
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "PM_FaceShapMatch"
},
"color": "#323",
"bgcolor": "#535"
},
{
"id": 144,
"type": "VAEDecode",
"pos": [
4678,
2799
],
"size": {
"0": 210,
"1": 46
},
"flags": {},
"order": 80,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 244
},
{
"name": "vae",
"type": "VAE",
"link": 245
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
246,
422
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "VAEDecode"
},
"color": "#323",
"bgcolor": "#535"
},
{
"id": 225,
"type": "PreviewImage",
"pos": [
4148,
101
],
"size": [
370.333740234375,
482.09925079345703
5014,
2933
],
"size": {
"0": 370.333740234375,
"1": 482.0992431640625
},
"flags": {},
"order": 59,
"order": 83,
"mode": 0,
"inputs": [
{
@@ -5201,14 +5204,6 @@
1,
"MASK"
],
[
271,
144,
0,
159,
0,
"IMAGE"
],
[
272,
159,
@@ -5385,14 +5380,6 @@
2,
"IMAGE"
],
[
312,
144,
0,
168,
0,
"IMAGE"
],
[
319,
17,
@@ -5737,22 +5724,6 @@
0,
"IMAGE"
],
[
402,
224,
0,
131,
0,
"IMAGE"
],
[
403,
224,
0,
112,
0,
"IMAGE"
],
[
414,
195,
@@ -5794,20 +5765,52 @@
"IMAGE"
],
[
419,
420,
61,
0,
112,
0,
"IMAGE"
],
[
421,
61,
0,
131,
0,
"IMAGE"
],
[
422,
144,
0,
224,
0,
"IMAGE"
],
[
423,
224,
0,
159,
0,
"IMAGE"
],
[
424,
224,
0,
168,
0,
"IMAGE"
]
],
"groups": [
{
"title": "Roop Image",
"bounding": [
672,
295,
239,
227,
333,
410
],