| 1355 | |
| 1356 | |
| 1357 | class ImageEditing: |
| 1358 | template_model = True |
| 1359 | def __init__(self, Text2Box:Text2Box, Segmenting:Segmenting, Inpainting:Inpainting): |
| 1360 | print(f"Initializing ImageEditing") |
| 1361 | self.sam = Segmenting |
| 1362 | self.grounding = Text2Box |
| 1363 | self.inpaint = Inpainting |
| 1364 | |
| 1365 | def pad_edge(self,mask,padding): |
| 1366 | #mask Tensor [H,W] |
| 1367 | mask = mask.numpy() |
| 1368 | true_indices = np.argwhere(mask) |
| 1369 | mask_array = np.zeros_like(mask, dtype=bool) |
| 1370 | for idx in true_indices: |
| 1371 | padded_slice = tuple(slice(max(0, i - padding), i + padding + 1) for i in idx) |
| 1372 | mask_array[padded_slice] = True |
| 1373 | new_mask = (mask_array * 255).astype(np.uint8) |
| 1374 | #new_mask |
| 1375 | return new_mask |
| 1376 | |
| 1377 | @prompts(name="Remove Something From The Photo", |
| 1378 | description="useful when you want to remove and object or something from the photo " |
| 1379 | "from its description or location. " |
| 1380 | "The input to this tool should be a comma separated string of two, " |
| 1381 | "representing the image_path and the object need to be removed. ") |
| 1382 | def inference_remove(self, inputs): |
| 1383 | image_path, to_be_removed_txt = inputs.split(",")[0], ','.join(inputs.split(',')[1:]) |
| 1384 | return self.inference_replace_sam(f"{image_path},{to_be_removed_txt},background") |
| 1385 | |
| 1386 | @prompts(name="Replace Something From The Photo", |
| 1387 | description="useful when you want to replace an object from the object description or " |
| 1388 | "location with another object from its description. " |
| 1389 | "The input to this tool should be a comma separated string of three, " |
| 1390 | "representing the image_path, the object to be replaced, the object to be replaced with ") |
| 1391 | def inference_replace_sam(self,inputs): |
| 1392 | image_path, to_be_replaced_txt, replace_with_txt = inputs.split(",") |
| 1393 | |
| 1394 | print(f"image_path={image_path}, to_be_replaced_txt={to_be_replaced_txt}") |
| 1395 | image_pil, image = self.grounding.load_image(image_path) |
| 1396 | boxes_filt, pred_phrases = self.grounding.get_grounding_boxes(image, to_be_replaced_txt) |
| 1397 | image = cv2.imread(image_path) |
| 1398 | image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) |
| 1399 | self.sam.sam_predictor.set_image(image) |
| 1400 | masks = self.sam.get_mask_with_boxes(image_pil, image, boxes_filt) |
| 1401 | mask = torch.sum(masks, dim=0).unsqueeze(0) |
| 1402 | mask = torch.where(mask > 0, True, False) |
| 1403 | mask = mask.squeeze(0).squeeze(0).cpu() #tensor |
| 1404 | |
| 1405 | mask = self.pad_edge(mask,padding=20) #numpy |
| 1406 | mask_image = Image.fromarray(mask) |
| 1407 | |
| 1408 | updated_image = self.inpaint(prompt=replace_with_txt, image=image_pil, |
| 1409 | mask_image=mask_image) |
| 1410 | updated_image_path = get_new_image_name(image_path, func_name="replace-something") |
| 1411 | updated_image = updated_image.resize(image_pil.size) |
| 1412 | updated_image.save(updated_image_path) |
| 1413 | print( |
| 1414 | f"\nProcessed ImageEditing, Input Image: {image_path}, Replace {to_be_replaced_txt} to {replace_with_txt}, " |
nothing calls this directly
no outgoing calls
no test coverage detected