Improved projection "fill holes"
This commit is contained in:
@@ -789,54 +789,6 @@
|
||||
1024
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 250,
|
||||
"type": "Hy3DDiffusersSchedulerConfig",
|
||||
"pos": [
|
||||
-314.72770034835025,
|
||||
2141.9033917044144
|
||||
],
|
||||
"size": [
|
||||
390.5999755859375,
|
||||
82
|
||||
],
|
||||
"flags": {
|
||||
"collapsed": true
|
||||
},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "pipeline",
|
||||
"type": "HY3DDIFFUSERSPIPE",
|
||||
"link": 450
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "diffusers_scheduler",
|
||||
"type": "NOISESCHEDULER",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
455
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"aux_id": "visualbruno/ComfyUI-Hunyuan3DWrapper",
|
||||
"ver": "6090a9051f109d2774d309cf6a8a22d4a11a1b15",
|
||||
"Node name for S&R": "Hy3DDiffusersSchedulerConfig",
|
||||
"widget_ue_connectable": {
|
||||
"scheduler": true,
|
||||
"sigmas": true
|
||||
},
|
||||
"cnr_id": "comfyui-hunyan3dwrapper"
|
||||
},
|
||||
"widgets_values": [
|
||||
"Euler",
|
||||
"default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 248,
|
||||
"type": "Hy3DRenderMultiView",
|
||||
@@ -1857,8 +1809,8 @@
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"Node name for S&R": "Preview3D",
|
||||
"Last Time Model File": "C:/Git/ComfyUI/output/3D/Pistol_MV/Pistol_MV_Textured_MV_00001_.glb",
|
||||
"Resource Folder": "Git/ComfyUI/output/3D/Pistol_MV",
|
||||
"Last Time Model File": "C:/Git/ComfyUI/output/3D/AnimeGirl/AnimeGirl_Textured_MV_00002_.glb",
|
||||
"Resource Folder": "Git/ComfyUI/output/3D/AnimeGirl",
|
||||
"Scene Config": {
|
||||
"showGrid": true,
|
||||
"backgroundColor": "#282828",
|
||||
@@ -1870,13 +1822,13 @@
|
||||
"fov": 35,
|
||||
"state": {
|
||||
"position": {
|
||||
"x": -9.285925508472754,
|
||||
"y": 6.135860681339741,
|
||||
"z": -3.084115266640774
|
||||
"x": -2.7373252313099936,
|
||||
"y": 5.5744471940243105,
|
||||
"z": 7.192391392495912
|
||||
},
|
||||
"target": {
|
||||
"x": 0,
|
||||
"y": 2.3565700410649804,
|
||||
"y": 2.5,
|
||||
"z": 0
|
||||
},
|
||||
"zoom": 1,
|
||||
@@ -1888,10 +1840,221 @@
|
||||
}
|
||||
},
|
||||
"widgets_values": [
|
||||
"C:/Git/ComfyUI/output/3D/Pistol_MV/Pistol_MV_Textured_MV_00001_.glb",
|
||||
"C:/Git/ComfyUI/output/3D/AnimeGirl/AnimeGirl_Textured_MV_00002_.glb",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 209,
|
||||
"type": "PrimitiveInt",
|
||||
"pos": [
|
||||
-1941.870656950478,
|
||||
277.2558588777398
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
82
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "INT",
|
||||
"type": "INT",
|
||||
"links": [
|
||||
400
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Target Face Number",
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"Node name for S&R": "PrimitiveInt"
|
||||
},
|
||||
"widgets_values": [
|
||||
500000,
|
||||
"fixed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "Trellis2LoadImageWithTransparency",
|
||||
"pos": [
|
||||
-1948.5694294982507,
|
||||
430.5866991705322
|
||||
],
|
||||
"size": [
|
||||
631.9393495485403,
|
||||
765.9737728955563
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": null
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null
|
||||
},
|
||||
{
|
||||
"name": "image_with_alpha",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
344
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Normal Image",
|
||||
"properties": {
|
||||
"aux_id": "visualbruno/ComfyUI-Trellis2",
|
||||
"ver": "e7f9b30df7a09bcedf1c955e176754c73f983254",
|
||||
"Node name for S&R": "Trellis2LoadImageWithTransparency",
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
"AnimeGirl_1024_00001_.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 239,
|
||||
"type": "Trellis2LoadImageWithTransparency",
|
||||
"pos": [
|
||||
-1939.1565291278416,
|
||||
1247.0590522961702
|
||||
],
|
||||
"size": [
|
||||
627.638044195148,
|
||||
672.4931923313359
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
483
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null
|
||||
},
|
||||
{
|
||||
"name": "image_with_alpha",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Color Image",
|
||||
"properties": {
|
||||
"aux_id": "visualbruno/ComfyUI-Trellis2",
|
||||
"ver": "e8098f5641702e74133c2dea0b45a13a3ab19985",
|
||||
"Node name for S&R": "Trellis2LoadImageWithTransparency"
|
||||
},
|
||||
"widgets_values": [
|
||||
"AnimeGirl_808_00001_.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 219,
|
||||
"type": "PrimitiveString",
|
||||
"pos": [
|
||||
-1941.3621908316666,
|
||||
157.6667334107927
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
464,
|
||||
465
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Name -> output in 3D folder",
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"Node name for S&R": "PrimitiveString"
|
||||
},
|
||||
"widgets_values": [
|
||||
"AnimeGirl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 250,
|
||||
"type": "Hy3DDiffusersSchedulerConfig",
|
||||
"pos": [
|
||||
-308.8898175615872,
|
||||
2137.2330213377168
|
||||
],
|
||||
"size": [
|
||||
390.5999755859375,
|
||||
82
|
||||
],
|
||||
"flags": {
|
||||
"collapsed": true
|
||||
},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "pipeline",
|
||||
"type": "HY3DDIFFUSERSPIPE",
|
||||
"link": 450
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "diffusers_scheduler",
|
||||
"type": "NOISESCHEDULER",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
455
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"aux_id": "visualbruno/ComfyUI-Hunyuan3DWrapper",
|
||||
"ver": "6090a9051f109d2774d309cf6a8a22d4a11a1b15",
|
||||
"Node name for S&R": "Hy3DDiffusersSchedulerConfig",
|
||||
"widget_ue_connectable": {
|
||||
"scheduler": true,
|
||||
"sigmas": true
|
||||
},
|
||||
"cnr_id": "comfyui-hunyan3dwrapper"
|
||||
},
|
||||
"widgets_values": [
|
||||
"Euler",
|
||||
"default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 264,
|
||||
"type": "Trellis2MultiViewTexturing",
|
||||
@@ -1901,7 +2064,7 @@
|
||||
],
|
||||
"size": [
|
||||
363.3228515625,
|
||||
386
|
||||
410
|
||||
],
|
||||
"flags": {},
|
||||
"order": 38,
|
||||
@@ -1991,173 +2154,11 @@
|
||||
2,
|
||||
1.1,
|
||||
1.15,
|
||||
"",
|
||||
true,
|
||||
10,
|
||||
"",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 209,
|
||||
"type": "PrimitiveInt",
|
||||
"pos": [
|
||||
-1941.870656950478,
|
||||
277.2558588777398
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
82
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "INT",
|
||||
"type": "INT",
|
||||
"links": [
|
||||
400
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Target Face Number",
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"Node name for S&R": "PrimitiveInt"
|
||||
},
|
||||
"widgets_values": [
|
||||
500000,
|
||||
"fixed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "Trellis2LoadImageWithTransparency",
|
||||
"pos": [
|
||||
-1948.5694294982507,
|
||||
430.5866991705322
|
||||
],
|
||||
"size": [
|
||||
631.9393495485403,
|
||||
765.9737728955563
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": null
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null
|
||||
},
|
||||
{
|
||||
"name": "image_with_alpha",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
344
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Normal Image",
|
||||
"properties": {
|
||||
"aux_id": "visualbruno/ComfyUI-Trellis2",
|
||||
"ver": "e7f9b30df7a09bcedf1c955e176754c73f983254",
|
||||
"Node name for S&R": "Trellis2LoadImageWithTransparency",
|
||||
"widget_ue_connectable": {}
|
||||
},
|
||||
"widgets_values": [
|
||||
"Image_1024_00081_.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 239,
|
||||
"type": "Trellis2LoadImageWithTransparency",
|
||||
"pos": [
|
||||
-1939.1565291278416,
|
||||
1247.0590522961702
|
||||
],
|
||||
"size": [
|
||||
627.638044195148,
|
||||
672.4931923313359
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
483
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null
|
||||
},
|
||||
{
|
||||
"name": "image_with_alpha",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Color Image",
|
||||
"properties": {
|
||||
"aux_id": "visualbruno/ComfyUI-Trellis2",
|
||||
"ver": "e8098f5641702e74133c2dea0b45a13a3ab19985",
|
||||
"Node name for S&R": "Trellis2LoadImageWithTransparency"
|
||||
},
|
||||
"widgets_values": [
|
||||
"Image_1024_00065_.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 219,
|
||||
"type": "PrimitiveString",
|
||||
"pos": [
|
||||
-1941.3621908316666,
|
||||
157.6667334107927
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
464,
|
||||
465
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Name -> output in 3D folder",
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.16.4",
|
||||
"Node name for S&R": "PrimitiveString"
|
||||
},
|
||||
"widgets_values": [
|
||||
"Pistol_MV"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
@@ -2722,10 +2723,10 @@
|
||||
"workflowRendererVersion": "LG",
|
||||
"ue_links": [],
|
||||
"ds": {
|
||||
"scale": 0.3899868676879694,
|
||||
"scale": 0.835971485622887,
|
||||
"offset": [
|
||||
2537.916276869781,
|
||||
-243.0909834796268
|
||||
1391.1352648291552,
|
||||
-2311.024721130755
|
||||
]
|
||||
},
|
||||
"links_added_by_ue": [],
|
||||
|
||||
@@ -3852,7 +3852,8 @@ class Trellis2MultiViewTexturing:
|
||||
"blend_exponent": ("FLOAT", {"default": 2.0, "min": 0.5, "max": 8.0, "step": 0.5}),
|
||||
"ortho_scale": ("FLOAT", {"default": 1.0, "min": 0.05, "max": 10.0, "step": 0.01}),
|
||||
"norm_size": ("FLOAT",{"default":1.15, "min":0.0, "max":9.99, "step":0.01}),
|
||||
"fill_holes": ("BOOLEAN",{"default":False}),
|
||||
"fill_holes": ("BOOLEAN",{"default":True}),
|
||||
"max_hole_size": ("INT",{"default":10,"min":0,"max":99999,"step":1}),
|
||||
},
|
||||
"optional": {
|
||||
# Standard views
|
||||
@@ -3885,6 +3886,7 @@ class Trellis2MultiViewTexturing:
|
||||
ortho_scale,
|
||||
norm_size,
|
||||
fill_holes,
|
||||
max_hole_size,
|
||||
baseColorTexture = None,
|
||||
front_image=None,
|
||||
back_image=None,
|
||||
@@ -3964,7 +3966,8 @@ class Trellis2MultiViewTexturing:
|
||||
ortho_scale=ortho_scale,
|
||||
blend_texture=blend_texture,
|
||||
fill_holes=fill_holes,
|
||||
norm_size=norm_size
|
||||
norm_size=norm_size,
|
||||
max_hole_size=max_hole_size
|
||||
)
|
||||
|
||||
return (trimesh_obj, pil2tensor(base_color), pil2tensor(mr))
|
||||
|
||||
@@ -53,6 +53,7 @@ import math
|
||||
|
||||
import cumesh as CuMesh
|
||||
|
||||
from tqdm import tqdm
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Camera helpers
|
||||
@@ -138,6 +139,7 @@ def texture_mesh_with_multiview(
|
||||
norm_size: float = 1.15,
|
||||
fill_holes: bool = False,
|
||||
blend_texture: bool = True,
|
||||
max_hole_size: int = 10,
|
||||
):
|
||||
if not (len(images) == len(azimuths) == len(elevations)):
|
||||
raise ValueError("images, azimuths, and elevations must have the same length")
|
||||
@@ -339,36 +341,96 @@ def texture_mesh_with_multiview(
|
||||
n_projected = int(composite_mask.sum().item())
|
||||
print(f" Projected texels: {n_projected} / {texture_size*texture_size}"
|
||||
f" ({100.0*n_projected/(texture_size*texture_size):.1f}%)")
|
||||
|
||||
if fill_holes:
|
||||
print('Filling holes ...')
|
||||
|
||||
hole_mask = (~valid_mask.cpu().numpy()).astype(np.uint8)
|
||||
n_holes = int(hole_mask.sum())
|
||||
print(f" Inpainting {n_holes} hole texels ({100.0*n_holes/hole_mask.size:.1f}%)...")
|
||||
|
||||
if n_holes > 0:
|
||||
for c in range(3):
|
||||
color_np[..., c] = cv2.inpaint(color_np[..., c], hole_mask, 3, cv2.INPAINT_NS)
|
||||
alpha_np = cv2.inpaint(alpha_np, hole_mask, 3, cv2.INPAINT_NS)
|
||||
else:
|
||||
# No existing texture found – fall back to projection-only output
|
||||
print(" WARNING: No existing PBR baseColorTexture found on mesh, "
|
||||
"outputting projection-only texture (holes will be transparent).")
|
||||
color_np = (projected_color.cpu().numpy() * 255).clip(0, 255).astype(np.uint8)
|
||||
alpha_np = composite_mask.cpu().numpy().astype(np.uint8) * 255
|
||||
|
||||
if fill_holes:
|
||||
print('Filling holes ...')
|
||||
|
||||
hole_mask = (~valid_mask.cpu().numpy()).astype(np.uint8)
|
||||
n_holes = int(hole_mask.sum())
|
||||
print(f" Inpainting {n_holes} hole texels ({100.0*n_holes/hole_mask.size:.1f}%)...")
|
||||
|
||||
if n_holes > 0:
|
||||
for c in range(3):
|
||||
color_np[..., c] = cv2.inpaint(color_np[..., c], hole_mask, 3, cv2.INPAINT_NS)
|
||||
alpha_np = cv2.inpaint(alpha_np, hole_mask, 3, cv2.INPAINT_NS)
|
||||
if fill_holes:
|
||||
print('Filling holes and padding UV seams ...')
|
||||
|
||||
# Get numpy arrays
|
||||
uv_mask_np = uv_hit_mask.cpu().numpy().astype(np.uint8)
|
||||
valid_mask_np = valid_mask.cpu().numpy().astype(np.uint8)
|
||||
|
||||
# 1. INTERNAL HOLES: Pixels inside the UV map that didn't get colored
|
||||
internal_hole_mask = cv2.bitwise_and(cv2.bitwise_not(valid_mask_np), uv_mask_np)
|
||||
|
||||
if max_hole_size > 0:
|
||||
# Filter internal holes by size to avoid filling massive intentional gaps
|
||||
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(internal_hole_mask, connectivity=8)
|
||||
areas = stats[:, cv2.CC_STAT_AREA]
|
||||
valid_labels_mask = (areas <= max_hole_size)
|
||||
valid_labels_mask[0] = False # Ignore background
|
||||
filtered_internal_holes = valid_labels_mask[labels].astype(np.uint8)
|
||||
else:
|
||||
filtered_internal_holes = internal_hole_mask
|
||||
|
||||
# 2. UV SEAM PADDING: A small band of pixels just outside the UV islands
|
||||
# We dilate the UV mask by a few pixels to create a "bleed" area
|
||||
pad_radius = 5 # You can increase this if the black lines persist at long distances
|
||||
kernel = np.ones((3, 3), np.uint8)
|
||||
dilated_uv = cv2.dilate(uv_mask_np, kernel, iterations=pad_radius)
|
||||
|
||||
# The padding mask is the dilated area MINUS the original UV area
|
||||
seam_padding_mask = cv2.bitwise_and(dilated_uv, cv2.bitwise_not(uv_mask_np))
|
||||
|
||||
# 3. COMBINE AND INPAINT
|
||||
# We want to inpaint both the internal dots and the external seams simultaneously
|
||||
final_inpaint_mask = cv2.bitwise_or(filtered_internal_holes, seam_padding_mask)
|
||||
|
||||
n_holes = int(filtered_internal_holes.sum())
|
||||
n_pad = int(seam_padding_mask.sum())
|
||||
print(f" Inpainting {n_holes} internal texels and {n_pad} seam padding texels...")
|
||||
|
||||
if (n_holes + n_pad) > 0:
|
||||
for c in range(3):
|
||||
color_np[..., c] = cv2.inpaint(color_np[..., c], final_inpaint_mask, 3, cv2.INPAINT_NS)
|
||||
alpha_np = cv2.inpaint(alpha_np, final_inpaint_mask, 3, cv2.INPAINT_NS)
|
||||
|
||||
# if fill_holes:
|
||||
# print('Filling holes ...')
|
||||
|
||||
# # 1. Get the raw mask of all holes (1 for hole, 0 for valid)
|
||||
# raw_hole_mask = (~valid_mask.cpu().numpy()).astype(np.uint8)
|
||||
|
||||
# # 2. Filter by size if a limit is set
|
||||
# if max_hole_size > 0:
|
||||
# filtered_hole_mask = np.zeros_like(raw_hole_mask)
|
||||
# # Find connected components (connectivity=8 handles diagonals)
|
||||
# num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(raw_hole_mask, connectivity=8)
|
||||
|
||||
# print(f"Num Labels: {num_labels}")
|
||||
# # Label 0 is the background (non-holes), so we start checking from Label 1
|
||||
|
||||
# if num_labels>0:
|
||||
# progress_bar = tqdm(total=num_labels, desc="Filling holes")
|
||||
|
||||
# for label_id in range(1, num_labels):
|
||||
# area = stats[label_id, cv2.CC_STAT_AREA]
|
||||
# if area <= max_hole_size:
|
||||
# # If the hole is small enough, add it to our filtered mask
|
||||
# filtered_hole_mask[labels == label_id] = 1
|
||||
# progress_bar.update(1)
|
||||
|
||||
# progress_bar.close()
|
||||
|
||||
# print(f"Number of filtered holes: {len(filtered_hole_mask)}")
|
||||
|
||||
# hole_mask = filtered_hole_mask
|
||||
# else:
|
||||
# hole_mask = raw_hole_mask
|
||||
|
||||
# n_holes = int(hole_mask.sum())
|
||||
# print(f" Inpainting {n_holes} hole texels ({100.0*n_holes/hole_mask.size:.1f}%)...")
|
||||
|
||||
# if n_holes > 0:
|
||||
# for c in range(3):
|
||||
# color_np[..., c] = cv2.inpaint(color_np[..., c], hole_mask, 3, cv2.INPAINT_NS)
|
||||
# alpha_np = cv2.inpaint(alpha_np, hole_mask, 3, cv2.INPAINT_NS)
|
||||
|
||||
|
||||
# =========================================================================
|
||||
|
||||
Reference in New Issue
Block a user