Recycling-CV / dataset.py
shun-ren
added more py files for build import
0f049b3
Raw
History Blame Contribute Delete
3.94 kB
# -------------------------------------------------------------
# This script:
# Downloads the Trash-Type Image Dataset from Kaggle
# Keeps only the classes: paper, plastic, metal (groups others)
# Splits data into train / val / test
# Copies them into the folder structure:
# data/images/train/paper/
# data/images/val/plastic/
# data/images/test/metal/
# -------------------------------------------------------------
import os, shutil, random
from pathlib import Path
import kagglehub
# ---- CLASS FILTERING ----
CLASS_KEEP = {"paper", "plastic", "metal"} # Classes we care about
TO_OTHERS = {"glass", "cardboard", "trash"} # Classes to group as "others"
# ---- TARGET DIRECTORY ----
TARGET = Path("data/images") # Where to save the new dataset
# ---- DATA SPLIT RATIOS ----
SPLITS = {"train":0.7,"val":0.15,"test":0.15}
# ---- IMAGE EXTENSIONS TO LOOK FOR ----
IMG_EXTS = (".jpg",".jpeg",".png",".bmp",".webp")
# ---- SET FIXED RANDOM SEED (for reproducibility) ----
random.seed(42)
# -------------------------------------------------------------
# STEP 1: INFER CLASS FROM FILE PATH
# -------------------------------------------------------------
def infer_class(path: Path) -> str:
parts = [p.lower() for p in path.parts]
for p in reversed(parts): # Search backwards in path parts
if p in CLASS_KEEP:
return p
if p in TO_OTHERS:
return "others"
return "others" # Fallback if no match found
# -------------------------------------------------------------
# STEP 2: FIND ALL IMAGES IN THE DOWNLOADED DATASET
# -------------------------------------------------------------
def gather_images(root: Path):
imgs = []
for fp in root.rglob("*"): # Recursively walk through subfolders
if fp.suffix.lower() in IMG_EXTS:
cls = infer_class(fp.parent)
imgs.append((fp, cls))
return imgs
# -------------------------------------------------------------
# STEP 3: SPLIT INTO TRAIN/VAL/TEST AND COPY FILES
# -------------------------------------------------------------
def split_and_copy(items):
by_cls = {}
# Group all images by class
for fp, cls in items:
by_cls.setdefault(cls, []).append(fp)
TARGET.mkdir(parents=True, exist_ok=True)
# For each class, randomly split its images
for cls, files in by_cls.items():
random.shuffle(files)
n = len(files); n_tr = int(SPLITS["train"]*n); n_va = int(SPLITS["val"]*n)
# Split into train, val, test
splits = {"train":files[:n_tr], "val":files[n_tr:n_tr+n_va], "test":files[n_tr+n_va:]}
# Copy images to correct folders
for split, fps in splits.items():
outdir = TARGET / split / cls
outdir.mkdir(parents=True, exist_ok=True)
for src in fps:
shutil.copy(src, outdir / src.name)
# Print summary
print(f"{cls}: {n} -> train {len(splits['train'])}, val {len(splits['val'])}, test {len(splits['test'])}")
# -------------------------------------------------------------
# STEP 4: MAIN FUNCTION – DOWNLOAD & PREPARE DATASET
# -------------------------------------------------------------
def main():
# Download dataset (cached locally after first time)
root = Path(kagglehub.dataset_download("farzadnekouei/trash-type-image-dataset"))
print("Dataset at:", root)
# Collect all image paths + inferred labels
items = gather_images(root)
if not items:
raise SystemExit("No images found. Check dataset layout.")
print("Classes detected:", sorted({c for _, c in items}))
# Split and copy into new structure
split_and_copy(items)
print("Flattened dataset ready in:", TARGET)
# -------------------------------------------------------------
# ENTRY POINT (only runs when executed directly)
# -------------------------------------------------------------
if __name__ == "__main__":
main()