agrobot_base/Python/OAK/datasets/_2_augmentation.py

110 lines
3.6 KiB
Python
Raw Normal View History

2025-08-11 23:11:23 +00:00
import json, os, cv2
2025-08-08 20:09:17 +00:00
from PIL import Image
import albumentations as A
2025-07-17 11:19:42 +00:00
2025-08-07 18:23:53 +00:00
# ⚙️ Configurações
2025-08-08 20:09:17 +00:00
with open("config.json", "r") as f:
config = json.load(f)
MODELO = config["camera"]
2025-08-08 20:09:17 +00:00
# Pastas
dataset_path = os.path.join(MODELO, "dataset", "original", "images")
2025-08-08 20:09:17 +00:00
masks_path = os.path.join(MODELO, "dataset", "original", "masks")
aug_img_out = os.path.join(MODELO, "dataset", "augmented", "images")
aug_msk_out = os.path.join(MODELO, "dataset", "augmented", "masks")
os.makedirs(aug_img_out, exist_ok=True)
os.makedirs(aug_msk_out, exist_ok=True)
# Pipeline de augmentations
train_tf = A.Compose([
A.HorizontalFlip(p=0.5),
# Geométricas (aplicam em imagem e máscara)
A.ShiftScaleRotate(
shift_limit=0.05,
scale_limit=0.15,
rotate_limit=8,
border_mode=cv2.BORDER_CONSTANT,
value=(255,255,255),
mask_value=(255,255,255),
interpolation=cv2.INTER_LINEAR,
p=0.5
),
# Fotométricas (somente imagem)
A.OneOf([
A.RandomBrightnessContrast(0.2, 0.2, p=1),
A.HueSaturationValue(hue_shift_limit=5, sat_shift_limit=25, val_shift_limit=20, p=1),
A.RandomGamma(gamma_limit=(80,120), p=1),
], p=0.7),
A.OneOf([
A.MotionBlur(blur_limit=3, p=1),
A.GaussianBlur(blur_limit=3, p=1),
], p=0.25),
A.OneOf([
A.GaussNoise(var_limit=(5.0, 15.0), p=1),
A.ImageCompression(quality_lower=40, quality_upper=80, p=1),
], p=0.25),
A.RandomShadow(p=0.2),
A.RandomSunFlare(p=0.1),
A.ChannelShuffle(p=0.05),
A.CoarseDropout(max_holes=8, max_height=20, max_width=20, p=0.2)
# Resize final (img=LINEAR, mask=NEAREST)
#A.Resize(height=H, width=W, interpolation=cv2.INTER_LINEAR, mask_interpolation=cv2.INTER_NEAREST),
], additional_targets={'mask':'mask'})
def load_rgb(path):
# cv2 lê BGR → converte pra RGB (Albumentations usa RGB por padrão)
im = cv2.imread(path, cv2.IMREAD_COLOR)
if im is None:
raise FileNotFoundError(path)
return cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
def save_rgb(path, arr_rgb):
# Salva em RGB mantendo cores corretas
Image.fromarray(arr_rgb).save(path)
def augment_images_and_masks(n_copies=6):
# Faz pareamento por nome base (sem extensão)
imgs = sorted([f for f in os.listdir(dataset_path) if os.path.isfile(os.path.join(dataset_path,f))])
msks = sorted([f for f in os.listdir(masks_path) if os.path.isfile(os.path.join(masks_path,f))])
# Mapeia máscaras por nome-base
msk_map = {os.path.splitext(m)[0]: m for m in msks}
total = 0
for img_file in imgs:
base, ext = os.path.splitext(img_file)
if base not in msk_map:
print(f"[WARN] Máscara não encontrada para {img_file}, pulando.")
continue
img_path = os.path.join(dataset_path, img_file)
msk_path = os.path.join(masks_path, msk_map[base])
# Carrega RGB (máscara como RGB também — mantemos as cores exatas)
img = load_rgb(img_path)
msk = load_rgb(msk_path)
for i in range(n_copies):
# Aplica aug; máscara recebe só geométricas
aug = train_tf(image=img, mask=msk)
img_aug = aug["image"]
msk_aug = aug["mask"]
# Salva
out_img = os.path.join(aug_img_out, f"{base}_aug_{i:02d}{ext}")
out_msk = os.path.join(aug_msk_out, f"{base}_aug_{i:02d}{os.path.splitext(msk_map[base])[1]}")
save_rgb(out_img, img_aug)
save_rgb(out_msk, msk_aug)
total += 1
print(f"Augmentation completed! {total} pares gerados.")
if __name__ == "__main__":
augment_images_and_masks(n_copies=8)