diff --git a/.gitignore b/.gitignore index 82f9275..f7d3395 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,7 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +dataset/train/images +dataset/train/labels +app_logs.txt +.aider* diff --git a/README.md b/README.md index 53131d3..f98ac50 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ SearchVision is designed to provide a seamless experience for users to perform i ## Contributing We welcome contributions! If you're interested in contributing to SearchVision, please read our [CONTRIBUTING.md](CONTRIBUTING.md) file for guidelines on how to get started. +You can also give feedback [here](https://feedbackflux.vercel.app/brandonshen123@gmail.com/b/SearchVision) ## License diff --git a/dataset/data.yaml b/dataset/data.yaml new file mode 100644 index 0000000..4ff8642 --- /dev/null +++ b/dataset/data.yaml @@ -0,0 +1,5 @@ +path: C:\Users\Brandon Shen\Documents\SearchVision\dataset +train: C:\Users\Brandon Shen\Documents\SearchVision\dataset\train\images +val: C:\Users\Brandon Shen\Documents\SearchVision\dataset\train\images +names: + 0: basketball diff --git a/dataset/train/labels.cache b/dataset/train/labels.cache new file mode 100644 index 0000000..f835e11 Binary files /dev/null and b/dataset/train/labels.cache differ diff --git a/requirements.txt b/requirements.txt index 2be2fb1..8cbd9f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,9 @@ requests beautifulsoup4 ultralytics python-multipart +torch +torchvision +numpy +scikit-learn +pillow +python-dotenv diff --git a/runs/detect/train/args.yaml b/runs/detect/train/args.yaml new file mode 100644 index 0000000..315f5b0 --- /dev/null +++ b/runs/detect/train/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train diff --git a/runs/detect/train10/args.yaml b/runs/detect/train10/args.yaml new file mode 100644 index 0000000..e46c174 --- /dev/null +++ b/runs/detect/train10/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train10 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train10 diff --git a/runs/detect/train11/args.yaml b/runs/detect/train11/args.yaml new file mode 100644 index 0000000..51a4b2a --- /dev/null +++ b/runs/detect/train11/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train11 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train11 diff --git a/runs/detect/train12/args.yaml b/runs/detect/train12/args.yaml new file mode 100644 index 0000000..7bfc360 --- /dev/null +++ b/runs/detect/train12/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train12 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train12 diff --git a/runs/detect/train13/args.yaml b/runs/detect/train13/args.yaml new file mode 100644 index 0000000..6322fa5 --- /dev/null +++ b/runs/detect/train13/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train13 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train13 diff --git a/runs/detect/train14/args.yaml b/runs/detect/train14/args.yaml new file mode 100644 index 0000000..9c1277a --- /dev/null +++ b/runs/detect/train14/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train14 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train14 diff --git a/runs/detect/train15/args.yaml b/runs/detect/train15/args.yaml new file mode 100644 index 0000000..0f2ddb5 --- /dev/null +++ b/runs/detect/train15/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train15 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train15 diff --git a/runs/detect/train16/args.yaml b/runs/detect/train16/args.yaml new file mode 100644 index 0000000..de81f9f --- /dev/null +++ b/runs/detect/train16/args.yaml @@ -0,0 +1,107 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset\data.yaml +epochs: 25 +time: null +patience: 10 +batch: 8 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: cpu +workers: 8 +project: null +name: train16 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: true +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +copy_paste_mode: flip +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: C:\Users\Brandon Shen\Documents\SearchVision\runs\detect\train16 diff --git a/runs/detect/train17/F1_curve.png b/runs/detect/train17/F1_curve.png new file mode 100644 index 0000000..5158e5e Binary files /dev/null and b/runs/detect/train17/F1_curve.png differ diff --git a/runs/detect/train17/PR_curve.png b/runs/detect/train17/PR_curve.png new file mode 100644 index 0000000..33f9935 Binary files /dev/null and b/runs/detect/train17/PR_curve.png differ diff --git a/runs/detect/train17/P_curve.png b/runs/detect/train17/P_curve.png new file mode 100644 index 0000000..525f554 Binary files /dev/null and b/runs/detect/train17/P_curve.png differ diff --git a/runs/detect/train17/R_curve.png b/runs/detect/train17/R_curve.png new file mode 100644 index 0000000..359d844 Binary files /dev/null and b/runs/detect/train17/R_curve.png differ diff --git a/runs/detect/train17/args.yaml b/runs/detect/train17/args.yaml new file mode 100644 index 0000000..55ff50a --- /dev/null +++ b/runs/detect/train17/args.yaml @@ -0,0 +1,107 @@ +task: detect +mode: train +model: yolov8n.pt +data: C:\Users\Brandon Shen\Documents\SearchVision\dataset\data.yaml +epochs: 25 +time: null +patience: 10 +batch: 8 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: cpu +workers: 8 +project: null +name: train17 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: true +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +copy_paste_mode: flip +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: C:\Users\Brandon Shen\Documents\SearchVision\runs\detect\train17 diff --git a/runs/detect/train17/confusion_matrix.png b/runs/detect/train17/confusion_matrix.png new file mode 100644 index 0000000..6ff56da Binary files /dev/null and b/runs/detect/train17/confusion_matrix.png differ diff --git a/runs/detect/train17/confusion_matrix_normalized.png b/runs/detect/train17/confusion_matrix_normalized.png new file mode 100644 index 0000000..04e394f Binary files /dev/null and b/runs/detect/train17/confusion_matrix_normalized.png differ diff --git a/runs/detect/train17/events.out.tfevents.1740701719.PW4638167770234.55244.0 b/runs/detect/train17/events.out.tfevents.1740701719.PW4638167770234.55244.0 new file mode 100644 index 0000000..9a5bbf6 Binary files /dev/null and b/runs/detect/train17/events.out.tfevents.1740701719.PW4638167770234.55244.0 differ diff --git a/runs/detect/train17/labels.jpg b/runs/detect/train17/labels.jpg new file mode 100644 index 0000000..5baaba5 Binary files /dev/null and b/runs/detect/train17/labels.jpg differ diff --git a/runs/detect/train17/labels_correlogram.jpg b/runs/detect/train17/labels_correlogram.jpg new file mode 100644 index 0000000..7351913 Binary files /dev/null and b/runs/detect/train17/labels_correlogram.jpg differ diff --git a/runs/detect/train17/results.csv b/runs/detect/train17/results.csv new file mode 100644 index 0000000..e4b1c96 --- /dev/null +++ b/runs/detect/train17/results.csv @@ -0,0 +1,26 @@ +epoch,time,train/box_loss,train/cls_loss,train/dfl_loss,metrics/precision(B),metrics/recall(B),metrics/mAP50(B),metrics/mAP50-95(B),val/box_loss,val/cls_loss,val/dfl_loss,lr/pg0,lr/pg1,lr/pg2 +1,21.0361,0.91108,2.80163,1.17384,0.00856,0.9625,0.34137,0.24818,0.39739,2.98326,0.90614,6e-05,6e-05,6e-05 +2,33.0195,0.98657,2.64668,1.13301,0.00867,0.975,0.4323,0.35792,0.46403,2.96352,0.91283,0.000134456,0.000134456,0.000134456 +3,43.9278,0.84994,2.10175,1.12605,0.00867,0.975,0.4622,0.37828,0.53374,2.91079,0.92489,0.000202576,0.000202576,0.000202576 +4,55.7088,0.81153,1.78668,1.07674,0.00878,0.9875,0.51515,0.40305,0.61849,2.79785,0.95287,0.00026436,0.00026436,0.00026436 +5,67.7567,0.90498,1.49133,1.07601,0.94146,0.2011,0.5381,0.396,0.70973,2.6416,0.97848,0.000319808,0.000319808,0.000319808 +6,80.1714,0.936,1.94005,1.25179,0.95326,0.25506,0.55077,0.43206,0.69786,2.55737,0.96863,0.00036892,0.00036892,0.00036892 +7,91.0975,0.86754,1.52,1.12672,0.96576,0.3526,0.58323,0.48808,0.66286,2.46892,0.97026,0.000411696,0.000411696,0.000411696 +8,101.657,0.80064,1.6376,1.12076,0.96167,0.31364,0.57858,0.47984,0.66931,2.4826,0.97193,0.000448136,0.000448136,0.000448136 +9,112.643,0.63558,1.39311,1.05431,1,0.25529,0.57879,0.47119,0.68391,2.58967,0.97364,0.00047824,0.00047824,0.00047824 +10,123.155,0.78626,1.54893,1.13025,1,0.21903,0.55938,0.45304,0.69666,2.63499,0.97718,0.000502008,0.000502008,0.000502008 +11,133.726,0.7854,1.34338,1.08913,1,0.36744,0.56225,0.47962,0.70092,2.51946,0.9834,0.00051944,0.00051944,0.00051944 +12,144.197,0.79021,1.4295,1.09774,0.92005,0.4316,0.54507,0.46676,0.67422,2.34246,0.99195,0.000530536,0.000530536,0.000530536 +13,154.671,0.72066,1.33911,1.04883,0.79628,0.43977,0.56778,0.47914,0.65884,2.23407,0.98003,0.000535296,0.000535296,0.000535296 +14,165.229,0.69716,1.22407,1.04598,0.86489,0.56014,0.68678,0.6031,0.64374,2.10599,0.97019,0.00053372,0.00053372,0.00053372 +15,176.004,0.84211,1.1759,1.03366,0.84858,0.63049,0.79059,0.69692,0.62518,1.94564,0.99782,0.000525808,0.000525808,0.000525808 +16,186.86,0.5805,1.83191,0.97853,0.84858,0.63049,0.79059,0.69692,0.62518,1.94564,0.99782,0.00051156,0.00051156,0.00051156 +17,197.522,0.69049,1.67263,0.98821,0.89012,0.675,0.8282,0.71474,0.63029,1.88828,1.00195,0.000490976,0.000490976,0.000490976 +18,210.531,0.62329,1.87898,0.98679,0.88448,0.675,0.83214,0.7142,0.65848,1.86514,1.02756,0.000464056,0.000464056,0.000464056 +19,221.325,0.65359,1.47793,0.95454,0.88448,0.675,0.83214,0.7142,0.65848,1.86514,1.02756,0.0004308,0.0004308,0.0004308 +20,231.667,0.65471,1.68673,1.0228,0.96476,0.68446,0.82951,0.70684,0.66719,1.86883,1.04404,0.000391208,0.000391208,0.000391208 +21,242.31,0.644,1.74126,1.06733,0.9188,0.70729,0.84282,0.72777,0.65072,1.83517,1.00727,0.00034528,0.00034528,0.00034528 +22,252.655,0.60214,1.57435,0.9613,0.9188,0.70729,0.84282,0.72777,0.65072,1.83517,1.00727,0.000293016,0.000293016,0.000293016 +23,263.138,0.69024,1.60948,1.02949,0.908,0.74026,0.87572,0.75413,0.62707,1.7348,0.97154,0.000234416,0.000234416,0.000234416 +24,273.372,0.5577,1.43103,0.922,0.908,0.74026,0.87572,0.75413,0.62707,1.7348,0.97154,0.00016948,0.00016948,0.00016948 +25,284.072,0.79471,1.6108,1.10699,0.91309,0.78797,0.88191,0.75918,0.61545,1.61585,0.94993,9.8208e-05,9.8208e-05,9.8208e-05 diff --git a/runs/detect/train17/results.png b/runs/detect/train17/results.png new file mode 100644 index 0000000..3e885f3 Binary files /dev/null and b/runs/detect/train17/results.png differ diff --git a/runs/detect/train17/train_batch0.jpg b/runs/detect/train17/train_batch0.jpg new file mode 100644 index 0000000..48009b5 Binary files /dev/null and b/runs/detect/train17/train_batch0.jpg differ diff --git a/runs/detect/train17/train_batch1.jpg b/runs/detect/train17/train_batch1.jpg new file mode 100644 index 0000000..990b246 Binary files /dev/null and b/runs/detect/train17/train_batch1.jpg differ diff --git a/runs/detect/train17/train_batch2.jpg b/runs/detect/train17/train_batch2.jpg new file mode 100644 index 0000000..b354a9d Binary files /dev/null and b/runs/detect/train17/train_batch2.jpg differ diff --git a/runs/detect/train17/train_batch60.jpg b/runs/detect/train17/train_batch60.jpg new file mode 100644 index 0000000..1dea173 Binary files /dev/null and b/runs/detect/train17/train_batch60.jpg differ diff --git a/runs/detect/train17/train_batch61.jpg b/runs/detect/train17/train_batch61.jpg new file mode 100644 index 0000000..608396a Binary files /dev/null and b/runs/detect/train17/train_batch61.jpg differ diff --git a/runs/detect/train17/train_batch62.jpg b/runs/detect/train17/train_batch62.jpg new file mode 100644 index 0000000..8b35e40 Binary files /dev/null and b/runs/detect/train17/train_batch62.jpg differ diff --git a/runs/detect/train17/val_batch0_labels.jpg b/runs/detect/train17/val_batch0_labels.jpg new file mode 100644 index 0000000..524c0b5 Binary files /dev/null and b/runs/detect/train17/val_batch0_labels.jpg differ diff --git a/runs/detect/train17/val_batch0_pred.jpg b/runs/detect/train17/val_batch0_pred.jpg new file mode 100644 index 0000000..f870c41 Binary files /dev/null and b/runs/detect/train17/val_batch0_pred.jpg differ diff --git a/runs/detect/train17/val_batch1_labels.jpg b/runs/detect/train17/val_batch1_labels.jpg new file mode 100644 index 0000000..d6ccc49 Binary files /dev/null and b/runs/detect/train17/val_batch1_labels.jpg differ diff --git a/runs/detect/train17/val_batch1_pred.jpg b/runs/detect/train17/val_batch1_pred.jpg new file mode 100644 index 0000000..19da4b7 Binary files /dev/null and b/runs/detect/train17/val_batch1_pred.jpg differ diff --git a/runs/detect/train17/weights/best.pt b/runs/detect/train17/weights/best.pt new file mode 100644 index 0000000..db68787 Binary files /dev/null and b/runs/detect/train17/weights/best.pt differ diff --git a/runs/detect/train17/weights/last.pt b/runs/detect/train17/weights/last.pt new file mode 100644 index 0000000..b8938b7 Binary files /dev/null and b/runs/detect/train17/weights/last.pt differ diff --git a/runs/detect/train2/args.yaml b/runs/detect/train2/args.yaml new file mode 100644 index 0000000..9716e45 --- /dev/null +++ b/runs/detect/train2/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train2 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train2 diff --git a/runs/detect/train3/args.yaml b/runs/detect/train3/args.yaml new file mode 100644 index 0000000..fd7e27e --- /dev/null +++ b/runs/detect/train3/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train3 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train3 diff --git a/runs/detect/train4/args.yaml b/runs/detect/train4/args.yaml new file mode 100644 index 0000000..1871847 --- /dev/null +++ b/runs/detect/train4/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train4 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train4 diff --git a/runs/detect/train5/args.yaml b/runs/detect/train5/args.yaml new file mode 100644 index 0000000..6278269 --- /dev/null +++ b/runs/detect/train5/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train5 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train5 diff --git a/runs/detect/train6/args.yaml b/runs/detect/train6/args.yaml new file mode 100644 index 0000000..e19c16b --- /dev/null +++ b/runs/detect/train6/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train6 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train6 diff --git a/runs/detect/train7/args.yaml b/runs/detect/train7/args.yaml new file mode 100644 index 0000000..bec1959 --- /dev/null +++ b/runs/detect/train7/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train7 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train7 diff --git a/runs/detect/train8/args.yaml b/runs/detect/train8/args.yaml new file mode 100644 index 0000000..032cb2b --- /dev/null +++ b/runs/detect/train8/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train8 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train8 diff --git a/runs/detect/train9/args.yaml b/runs/detect/train9/args.yaml new file mode 100644 index 0000000..00bb6a7 --- /dev/null +++ b/runs/detect/train9/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: dataset/data.yaml +epochs: 50 +time: null +patience: 100 +batch: 16 +imgsz: 640 +save: true +save_period: -1 +cache: false +device: null +workers: 8 +project: null +name: train9 +exist_ok: false +pretrained: true +optimizer: auto +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +save_hybrid: false +conf: null +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: false +opset: null +workspace: 4 +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 3.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 0.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +label_smoothing: 0.0 +nbs: 64 +hsv_h: 0.015 +hsv_s: 0.7 +hsv_v: 0.4 +degrees: 0.0 +translate: 0.1 +scale: 0.5 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +bgr: 0.0 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 +auto_augment: randaugment +erasing: 0.4 +crop_fraction: 1.0 +cfg: null +tracker: botsort.yaml +save_dir: runs\detect\train9 diff --git a/src/auto_annotate_images.py b/src/auto_annotate_images.py new file mode 100644 index 0000000..74bb769 --- /dev/null +++ b/src/auto_annotate_images.py @@ -0,0 +1,83 @@ +from ultralytics import YOLO +import os +from PIL import Image +import logging + +logger = logging.getLogger(__name__) + + +def auto_annotate_images(image_folder, labels_folder): + """ + Auto-annotate images using YOLOv8 and save annotations in YOLO format. + + Args: + image_folder: Directory containing images + labels_folder: Directory where annotation files will be saved + """ + # Load the pre-trained YOLOv8 model + model = YOLO('yolov8n.pt') + + os.makedirs(labels_folder, exist_ok=True) + + # Track statistics + processed_count = 0 + annotated_count = 0 + error_count = 0 + + # Loop through images in the specified folder + for image_file in os.listdir(image_folder): + if image_file.endswith(('.jpg', '.jpeg', '.png')): + image_path = os.path.join(image_folder, image_file) + + # Check if the image can be opened and processed + try: + # Get image dimensions + with Image.open(image_path) as img: + img_width, img_height = img.size + + # Run detection + results = model(image_path) + processed_count += 1 + + # Create annotation filename + label_filename = os.path.splitext(image_file)[0] + ".txt" + label_path = os.path.join(labels_folder, label_filename) + + # Process the results + for result in results: + if result.boxes is not None and len(result.boxes) > 0: + # Extract bounding boxes + boxes = result.boxes.xyxy.cpu().numpy() + + with open(label_path, 'w') as f: + for box in boxes: + if len(box) >= 4: + x_min, y_min, x_max, y_max = box[:4] + + # Calculate YOLO format (normalized) + x_center = ( + (x_min + x_max) / 2) / img_width + y_center = ( + (y_min + y_max) / 2) / img_height + width = (x_max - x_min) / img_width + height = (y_max - y_min) / img_height + + # Class 0 for all objects (single class) + f.write( + f"0 {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n") + annotated_count += 1 + + logger.info(f"Saved YOLO annotations for {image_file}") + else: + logger.warning(f"No objects detected in {image_file}") + + except Exception as e: + logger.error(f"Error processing image {image_path}: {e}") + error_count += 1 + continue + + logger.info( + f"Auto-annotation complete: processed {processed_count} images, " + f"created {annotated_count} annotations, {error_count} errors") + + return processed_count, annotated_count, error_count diff --git a/src/create_data_yaml.py b/src/create_data_yaml.py new file mode 100644 index 0000000..1ce53e2 --- /dev/null +++ b/src/create_data_yaml.py @@ -0,0 +1,39 @@ +import os +import yaml + + +def create_data_yaml(annotations_path, object_name="object"): + """ + Create a YAML configuration file for YOLOv8 training. + + Args: + annotations_path: Path to annotations (used for determining dataset path) + object_name: Name of the object class + + Returns: + Path to the created YAML file + """ + # Use absolute paths + base_dir = os.path.dirname( + os.path.dirname( + os.path.abspath(annotations_path))) + train_images_path = os.path.join(base_dir, "train", "images") + train_labels_path = os.path.join(base_dir, "train", "labels") + + # Dataset structure expected by YOLOv8 with absolute paths + data = { + 'path': base_dir, # Absolute base path + 'train': train_images_path, # Absolute train images path + 'val': train_images_path, # Using same images for validation + 'names': { + 0: object_name # Single class detection + } + } + + # Create the YAML file + yaml_path = os.path.join(base_dir, 'data.yaml') + with open(yaml_path, 'w') as f: + yaml.dump(data, f, sort_keys=False, default_flow_style=False) + + print(f"Created data.yaml at {yaml_path}") + return yaml_path diff --git a/src/download_images.py b/src/download_images.py new file mode 100644 index 0000000..398dc20 --- /dev/null +++ b/src/download_images.py @@ -0,0 +1,44 @@ +# src/download_images.py + +import requests +import os + + +def download_images(image_urls, download_path="dataset/train/images"): + """ + Downloads images from a list of URLs and saves them to the specified directory. + + :param image_urls: List of image URLs to download. + :param download_path: Directory to save downloaded images. + :return: List of file paths for successfully downloaded images. + """ + print("Starting image download...") # Debugging statement + + # Ensure the download directory exists + if not os.path.exists(download_path): + os.makedirs(download_path) + + # List to hold paths of successfully downloaded images + downloaded_paths = [] + + # Iterate over the image URLs and download each image + for idx, url in enumerate(image_urls): + print(f"Attempting to download: {url}") # Debugging statement + try: + response = requests.get(url) + if response.status_code == 200: + file_path = os.path.join(download_path, f"image_{idx}.jpg") + with open(file_path, "wb") as f: + f.write(response.content) + print(f"Downloaded: {file_path}") + downloaded_paths.append(file_path) # Add path to list + else: + print(f"Failed to download {url}") + except Exception as e: + print(f"Error downloading {url}: {e}") + + # Check if any images were downloaded + if not downloaded_paths: + print("No images were downloaded.") + + return downloaded_paths diff --git a/src/main.py b/src/main.py index 381d431..32c3449 100644 --- a/src/main.py +++ b/src/main.py @@ -1,95 +1,301 @@ import os -from fastapi import FastAPI, Form, HTTPException -from fastapi.responses import HTMLResponse +import json +import asyncio +from pathlib import Path +from fastapi import FastAPI, Form, HTTPException, Query, Request +from fastapi.responses import HTMLResponse, JSONResponse +from fastapi.templating import Jinja2Templates from fastapi.staticfiles import StaticFiles import logging +from dotenv import load_dotenv +from src.auto_annotate_images import auto_annotate_images +from src.download_images import download_images from src.search_images import search_images +from src.search_most_dissimilar_images import select_most_dissimilar_images from src.train_model import train_model from src.scrape_similar import scrape_similar_images +from PIL import Image +from src.create_data_yaml import create_data_yaml +import shutil +from src.utils.annotation_converter import convert_to_yolo_format, ensure_directory + +load_dotenv() -# Initialize the FastAPI app app = FastAPI() -# Set up logging -logging.basicConfig(level=logging.INFO) +templates = Jinja2Templates(directory=Path(__file__).parent / "templates") + +log_file_path = os.path.join(os.getcwd(), 'app_logs.txt') +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler(log_file_path), + logging.StreamHandler() + ] +) logger = logging.getLogger(__name__) -# Serve static files (like images) from the "static" directory -try: - static_path = os.path.join(os.path.dirname(__file__), "static") - if not os.path.exists(static_path): - raise FileNotFoundError( - f"Static directory '{static_path}' does not exist.") - app.mount("/static", StaticFiles(directory=static_path), name="static") -except Exception as e: - logger.error(f"Error setting up static files: {e}") +images_path = "dataset/train/images" +labels_path = "dataset/train/labels" +download_path = "dataset/train/images" -# Route to handle the main form +os.makedirs(download_path, exist_ok=True) +app.mount("/images", StaticFiles(directory=download_path), name="images") +training_status = { + "step": 0, + "status": "Idle", + "detail": "", + "completed": False, + "success": False, + "model_path": "", + "error": "", + "query": "" +} + + +def clear_directory(path): + if os.path.exists(path): + shutil.rmtree(path) + os.makedirs(path) -@app.get("/", response_class=HTMLResponse) -async def index(): - try: - html_content = """ - - -
- - -
- - - """ - return html_content - except Exception as e: - logger.error(f"Error generating the index page: {e}") - raise HTTPException(status_code=500, detail="Internal Server Error") -# Route to handle the search and display images +def reset_training_status(query): + global training_status + training_status = { + "step": 0, + "status": "Starting", + "detail": "Initializing...", + "completed": False, + "success": False, + "model_path": "", + "error": "", + "query": query + } + + +@app.get("/", response_class=HTMLResponse) +async def index(request: Request): + clear_directory(images_path) + clear_directory(labels_path) + return templates.TemplateResponse("search.html", {"request": request}) @app.post("/search", response_class=HTMLResponse) -async def search(query: str = Form(...)): +async def search(request: Request, query: str = Form(...)): try: - api_key = "YOUR_API_KEY" - search_engine_id = "YOUR_SEARCH_ENGINE_ID" + api_key = os.getenv("GOOGLE_API_KEY") + search_engine_id = os.getenv("SEARCH_ENGINE_ID") + + if not api_key or not search_engine_id: + return templates.TemplateResponse("search.html", { + "request": request, + "error": "API keys not configured. Please set GOOGLE_API_KEY and SEARCH_ENGINE_ID in .env" + }) + images = search_images(query, api_key, search_engine_id) if not images: - return HTMLResponse("

No images found for the query.

", status_code=404) + return templates.TemplateResponse("search.html", { + "request": request, + "error": "No images found. Try a different search term." + }) + + selected_images = select_most_dissimilar_images(images, 9) - html_content = f"

Results for: {query}

" - for image_url in images: - html_content += f"
" - html_content += "
" - return html_content + return templates.TemplateResponse("select.html", { + "request": request, + "query": query, + "images": selected_images + }) except Exception as e: logger.error(f"Error during image search: {e}") - raise HTTPException(status_code=500, detail="Internal Server Error") - -# Route to handle selected images and scrape for similar images + return templates.TemplateResponse("search.html", { + "request": request, + "error": f"Search failed: {str(e)}" + }) @app.post("/select", response_class=HTMLResponse) -async def select(selected_images: list[str] = Form(...)): +async def select( + request: Request, + selected_images: list[str] = Form(...), + original_query: str = Form(...)): try: - if not selected_images: - raise HTTPException(status_code=400, detail="No images selected.") + if not selected_images or len(selected_images) < 3: + raise HTTPException(status_code=400, + detail="Please select at least 3 images.") - similar_images = scrape_similar_images(selected_images) + clear_directory(images_path) + clear_directory(labels_path) - if not similar_images: - return HTMLResponse("

No similar images found.

", status_code=404) + local_image_paths = download_images(selected_images, download_path) - # Here, you'd train your YOLO model with the selected images - # Add appropriate annotations - train_model(similar_images, annotations=[]) + images_data = [ + (path, os.path.basename(path)) + for path in local_image_paths + ] - return "

Model Training Complete

" - except HTTPException as he: - logger.error(f"HTTP error during image selection: {he}") - raise he + return templates.TemplateResponse("annotate.html", { + "request": request, + "query": original_query, + "images": images_data + }) except Exception as e: - logger.error(f"Error during image selection or model training: {e}") - raise HTTPException(status_code=500, detail="Internal Server Error") + logger.error(f"Error during image selection: {e}") + raise HTTPException(status_code=500, detail=str(e)) + + +@app.post("/start-training", response_class=HTMLResponse) +async def start_training( + request: Request, + image_urls: list[str] = Form(...), + annotations: list[str] = Form(...), + original_query: str = Form(...)): + try: + reset_training_status(original_query) + + asyncio.create_task( + run_training( + image_urls, + annotations, + original_query)) + + return templates.TemplateResponse("training.html", { + "request": request, + "query": original_query + }) + except Exception as e: + logger.error(f"Error starting training: {e}") + raise HTTPException(status_code=500, detail=str(e)) + + +async def run_training(image_urls, annotations, original_query): + global training_status + try: + training_status["status"] = "Downloading" + training_status["detail"] = "Saving your annotated images" + training_status["step"] = 0 + + ensure_directory( + labels_dir := os.path.join( + "dataset", "train", "labels")) + + for image_url, annotation_json in zip(image_urls, annotations): + try: + image_name = os.path.basename(image_url) + image_path = os.path.join(images_path, image_name) + + with Image.open(image_path) as img: + img_width, img_height = img.size + + yolo_annotation = convert_to_yolo_format( + annotation_json, img_width, img_height) + + label_filename = os.path.splitext(image_name)[0] + ".txt" + label_path = os.path.join(labels_dir, label_filename) + + with open(label_path, 'w') as f: + f.write(yolo_annotation) + except Exception as e: + logger.error(f"Error processing annotation: {e}") + + training_status["step"] = 1 + training_status["status"] = "Scraping" + training_status["detail"] = "Finding similar images..." + + api_key = os.getenv("GOOGLE_API_KEY") + search_engine_id = os.getenv("SEARCH_ENGINE_ID") + + similar_images = scrape_similar_images( + image_urls, + original_query, + api_key, + search_engine_id, + num_results_per_image=10, + total_images_to_download=30 + ) + + training_status["step"] = 2 + training_status["status"] = "Downloading" + training_status["detail"] = f"Downloading {len(similar_images)} similar images" + + download_images(similar_images, images_path) + + training_status["step"] = 3 + training_status["status"] = "Annotating" + training_status["detail"] = "Auto-annotating scraped images" + + auto_annotate_images(images_path, labels_dir) + + training_status["step"] = 4 + training_status["status"] = "Training" + training_status["detail"] = "Training YOLOv8 model (this may take a few minutes)" + + data_yaml_path = create_data_yaml(labels_dir, original_query) + + model_path = train_model(data_yaml_path, 'yolov8') + + if model_path and os.path.exists(model_path): + training_status["completed"] = True + training_status["success"] = True + training_status["model_path"] = model_path + training_status["status"] = "Complete" + training_status["detail"] = "Model trained successfully!" + else: + raise Exception("Model training failed - no output model found") + + except Exception as e: + logger.error(f"Training error: {e}") + training_status["completed"] = True + training_status["success"] = False + training_status["error"] = str(e) + training_status["status"] = "Error" + training_status["detail"] = str(e) + + +@app.get("/training-status") +async def get_training_status(): + return JSONResponse(training_status) + + +@app.get("/results", response_class=HTMLResponse) +async def results(request: Request, model: str = Query(...)): + query = training_status.get("query", "Unknown") + + images_count = len([f for f in os.listdir(images_path) + if f.endswith(('.jpg', '.png'))]) + labels_count = len([f for f in os.listdir( + labels_path) if f.endswith('.txt')]) + + stats = { + "images": images_count, + "annotations": labels_count, + "epochs": 25 + } + + return templates.TemplateResponse("results.html", { + "request": request, + "query": query, + "model_path": model, + "stats": stats + }) + + +@app.get("/error", response_class=HTMLResponse) +async def error_page(request: Request, message: str = Query(...)): + return templates.TemplateResponse("error.html", { + "request": request, + "error": message + }) + + +@app.post("/save_annotations", response_class=HTMLResponse) +async def save_annotations( + request: Request, + image_urls: list[str] = Form(...), + annotations: list[str] = Form(...), + original_query: str = Form(...)): + return await start_training(request, image_urls, annotations, original_query) diff --git a/src/scrape_similar.py b/src/scrape_similar.py index 5000ee6..4880946 100644 --- a/src/scrape_similar.py +++ b/src/scrape_similar.py @@ -1,14 +1,46 @@ -# Function to scrape similar images based on selected images -from src import search_images +from src.search_images import search_images -def scrape_similar_images(selected_image_urls, api_key, search_engine_id): +def scrape_similar_images( + selected_image_urls, + original_query, + api_key, + search_engine_id, + num_results_per_image=10, + total_images_to_download=50): similar_images = [] - for url in selected_image_urls: - # Use the selected image URL or related terms to search for similar images - # Here, you can use the original search term or variations of it - query = f"related:{url}" # Use the URL to find related images - images = search_images(query, api_key, search_engine_id, num_results=5) - similar_images.extend(images) - - return similar_images + + # Enhanced fallback queries for better results + fallback_queries = [ + f"{original_query} clear photo", + f"{original_query} high resolution", + f"{original_query} isolated", + f"{original_query} product photo", + f"{original_query} professional photo" + ] + + # Add specific filters to the query + base_query = f"{original_query} filetype:jpg OR filetype:png" + images = search_images( + base_query, + api_key, + search_engine_id, + num_results=num_results_per_image) + similar_images.extend(images) + + # Use fallback queries only if needed + for fallback_query in fallback_queries: + if len(similar_images) >= total_images_to_download: + break + + fallback_images = search_images( + f"{fallback_query} filetype:jpg OR filetype:png", + api_key, + search_engine_id, + num_results=num_results_per_image) + similar_images.extend(fallback_images) + + # Remove duplicates while preserving order + similar_images = list(dict.fromkeys(similar_images)) + + return similar_images[:total_images_to_download] diff --git a/src/search_images.py b/src/search_images.py index ada2251..a9476b6 100644 --- a/src/search_images.py +++ b/src/search_images.py @@ -1,18 +1,35 @@ import requests -# Function to search for images using Google Custom Search API - - -def search_images(query, api_key, search_engine_id, num_results=5): - - search_url = "https://www.googleapis.com/customsearch/v1" - params = { - 'q': query, - 'cx': search_engine_id, - 'key': api_key, - 'searchType': 'image', - 'num': num_results - } - response = requests.get(search_url, params=params) - results = response.json() - image_urls = [item['link'] for item in results.get('items', [])] - return image_urls + + +def search_images(query, api_key, search_engine_id, num_results=10): + images = [] + # Google Custom Search allows a maximum of 10 results per page + results_per_page = 10 + start_index = 1 + + while len(images) < num_results: + # Adjust the start index for pagination + search_url = ( + f"https://www.googleapis.com/customsearch/v1?" + f"q={query}&searchType=image&key={api_key}&cx={search_engine_id}" + f"&start={start_index}&num={min(results_per_page, num_results - len(images))}") + + response = requests.get(search_url) + if response.status_code != 200: + raise Exception( + f"Failed to fetch images: Status code {response.status_code}, Response: {response.text}") + + data = response.json() + if 'items' not in data: + break # No more results + + for item in data['items']: + images.append(item['link']) # Get the image URL + + # Increment the start index for the next batch of results + start_index += results_per_page + + if len(data['items']) < results_per_page: + break # No more results available + + return images diff --git a/src/search_most_dissimilar_images.py b/src/search_most_dissimilar_images.py new file mode 100644 index 0000000..e21ff98 --- /dev/null +++ b/src/search_most_dissimilar_images.py @@ -0,0 +1,89 @@ +import numpy as np +from sklearn.metrics.pairwise import cosine_distances +from PIL import Image +from torchvision import models, transforms +import torch +from src.download_images import download_images + +# Load a pre-trained model (e.g., ResNet) for feature extraction +# Updated to use the correct 'weights' parameter +model = models.resnet50(weights='IMAGENET1K_V1') +model = model.eval() # Set the model to evaluation mode + +# Transformation for input images (resize, normalize, etc.) +transform = transforms.Compose([ + transforms.Resize((224, 224)), + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) +]) + + +def extract_features(image_path): + """ + Extracts features from an image using a pre-trained model. + + :param image_path: Path to the image. + :return: Feature vector of the image. + """ + try: + image = Image.open(image_path).convert( + 'RGB') # Ensure the image is in RGB format + image_tensor = transform(image).unsqueeze( + 0) # Transform and add batch dimension + with torch.no_grad(): + # Use the model to extract features + # Convert tensor to numpy array and flatten + features = model(image_tensor).flatten().numpy() + return features + except Exception as e: + print(f"Error extracting features from {image_path}: {e}") + return None + + +def select_most_dissimilar_images(image_urls, num_images): + """ + Selects the most dissimilar images from a list. + + :param image_urls: List of image URLs. + :param num_images: Number of most dissimilar images to select. + :return: List of the most dissimilar image URLs. + """ + # Download images to a local directory + # Temporary directory to save downloaded images + download_path = "dataset/train/images" + image_paths = download_images(image_urls, download_path=download_path) + + # Validate that images were downloaded + if not image_paths: + print("No images were downloaded.") + return [] + + # Extract features from each downloaded image + features = [] + valid_image_paths = [] + for path in image_paths: + feature = extract_features(path) + if feature is not None: + features.append(feature) + valid_image_paths.append(path) + + # Ensure there are enough features to proceed + if len(features) < num_images: + print("Not enough images to select the most dissimilar ones.") + return image_urls[:len(features)] # Return as many images as available + + # Convert features list to a numpy array + features = np.array(features) + + # Compute the cosine distance matrix between image features + distance_matrix = cosine_distances(features) + + # Sum the distances for each image and sort them in descending order + dissimilarity_scores = np.sum(distance_matrix, axis=1) + most_dissimilar_indices = np.argsort(dissimilarity_scores)[-num_images:] + + # Select the most dissimilar image URLs + most_dissimilar_images = [image_urls[idx] + for idx in most_dissimilar_indices] + + return most_dissimilar_images diff --git a/src/templates/annotate.html b/src/templates/annotate.html new file mode 100644 index 0000000..60a9e75 --- /dev/null +++ b/src/templates/annotate.html @@ -0,0 +1,242 @@ +{% extends "base.html" %} + +{% block title %}Annotate - SearchVision{% endblock %} + +{% block styles %} +.annotation-info { + text-align: center; + margin-bottom: 30px; +} + +.annotation-info h2 { + color: #333; + margin-bottom: 10px; +} + +.annotation-info p { + color: #666; +} + +.annotation-container { + max-width: 600px; + margin: 0 auto; +} + +.canvas-wrapper { + background: #f8f9fa; + border-radius: 12px; + padding: 20px; + text-align: center; + margin-bottom: 20px; +} + +.canvas-wrapper h3 { + margin-bottom: 15px; + color: #333; +} + +canvas { + border: 2px solid #ddd; + border-radius: 8px; + cursor: crosshair; + max-width: 100%; +} + +.annotation-tools { + display: flex; + justify-content: center; + gap: 15px; + margin-bottom: 20px; + flex-wrap: wrap; +} + +.tool-btn { + padding: 10px 20px; + background: white; + border: 2px solid #ddd; + border-radius: 6px; + cursor: pointer; + font-size: 0.9rem; + transition: all 0.2s; +} + +.tool-btn:hover { + border-color: #667eea; +} + +.tool-btn.active { + background: #667eea; + color: white; + border-color: #667eea; +} + +.instructions { + background: #e8f4f8; + border-radius: 8px; + padding: 16px; + margin-bottom: 20px; + font-size: 0.9rem; + color: #333; +} + +.instructions h4 { + margin-bottom: 8px; + color: #667eea; +} + +.nav-buttons { + display: flex; + justify-content: space-between; + margin-top: 30px; +} + +.skip-btn { + background: #6c757d; +} +{% endblock %} + +{% block content %} +
+

Annotate: "{{ query }}"

+

Draw bounding boxes around the object you want to detect

+
+ +
+

How to annotate:

+ +
+ +
+ + + {% for local_image_path, image_filename in images %} +
+
+

Image {{ loop.index }}: {{ image_filename }}

+ + + +
+ +
+
+
+ {% endfor %} + +
+ +
+
+ + +{% endblock %} diff --git a/src/templates/base.html b/src/templates/base.html new file mode 100644 index 0000000..8f05a50 --- /dev/null +++ b/src/templates/base.html @@ -0,0 +1,112 @@ + + + + + + {% block title %}SearchVision{% endblock %} + + + +
+
+

🔍 SearchVision

+

Train your own object detection model in minutes

+
+
+ {% block content %}{% endblock %} +
+ +
+ + diff --git a/src/templates/error.html b/src/templates/error.html new file mode 100644 index 0000000..980b0ec --- /dev/null +++ b/src/templates/error.html @@ -0,0 +1,49 @@ +{% extends "base.html" %} + +{% block title %}Error - SearchVision{% endblock %} + +{% block styles %} +.error-container { + max-width: 600px; + margin: 0 auto; + text-align: center; +} + +.error-icon { + font-size: 4rem; + margin-bottom: 20px; +} + +.error-message { + background: #fee; + border: 1px solid #fcc; + border-radius: 12px; + padding: 24px; + margin: 24px 0; + text-align: left; +} + +.error-message h3 { + color: #c33; + margin-bottom: 10px; +} + +.error-message p { + color: #666; + word-break: break-word; +} +{% endblock %} + +{% block content %} +
+
⚠️
+

Something went wrong

+ +
+

Error Details:

+

{{ error }}

+
+ + Try Again +
+{% endblock %} diff --git a/src/templates/results.html b/src/templates/results.html new file mode 100644 index 0000000..ab05bbe --- /dev/null +++ b/src/templates/results.html @@ -0,0 +1,148 @@ +{% extends "base.html" %} + +{% block title %}Results - SearchVision{% endblock %} + +{% block styles %} +.results-container { + max-width: 800px; + margin: 0 auto; +} + +.results-header { + text-align: center; + margin-bottom: 40px; +} + +.results-header h2 { + color: #38ef7d; + font-size: 2rem; + margin-bottom: 10px; +} + +.success-icon { + font-size: 4rem; + margin-bottom: 20px; +} + +.model-info { + background: #f8f9fa; + border-radius: 12px; + padding: 24px; + margin-bottom: 24px; +} + +.model-info h3 { + color: #333; + margin-bottom: 16px; +} + +.info-row { + display: flex; + padding: 10px 0; + border-bottom: 1px solid #e0e0e0; +} + +.info-row:last-child { + border-bottom: none; +} + +.info-label { + font-weight: 600; + width: 180px; + color: #666; +} + +.info-value { + color: #333; + flex: 1; + word-break: break-all; +} + +.actions { + display: flex; + gap: 15px; + justify-content: center; + margin-top: 30px; + flex-wrap: wrap; +} + +.btn-icon { + margin-right: 8px; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 16px; + margin: 24px 0; +} + +.stat-card { + background: white; + border-radius: 8px; + padding: 20px; + text-align: center; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.stat-value { + font-size: 2rem; + font-weight: bold; + color: #667eea; +} + +.stat-label { + color: #666; + font-size: 0.9rem; + margin-top: 5px; +} +{% endblock %} + +{% block content %} +
+
+
🎉
+

Training Complete!

+

Your model is ready to detect: {{ query }}

+
+ +
+

Model Details

+
+ Model Path: + {{ model_path }} +
+
+ Model Type: + YOLOv8 (nano) +
+
+ Training Object: + {{ query }} +
+
+ + {% if stats %} +
+
+
{{ stats.images }}
+
Images Used
+
+
+
{{ stats.annotations }}
+
Annotations
+
+
+
{{ stats.epochs }}
+
Epochs Trained
+
+
+ {% endif %} + +
+ + 🔄Train Another Model + +
+
+{% endblock %} diff --git a/src/templates/search.html b/src/templates/search.html new file mode 100644 index 0000000..6673877 --- /dev/null +++ b/src/templates/search.html @@ -0,0 +1,100 @@ +{% extends "base.html" %} + +{% block title %}Search - SearchVision{% endblock %} + +{% block styles %} +.search-box { + max-width: 600px; + margin: 0 auto; + text-align: center; +} + +.search-form { + display: flex; + gap: 12px; + margin-top: 30px; +} + +.search-input { + flex: 1; + padding: 16px 20px; + font-size: 1.1rem; + border: 2px solid #e0e0e0; + border-radius: 8px; + outline: none; + transition: border-color 0.3s; +} + +.search-input:focus { + border-color: #667eea; +} + +.search-btn { + padding: 16px 32px; + font-size: 1.1rem; +} + +.features { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 24px; + margin-top: 50px; +} + +.feature-card { + padding: 24px; + background: #f8f9fa; + border-radius: 12px; + text-align: center; + transition: transform 0.2s; +} + +.feature-card:hover { + transform: translateY(-4px); +} + +.feature-icon { + font-size: 3rem; + margin-bottom: 16px; +} + +.feature-card h3 { + color: #333; + margin-bottom: 8px; +} + +.feature-card p { + color: #666; + font-size: 0.95rem; +} +{% endblock %} + +{% block content %} + + +
+
+
🔍
+

Search Images

+

Find relevant images using Google Custom Search

+
+
+
✏️
+

Annotate

+

Draw bounding boxes on selected images

+
+
+
🤖
+

Auto-Train

+

Automatically scrape more data and train YOLOv8

+
+
+{% endblock %} diff --git a/src/templates/select.html b/src/templates/select.html new file mode 100644 index 0000000..160f256 --- /dev/null +++ b/src/templates/select.html @@ -0,0 +1,151 @@ +{% extends "base.html" %} + +{% block title %}Select Images - SearchVision{% endblock %} + +{% block styles %} +.selection-info { + text-align: center; + margin-bottom: 30px; +} + +.selection-info h2 { + color: #333; + margin-bottom: 10px; +} + +.selection-info p { + color: #666; +} + +.image-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 20px; + margin: 30px 0; +} + +.image-card { + position: relative; + border-radius: 12px; + overflow: hidden; + background: #f8f9fa; + transition: transform 0.2s, box-shadow 0.2s; + cursor: pointer; +} + +.image-card:hover { + transform: translateY(-4px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); +} + +.image-card.selected { + box-shadow: 0 0 0 4px #38ef7d; +} + +.image-card img { + width: 100%; + height: 180px; + object-fit: cover; +} + +.image-card .checkbox { + position: absolute; + top: 10px; + left: 10px; + width: 24px; + height: 24px; + background: white; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); +} + +.image-card.selected .checkbox::after { + content: "✓"; + color: #38ef7d; + font-weight: bold; +} + +.image-card label { + display: block; + padding: 10px; + text-align: center; + font-size: 0.9rem; + color: #666; +} + +.submit-section { + text-align: center; + margin-top: 30px; + padding-top: 20px; + border-top: 1px solid #e0e0e0; +} + +.submit-section p { + color: #666; + margin-bottom: 15px; +} + +.selected-count { + display: inline-block; + background: #667eea; + color: white; + padding: 4px 12px; + border-radius: 20px; + font-size: 0.9rem; + margin-left: 10px; +} +{% endblock %} + +{% block content %} +
+

Select images for: "{{ query }}"

+

Choose at least 3 images that clearly show the object you want to detect

+
+ +
+ + +
+ {% for image_url in images %} +
+
+ Search result + +
+ {% endfor %} +
+ +
+

Selected: 0 images Minimum 3 required

+ +
+
+ + +{% endblock %} diff --git a/src/templates/training.html b/src/templates/training.html new file mode 100644 index 0000000..95f8c9f --- /dev/null +++ b/src/templates/training.html @@ -0,0 +1,171 @@ +{% extends "base.html" %} + +{% block title %}Training - SearchVision{% endblock %} + +{% block styles %} +.progress-container { + max-width: 600px; + margin: 0 auto; + text-align: center; +} + +.progress-card { + background: #f8f9fa; + border-radius: 16px; + padding: 40px; + margin-top: 30px; +} + +.spinner { + width: 80px; + height: 80px; + border: 4px solid #e0e0e0; + border-top-color: #667eea; + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 0 auto 30px; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +.progress-status { + font-size: 1.3rem; + color: #333; + margin-bottom: 10px; +} + +.progress-detail { + color: #666; + font-size: 0.95rem; +} + +.progress-steps { + margin-top: 30px; + text-align: left; +} + +.step { + display: flex; + align-items: center; + padding: 12px 0; + border-bottom: 1px solid #e0e0e0; +} + +.step:last-child { + border-bottom: none; +} + +.step-icon { + width: 30px; + height: 30px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-right: 15px; + font-size: 0.9rem; +} + +.step.pending .step-icon { + background: #e0e0e0; + color: #999; +} + +.step.active .step-icon { + background: #667eea; + color: white; + animation: pulse 1.5s infinite; +} + +.step.completed .step-icon { + background: #38ef7d; + color: white; +} + +@keyframes pulse { + 0%, 100% { transform: scale(1); } + 50% { transform: scale(1.1); } +} + +.step-label { + color: #666; +} + +.step.pending .step-label { + color: #999; +} +{% endblock %} + +{% block content %} +
+

Training Your Model

+

Detecting: {{ query }}

+ +
+
+
Initializing...
+
Please wait while we process your images
+ +
+
+
1
+
Downloading selected images
+
+
+
2
+
Scraping similar images
+
+
+
3
+
Auto-annotating images
+
+
+
4
+
Training YOLOv8 model
+
+
+
+
+ + +{% endblock %} diff --git a/src/tests/conftest.py b/src/tests/conftest.py index b7e473d..f211786 100644 --- a/src/tests/conftest.py +++ b/src/tests/conftest.py @@ -3,4 +3,9 @@ import os # Add the src directory to the Python path -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))) +sys.path.insert( + 0, + os.path.abspath( + os.path.join( + os.path.dirname(__file__), + '../'))) diff --git a/src/tests/test_train_model.py b/src/tests/test_train_model.py index d7cece8..1a27d3a 100644 --- a/src/tests/test_train_model.py +++ b/src/tests/test_train_model.py @@ -1,16 +1,25 @@ -# src/tests/test_train_model.py from src.train_model import train_model +import os +import pytest def test_train_model(): - """Test the train_model function with a sample input.""" - image_paths = ["http://example.com/image1.jpg", - "http://example.com/image2.jpg"] - annotations = [] + """Test the train_model function with sample data.""" + # Create test data.yaml + test_yaml = "test_data.yaml" + with open(test_yaml, "w") as f: + f.write(""" +path: dataset +train: train/images +val: train/images +names: + 0: object + """) try: - train_model(image_paths, annotations) + train_model(test_yaml) except Exception as e: assert False, f"train_model raised an exception: {e}" - - # Check for specific output or side effects, if any + finally: + if os.path.exists(test_yaml): + os.remove(test_yaml) diff --git a/src/train_model.py b/src/train_model.py index 3066158..ae57f04 100644 --- a/src/train_model.py +++ b/src/train_model.py @@ -1,10 +1,50 @@ -# Function to train YOLOv8 model from ultralytics import YOLO +import os +import logging +logger = logging.getLogger(__name__) -def train_model(image_paths, annotations): - model = YOLO('yolov8n.pt') # Load a pre-trained YOLOv8 model - # Train the model - model.train(data={'images': image_paths, - 'annotations': annotations}, epochs=50) - model.save('yolov8_trained_model.pt') + +def train_model(data_yaml_path, model_type='yolov8'): + """ + Trains the YOLO model using the annotated dataset. + + Args: + data_yaml_path: Path to the data.yaml file containing dataset configuration + model_type: Type of YOLO model to train ('yolov8' recommended) + + Returns: + Path to the trained model + """ + try: + # Initialize YOLO model + model = YOLO('yolov8n.pt') # Start with pre-trained model + + # Train with specific parameters + results = model.train( + data=data_yaml_path, + epochs=25, # Reduced epochs for faster training + imgsz=640, # Image size + batch=8, # Batch size (reduce if memory issues) + patience=10, # Early stopping patience + save=True, # Save model + device='cpu' # Change to 'cuda' if GPU available + ) + + # Get the best model path + model_dir = "runs/detect/train" + if os.path.exists(model_dir): + latest_train_dir = max([os.path.join(model_dir, d) for d in os.listdir(model_dir) + if os.path.isdir(os.path.join(model_dir, d))], + key=os.path.getmtime) + model_path = os.path.join(latest_train_dir, "weights", "best.pt") + logger.info(f"Model trained and saved at {model_path}") + return model_path + else: + logger.error( + "Training directory not found. Training may have failed.") + return None + + except Exception as e: + logger.error(f"Error during model training: {e}") + return None diff --git a/src/utils/__init__.py b/src/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/utils/annotation_converter.py b/src/utils/annotation_converter.py new file mode 100644 index 0000000..597005a --- /dev/null +++ b/src/utils/annotation_converter.py @@ -0,0 +1,98 @@ +import os +import json +from PIL import Image + + +def convert_to_yolo_format(json_annotation, img_width, img_height): + """ + Convert JSON bbox annotation to YOLO format (normalized coordinates). + + Args: + json_annotation: JSON string with x, y, width, height (simple format) + or dict with rects array (complex format from canvas) + img_width: Width of the image + img_height: Height of the image + + Returns: + YOLO format string: " " + """ + # Parse JSON string to dict + data = json.loads(json_annotation) + + # Check if it's the new format with rects array + if 'rects' in data and isinstance( + data['rects'], list) and len( + data['rects']) > 0: + rects = data['rects'] + canvas_width = data.get('canvasWidth', img_width) + canvas_height = data.get('canvasHeight', img_height) + + # Get image element info if available + img_info = data.get('imageElement') + if img_info: + display_width = img_info.get('displayWidth', img_width) + display_height = img_info.get('displayHeight', img_height) + offset_x = img_info.get('offsetX', 0) + offset_y = img_info.get('offsetY', 0) + else: + display_width = img_width + display_height = img_height + offset_x = 0 + offset_y = 0 + + yolo_lines = [] + for rect in rects: + x = rect['x'] + y = rect['y'] + width = rect['width'] + height = rect['height'] + + # Scale from canvas coordinates to image coordinates + scale_x = display_width / canvas_width + scale_y = display_height / canvas_height + + x_scaled = (x - offset_x) / scale_x + y_scaled = (y - offset_y) / scale_y + width_scaled = width / scale_x + height_scaled = height / scale_y + + # Convert to YOLO format (normalized) + x_center = (x_scaled + width_scaled / 2) / img_width + y_center = (y_scaled + height_scaled / 2) / img_height + width_norm = abs(width_scaled / img_width) + height_norm = abs(height_scaled / img_height) + + # Clamp values between 0 and 1 + x_center = max(0, min(1, x_center)) + y_center = max(0, min(1, y_center)) + width_norm = max(0, min(1, width_norm)) + height_norm = max(0, min(1, height_norm)) + + yolo_lines.append( + f"0 {x_center:.6f} {y_center:.6f} {width_norm:.6f} {height_norm:.6f}") + + return "\n".join(yolo_lines) + + # Legacy format: simple x, y, width, height + bbox = data + + # YOLO uses center coordinates and normalized dimensions + x_center = (bbox['x'] + bbox['width'] / 2) / img_width + y_center = (bbox['y'] + bbox['height'] / 2) / img_height + width = abs(bbox['width'] / img_width) + height = abs(bbox['height'] / img_height) + + # Clamp values between 0 and 1 + x_center = max(0, min(1, x_center)) + y_center = max(0, min(1, y_center)) + width = max(0, min(1, width)) + height = max(0, min(1, height)) + + # Return YOLO format string (class 0) + return f"0 {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}" + + +def ensure_directory(directory): + """Create directory if it doesn't exist.""" + if not os.path.exists(directory): + os.makedirs(directory)