1

I would like to save the output image as json for future annotation. The following code is able to show the output prediction. Would like to seek your help to assist me on how to save the output as json format. Many thanks.

from detectron2.utils.visualizer import ColorMode

path = '/content/drive/MyDrive/Detectron2/test/*.png'

for file in glob.glob(path):
    print(file)
    im = cv2.imread(file, 1)
    outputs = predictor(im)
    print(outputs)
    v = Visualizer(im[:, :, ::-1],
                    metadata=train_metadata, 
                    scale=0.5,
                   instance_mode=ColorMode.SEGMENTATION
    )
    out = v.draw_instance_predictions(outputs["instances"].to("cpu"))
    cv2_imshow(out.get_image()[:, :, ::-1])

1 Answers1

0

I'm sharing my code snapshot that saves the inference output of Detection2 and exports the prediction polygons to a CSV file. Modifying the last code block can easily allow you to save the polygons to JSON or a shapefile.

The first code block handles inference and saves the predictions (outputs) as PKL files, while also saving the Visualizer plots as PNG images.

import pandas as pd
import glob


test_folder = Path(os.getcwd() + r"\dataset\test") #We need test_folder to be Path object, not string, for test_folder.glob to work
print ('The folder of images: ', test_folder)

for i, imageName in enumerate(test_folder.glob("*.png")):
    file = str(imageName)
    file_name = file.split("\\")[-1] # split and get the file name only
    im = cv2.imread(file)
    outputs = predictor(im) #Inference 

    # attributes variables
    predictions_output = {}
    predictions_output["file_name"] = file_name
    predictions_output["file_location"] = file
    predictions_output["prediction"] = outputs 
    
    # save the results with iteration no as pickle objects.
    predictions_pkl = 'predictions_' + str(i) + '.pkl'
    predictions_pkl_file = os.getcwd() + r"\dataset\predictions" + '\\' + predictions_pkl
    #print ('## The predictions_pkl_file: ', predictions_pkl_file)   
    
    with open(predictions_pkl_file , "wb") as f: # wb opens the file in binary format for writing 
        pickle.dump(predictions_output, f)
        
    v = Visualizer(
        im[:, :, ::-1],
        metadata=metadata,
        scale=1,
    )

    out = v.draw_instance_predictions(outputs["instances"].to("cpu"))
    plt.figure(figsize=(20, 20))
    plt.imshow(out.get_image()[:, :, ::-1])
    # save the visualizer result
    saved_image = os.getcwd() + r"\dataset\output_images" + '\\' + file_name
    plt.savefig(saved_image)

The 'outputs' variable contains the inference output, including ["pred_boxes"] and ["pred_masks"], in the format described in the Detectron2 tutorial: https://detectron2.readthedocs.io/tutorials/models.html#model-output-format.

The 'pred_masks' values are in binary (False, True). The OpenCV function 'findContours' is used to extract the contours of each predicted mask. Thus, the second code block is responsible for extracting 'pred_boxes,' 'pred_masks,' and contours from the 'outputs' or predictions.

from shapely.geometry import Polygon

csv_df = pd.DataFrame()
    for prediction in glob.glob(os.getcwd() + r"\dataset\predictions\*pkl"):
        fileName_absolute = os.path.basename(prediction)                 ## get the file name 
        print("The pkl_file name: ", fileName_absolute)
        # Read the pkl file
        pickleFile = open(prediction,"rb")
        pickel_Info = pickle.load(pickleFile)
        
        # Get the 'pred_boxes' values in the pkl file:
        boxes = (
            pickel_Info["prediction"]["instances"]
            .get_fields()["pred_boxes"]
            .tensor.cpu()
            .numpy()
        )
    
        # Get the 'pred_mask' values in the pkl file:
        masks = (
            pickel_Info["prediction"]["instances"]
            .get_fields()["pred_masks"]
            .cpu()
            .numpy()
            .astype('uint8')
        )
    
        # Extract the 'contour' of each 'pred_box' by converting pred_box boolean to a 8-bit numpy array:
        # Refer to this post to get and visualise the contours: https://stackoverflow.com/questions/73217530/extract-the-masks-values-from-detectron2-object-detection-segmentation-and-then
        contours = []
        for pred_mask in pickel_Info["prediction"]['instances'].pred_masks:
            mask = pred_mask.cpu().numpy().astype('uint8')
            contour, _ = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
            contours.append(contour[0]) # contour is a tuple (OpenCV 4.5.2), so take the first element which is the array of contour points
        
    
        # save boxes and masks-polygons
        dataset = []
        counter_box = 0
        for i, box in enumerate(boxes):
            data = {}
            data["file_name"] = pickel_Info['file_name']
            data["file_location"] = pickel_Info["file_location"]
            data["image_height"] = pickel_Info["prediction"]["instances"].image_size[0]
            data["image_width"] = pickel_Info["prediction"]["instances"].image_size[1]
            data["bounding_box"] = box
            data["mask"] = masks[i]
            data["contours"] = contours[i]
            data["polygon"] = Polygon(np.squeeze(contours[i]))
            data["id"] = "id_{counter_box}"
            counter_box = counter_box + 1
    
            dataset.append(data)
    
        df = pd.DataFrame(dataset)
    
        
        # keep specific columns for the csv file
        df = df[
            [
                "file_name",
                "id",
                "bounding_box",
                "polygon",
            ]
        ]
    
        csv_df = csv_df.append(df)
    print ('## csv_df: ', csv_df)

The third block involves saving the DataFrame to a CSV file.

csv_df.to_csv(os.getcwd() + r"\dataset\predictions_csv\result_polygons.csv')

I hope this helps you!

Alfa
  • 23
  • 6