Last active
November 10, 2023 08:25
-
-
Save innat/80ccd3fc2453f90a7e574024e82333ed to your computer and use it in GitHub Desktop.
Utility function to create mask (png) from polygon (json).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Optional | |
# I had the json (annotation) and image file in the same folder. That's why I did also | |
from pathlib import Path | |
import shutil | |
src_path = 'Mixed_Image_JSON_PATH' | |
trg_path = 'Separate_Path_For_Image' | |
for src_file in Path(src_path).glob('*.jpeg*'): | |
shutil.copy(src_file, trg_path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Case 2: Multiple Class Maks | |
# String to integer labels. | |
# Assuming we havae 5 classes like below (excluding background). | |
categories = { | |
'human' : 1, | |
'dog' : 2, | |
'cat' : 3, | |
'bus' : 4, | |
'road' : 5 | |
} | |
labels = sorted(categories.keys()) | |
# A function that will fill the polygon regions | |
def create_masks(raw_img_height, raw_img_width, points): | |
blank = np.zeros(shape=(raw_img_height, raw_img_width), dtype=np.uint8) | |
points = np.array(points, dtype=np.int32) | |
cv2.fillPoly(blank, [points], 255) | |
return np.array(blank, dtype=bool) | |
# A function that will assemble all the class mask | |
def create_multi_masks(raw_img_height, raw_img_width, shape_dicts): | |
channels = [] | |
cls = [x['label'] for x in shape_dicts] | |
poly = [np.array(x['points'], dtype=np.int32) for x in shape_dicts] | |
label2poly = dict(zip(cls, poly)) | |
background = np.zeros(shape=(raw_img_height, raw_img_width), dtype=np.int32) | |
# iterate through objects of interest | |
for i, label in enumerate(labels): | |
if label in cls: | |
cls_id = categories[label] | |
mask = create_masks(raw_img_height, raw_img_width, label2poly[label]) | |
background[mask] = cls_id | |
channels.append(background) | |
Y = np.stack(channels, axis=2) | |
return Y | |
show = True | |
save = True | |
input_dir = 'json_annotation_file_directory' | |
json_mask_path = sorted( | |
[ | |
os.path.join(input_dir, fname) | |
for fname in os.listdir(input_dir) | |
if fname.endswith(".json") | |
] | |
) | |
# CHECK | |
len(json_mask_path), json_mask_path[0] | |
# Loop over the json files | |
poly_to_mask_saving_path = 'mask' # I create a folder manually, and maned as 'mask' | |
for i, path in enumerate(json_mask_path): | |
shape_info, width, height = get_poly(path) | |
cls = [x['label'] for x in shape_info] | |
poly_to_mask = create_multi_masks(height, width, shape_info) | |
print(json.dumps(categories, indent=4, sort_keys=True)) | |
print(path, cls) | |
print(poly_to_mask.dtype, poly_to_mask.shape, np.unique(poly_to_mask)) | |
if show: | |
plt.imshow(poly_to_mask) | |
plt.show() | |
if save: | |
poly_name = path.split('\\')[1].split('.')[0] | |
print(f"{poly_to_mask_saving_path}/{poly_name}.png") | |
cv2.imwrite(f"{poly_to_mask_saving_path}/{poly_name}.png", poly_to_mask) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cv2 | |
import math | |
import json, os | |
import numpy as np | |
from tqdm import tqdm | |
import matplotlib.pyplot as plt | |
from PIL import Image, ImageDraw | |
# It reads polygon containing json file. | |
# Below is the informaation structure inside a json file. | |
''' | |
{ | |
... | |
... | |
"shapes": [ | |
{ | |
"label": "cat", | |
"points": [ | |
[ | |
19.0, | |
572.25 | |
], | |
[ | |
89.0, | |
638.5 | |
], | |
... | |
... | |
"group_id": null, | |
"shape_type": "polygon", | |
"imageHeight": 1204, | |
"imageWidth": 1827 | |
''' | |
# read json file and return some specific properties | |
def get_poly(annot_path): | |
with open(annot_path, encoding = 'utf-8') as handle: | |
data = json.load(handle) | |
return data['shapes'], data['imageWidth'], data['imageHeight'] | |
# Case 1: Binary Maks | |
def create_binary_masks(raw_img_height, raw_img_width, shape_dicts): | |
# image must be grayscal | |
blank = np.zeros(shape=(raw_img_height, raw_img_width), dtype=np.float32) | |
# Iterate over the ['shapes'] properites of json file. | |
for shape in shape_dicts: | |
# shape['label'] may or may not contain 'background' label | |
# and here for making binary mask, we fill 255 value except the background | |
# note, shape['label'] may coontain multiple class. | |
if shape['label'] != 'background': | |
points = np.array(shape['points'], dtype=np.int32) | |
cv2.fillPoly(blank, [points], 255) | |
# normalize the mask, from value (0, 255) to (0, 1) | |
blank = blank / 255.0 | |
# add channel axis | |
return np.expand_dims(blank, axis=2) | |
show = True | |
save = True | |
input_dir = 'mixed_150_train' # 'mixed_50_train' 'mixed_150_train' 'mixed_10_val' | |
json_mask_path = sorted( | |
[ | |
os.path.join(input_dir, fname) | |
for fname in os.listdir(input_dir) | |
if fname.endswith(".json") | |
] | |
) | |
# check | |
len(json_mask_path), json_mask_path[0] | |
# file saving location | |
poly_to_mask_saving_path = 'binary_mask' | |
try: | |
os.mkdir(poly_to_mask_saving_path) | |
except FileExistsError: | |
print('Directory not created.') | |
# Iterate over the JSON file and save Mask as PNG | |
for i, path in enumerate(json_mask_path): | |
shape_info, width, height = get_poly(path) | |
bin_mask = create_binary_masks(height, width, shape_info) | |
print(bin_mask.shape) | |
if show: | |
plt.imshow(bin_mask) | |
plt.title(str(np.unique(bin_mask))) | |
plt.show() | |
if save: | |
poly_name = path.split('\\')[1].split('.')[0] | |
print(poly_name) | |
print(f"{poly_to_mask_saving_path}/{poly_name}.png") | |
cv2.imwrite(f"{poly_to_mask_saving_path}/{poly_name}.png", bin_mask) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
From Mask to Polygon: Check: https://stackoverflow.com/a/60573495/9215780