Computer-Vision-Assistant-Package 1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- computer_vision_assistant_package-1.0/License.txt +21 -0
- computer_vision_assistant_package-1.0/PKG-INFO +151 -0
- computer_vision_assistant_package-1.0/README.md +140 -0
- computer_vision_assistant_package-1.0/pyproject.toml +21 -0
- computer_vision_assistant_package-1.0/src/Computer_Vision_Assistant_Package/AI_Metrics.py +241 -0
- computer_vision_assistant_package-1.0/src/Computer_Vision_Assistant_Package/Basic_Utils.py +597 -0
- computer_vision_assistant_package-1.0/src/Computer_Vision_Assistant_Package/Image_Utils.py +265 -0
- computer_vision_assistant_package-1.0/src/Computer_Vision_Assistant_Package/__innit__.py +21 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shounak Sanyal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: Computer_Vision_Assistant_Package
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: A user friendly package assiting in the most common computer vision tasks
|
|
5
|
+
Author-email: Shounak Sanyal <shounaksanyal1902@outlook.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: License.txt
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Requires-Python: >=3.12
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# Computer_vision_assisting_tools
|
|
13
|
+
|
|
14
|
+
**Author:** Shounak Sanyal
|
|
15
|
+
|
|
16
|
+
A small toolbox of helpers for computer-vision projects. It bundles the
|
|
17
|
+
functions that were most useful in a detection + classification workflow:
|
|
18
|
+
|
|
19
|
+
* find images and annotation files in a folder tree,
|
|
20
|
+
* check and read COCO-style datasets,
|
|
21
|
+
* run a detector (RF-DETR, YOLO) or a CNN classifier on an image and draw the
|
|
22
|
+
predictions next to the ground truth,
|
|
23
|
+
* slice large images into tiles (SAHI) and run detection / classification on
|
|
24
|
+
every tile,
|
|
25
|
+
* pre-process images (CLAHE, Reinhard colour transfer, Otsu, augmentation,
|
|
26
|
+
square padding, tensor transforms),
|
|
27
|
+
* score a detector with IoU, precision / recall and mAP.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Package hierarchy
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
.
|
|
35
|
+
├── README.md
|
|
36
|
+
└── Computer_vision_assisting_tools/
|
|
37
|
+
├── __innit__.py Package docstring (no code)
|
|
38
|
+
├── AI_Metrics.py Detection metrics
|
|
39
|
+
│ ├── IOU_calc
|
|
40
|
+
│ ├── mAP_calc
|
|
41
|
+
│ ├── AUC_calc
|
|
42
|
+
│ └── detection_metrics
|
|
43
|
+
├── Basic_Utils.py Files, datasets, annotations, inference, SAHI
|
|
44
|
+
│ ├── IMAGE_EXTENSIONS (constant)
|
|
45
|
+
│ ├── img_loc
|
|
46
|
+
│ ├── ai_analytics
|
|
47
|
+
│ ├── dataset_check
|
|
48
|
+
│ ├── provide_annotations
|
|
49
|
+
│ ├── SAHI_generation
|
|
50
|
+
│ └── SAHI_analysis
|
|
51
|
+
└── Image_Utils.py Image pre-processing
|
|
52
|
+
├── image_processing
|
|
53
|
+
├── data_augmentation
|
|
54
|
+
├── cell_geometry
|
|
55
|
+
└── cell_transform
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### How the modules depend on each other
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
AI_Metrics.py ──► Basic_Utils.py ──► Image_Utils.py
|
|
62
|
+
(metrics) (data + models) (image helpers)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`AI_Metrics` uses `provide_annotations` and `ai_analytics` from `Basic_Utils`;
|
|
66
|
+
`Basic_Utils` uses `cell_geometry` and `cell_transform` from `Image_Utils`.
|
|
67
|
+
`Image_Utils` depends on none of the others. The modules import each other
|
|
68
|
+
with relative imports (`from .Basic_Utils import *`), so they must be used as
|
|
69
|
+
part of the package, not run directly as scripts.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Module descriptions
|
|
74
|
+
|
|
75
|
+
### `Image_Utils.py` — image pre-processing
|
|
76
|
+
|
|
77
|
+
Helpers that prepare images (for example single-cell crops) before they reach
|
|
78
|
+
a classifier. Images are NumPy arrays read with OpenCV, so colour images are in
|
|
79
|
+
BGR order unless stated otherwise.
|
|
80
|
+
|
|
81
|
+
| Function | What it does |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `image_processing(img, ref_img=None, normalisation='Clahe', grid_window=(8,8))` | Normalises an image with CLAHE (default), Reinhard colour transfer (needs `ref_img`) or Otsu thresholding (`'Otsu'`). |
|
|
84
|
+
| `data_augmentation(img, n_rotate=3, blur=True)` | Returns up to three rotated copies (90°, 180°, 270°; default 3) and, optionally, a Gaussian-blurred copy. |
|
|
85
|
+
| `cell_geometry(img)` | Makes both sides even, then pads the shorter side with black so the image becomes a centred square. |
|
|
86
|
+
| `cell_transform(img, key)` | Converts an image to a `float32` tensor. `key=0` adds ImageNet normalisation, `key=1` only scales to [0, 1]. |
|
|
87
|
+
|
|
88
|
+
### `Basic_Utils.py` — data, annotations, inference and SAHI
|
|
89
|
+
|
|
90
|
+
The main working module. It finds files, checks datasets, reads ground truth,
|
|
91
|
+
runs models and handles SAHI tiling.
|
|
92
|
+
|
|
93
|
+
| Function | What it does |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `IMAGE_EXTENSIONS` | Tuple of file extensions treated as images (case-insensitive). |
|
|
96
|
+
| `img_loc(path)` | Recursively lists image, `.json` and `.txt` files under a folder. Returns `(img_list, json_list, txt_list)`. |
|
|
97
|
+
| `ai_analytics(file, image_path, model, name='RFDETR', key=True, mode='Detection')` | Runs RF-DETR / YOLO detection or CNN classification on one image (the model is moved to the GPU if available). For detection it also reads the COCO ground truth and can draw predictions (blue) and ground truth (green). |
|
|
98
|
+
| `dataset_check(file)` | Checks that the images in a folder and the COCO json agree. Returns five counts (images, json images, annotated images, categories, used categories). |
|
|
99
|
+
| `provide_annotations(json_path, file_name, key='COCO')` | Returns the ground-truth boxes and labels for one image, from a COCO json or from the `'Vanila'` multi-json format. |
|
|
100
|
+
| `SAHI_generation(image_path, ...)` | Slices a large image into tiles and saves them (the output folder is deleted first if it exists). |
|
|
101
|
+
| `SAHI_analysis(image_path, model_det, model_clss=None, ...)` | Detects (and optionally classifies) objects on every tile and draws them on the full image. |
|
|
102
|
+
|
|
103
|
+
### `AI_Metrics.py` — detection metrics
|
|
104
|
+
|
|
105
|
+
Scores a detector on a single image against COCO ground truth. Boxes are in
|
|
106
|
+
`(x_min, y_min, x_max, y_max)` format.
|
|
107
|
+
|
|
108
|
+
| Function | What it does |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `IOU_calc(target_pts, gt_pts)` | IoU of one box against a list of ground-truth boxes. |
|
|
111
|
+
| `mAP_calc(bboxes, gt_bboxes)` | Running precision and recall for IoU thresholds 0.50 – 0.90. |
|
|
112
|
+
| `AUC_calc(precision, recall)` | Builds the smoothed precision curve used for the area under the curve. |
|
|
113
|
+
| `detection_metrics(json_file, img_file, model_test)` | End-to-end evaluation. Returns `(mAP_50, mAP_50_95)`. |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Requirements
|
|
118
|
+
|
|
119
|
+
* Python 3.9+
|
|
120
|
+
* `numpy`
|
|
121
|
+
* `opencv-python`
|
|
122
|
+
* `torch`
|
|
123
|
+
* `torchvision` (0.16 or newer, for `torchvision.transforms.v2.ToImage`)
|
|
124
|
+
* `matplotlib` (imported by the modules)
|
|
125
|
+
* `sahi`
|
|
126
|
+
* A detector with a `.predict()` method (RF-DETR or Ultralytics YOLO) if you
|
|
127
|
+
use `ai_analytics`, `SAHI_analysis` or `detection_metrics`.
|
|
128
|
+
|
|
129
|
+
## Quick example
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from Computer_vision_assisting_tools.Basic_Utils import img_loc, dataset_check
|
|
133
|
+
from Computer_vision_assisting_tools.Image_Utils import image_processing
|
|
134
|
+
|
|
135
|
+
images, jsons, txts = img_loc("my_dataset") # find all files
|
|
136
|
+
print(dataset_check("my_dataset")) # sanity-check images vs json
|
|
137
|
+
|
|
138
|
+
import cv2
|
|
139
|
+
img = cv2.imread(images[0])
|
|
140
|
+
img_clahe = image_processing(img, normalisation="Clahe")
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Documentation style
|
|
144
|
+
|
|
145
|
+
Every module, function and inner helper has a NumPy-style docstring
|
|
146
|
+
(`Parameters`, `Returns`, `Examples`). Use `help(function_name)` to read
|
|
147
|
+
them.
|
|
148
|
+
|
|
149
|
+
## Author
|
|
150
|
+
|
|
151
|
+
Created and maintained by **Shounak Sanyal**.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Computer_vision_assisting_tools
|
|
2
|
+
|
|
3
|
+
**Author:** Shounak Sanyal
|
|
4
|
+
|
|
5
|
+
A small toolbox of helpers for computer-vision projects. It bundles the
|
|
6
|
+
functions that were most useful in a detection + classification workflow:
|
|
7
|
+
|
|
8
|
+
* find images and annotation files in a folder tree,
|
|
9
|
+
* check and read COCO-style datasets,
|
|
10
|
+
* run a detector (RF-DETR, YOLO) or a CNN classifier on an image and draw the
|
|
11
|
+
predictions next to the ground truth,
|
|
12
|
+
* slice large images into tiles (SAHI) and run detection / classification on
|
|
13
|
+
every tile,
|
|
14
|
+
* pre-process images (CLAHE, Reinhard colour transfer, Otsu, augmentation,
|
|
15
|
+
square padding, tensor transforms),
|
|
16
|
+
* score a detector with IoU, precision / recall and mAP.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Package hierarchy
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
.
|
|
24
|
+
├── README.md
|
|
25
|
+
└── Computer_vision_assisting_tools/
|
|
26
|
+
├── __innit__.py Package docstring (no code)
|
|
27
|
+
├── AI_Metrics.py Detection metrics
|
|
28
|
+
│ ├── IOU_calc
|
|
29
|
+
│ ├── mAP_calc
|
|
30
|
+
│ ├── AUC_calc
|
|
31
|
+
│ └── detection_metrics
|
|
32
|
+
├── Basic_Utils.py Files, datasets, annotations, inference, SAHI
|
|
33
|
+
│ ├── IMAGE_EXTENSIONS (constant)
|
|
34
|
+
│ ├── img_loc
|
|
35
|
+
│ ├── ai_analytics
|
|
36
|
+
│ ├── dataset_check
|
|
37
|
+
│ ├── provide_annotations
|
|
38
|
+
│ ├── SAHI_generation
|
|
39
|
+
│ └── SAHI_analysis
|
|
40
|
+
└── Image_Utils.py Image pre-processing
|
|
41
|
+
├── image_processing
|
|
42
|
+
├── data_augmentation
|
|
43
|
+
├── cell_geometry
|
|
44
|
+
└── cell_transform
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### How the modules depend on each other
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
AI_Metrics.py ──► Basic_Utils.py ──► Image_Utils.py
|
|
51
|
+
(metrics) (data + models) (image helpers)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`AI_Metrics` uses `provide_annotations` and `ai_analytics` from `Basic_Utils`;
|
|
55
|
+
`Basic_Utils` uses `cell_geometry` and `cell_transform` from `Image_Utils`.
|
|
56
|
+
`Image_Utils` depends on none of the others. The modules import each other
|
|
57
|
+
with relative imports (`from .Basic_Utils import *`), so they must be used as
|
|
58
|
+
part of the package, not run directly as scripts.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Module descriptions
|
|
63
|
+
|
|
64
|
+
### `Image_Utils.py` — image pre-processing
|
|
65
|
+
|
|
66
|
+
Helpers that prepare images (for example single-cell crops) before they reach
|
|
67
|
+
a classifier. Images are NumPy arrays read with OpenCV, so colour images are in
|
|
68
|
+
BGR order unless stated otherwise.
|
|
69
|
+
|
|
70
|
+
| Function | What it does |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `image_processing(img, ref_img=None, normalisation='Clahe', grid_window=(8,8))` | Normalises an image with CLAHE (default), Reinhard colour transfer (needs `ref_img`) or Otsu thresholding (`'Otsu'`). |
|
|
73
|
+
| `data_augmentation(img, n_rotate=3, blur=True)` | Returns up to three rotated copies (90°, 180°, 270°; default 3) and, optionally, a Gaussian-blurred copy. |
|
|
74
|
+
| `cell_geometry(img)` | Makes both sides even, then pads the shorter side with black so the image becomes a centred square. |
|
|
75
|
+
| `cell_transform(img, key)` | Converts an image to a `float32` tensor. `key=0` adds ImageNet normalisation, `key=1` only scales to [0, 1]. |
|
|
76
|
+
|
|
77
|
+
### `Basic_Utils.py` — data, annotations, inference and SAHI
|
|
78
|
+
|
|
79
|
+
The main working module. It finds files, checks datasets, reads ground truth,
|
|
80
|
+
runs models and handles SAHI tiling.
|
|
81
|
+
|
|
82
|
+
| Function | What it does |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `IMAGE_EXTENSIONS` | Tuple of file extensions treated as images (case-insensitive). |
|
|
85
|
+
| `img_loc(path)` | Recursively lists image, `.json` and `.txt` files under a folder. Returns `(img_list, json_list, txt_list)`. |
|
|
86
|
+
| `ai_analytics(file, image_path, model, name='RFDETR', key=True, mode='Detection')` | Runs RF-DETR / YOLO detection or CNN classification on one image (the model is moved to the GPU if available). For detection it also reads the COCO ground truth and can draw predictions (blue) and ground truth (green). |
|
|
87
|
+
| `dataset_check(file)` | Checks that the images in a folder and the COCO json agree. Returns five counts (images, json images, annotated images, categories, used categories). |
|
|
88
|
+
| `provide_annotations(json_path, file_name, key='COCO')` | Returns the ground-truth boxes and labels for one image, from a COCO json or from the `'Vanila'` multi-json format. |
|
|
89
|
+
| `SAHI_generation(image_path, ...)` | Slices a large image into tiles and saves them (the output folder is deleted first if it exists). |
|
|
90
|
+
| `SAHI_analysis(image_path, model_det, model_clss=None, ...)` | Detects (and optionally classifies) objects on every tile and draws them on the full image. |
|
|
91
|
+
|
|
92
|
+
### `AI_Metrics.py` — detection metrics
|
|
93
|
+
|
|
94
|
+
Scores a detector on a single image against COCO ground truth. Boxes are in
|
|
95
|
+
`(x_min, y_min, x_max, y_max)` format.
|
|
96
|
+
|
|
97
|
+
| Function | What it does |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `IOU_calc(target_pts, gt_pts)` | IoU of one box against a list of ground-truth boxes. |
|
|
100
|
+
| `mAP_calc(bboxes, gt_bboxes)` | Running precision and recall for IoU thresholds 0.50 – 0.90. |
|
|
101
|
+
| `AUC_calc(precision, recall)` | Builds the smoothed precision curve used for the area under the curve. |
|
|
102
|
+
| `detection_metrics(json_file, img_file, model_test)` | End-to-end evaluation. Returns `(mAP_50, mAP_50_95)`. |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Requirements
|
|
107
|
+
|
|
108
|
+
* Python 3.9+
|
|
109
|
+
* `numpy`
|
|
110
|
+
* `opencv-python`
|
|
111
|
+
* `torch`
|
|
112
|
+
* `torchvision` (0.16 or newer, for `torchvision.transforms.v2.ToImage`)
|
|
113
|
+
* `matplotlib` (imported by the modules)
|
|
114
|
+
* `sahi`
|
|
115
|
+
* A detector with a `.predict()` method (RF-DETR or Ultralytics YOLO) if you
|
|
116
|
+
use `ai_analytics`, `SAHI_analysis` or `detection_metrics`.
|
|
117
|
+
|
|
118
|
+
## Quick example
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from Computer_vision_assisting_tools.Basic_Utils import img_loc, dataset_check
|
|
122
|
+
from Computer_vision_assisting_tools.Image_Utils import image_processing
|
|
123
|
+
|
|
124
|
+
images, jsons, txts = img_loc("my_dataset") # find all files
|
|
125
|
+
print(dataset_check("my_dataset")) # sanity-check images vs json
|
|
126
|
+
|
|
127
|
+
import cv2
|
|
128
|
+
img = cv2.imread(images[0])
|
|
129
|
+
img_clahe = image_processing(img, normalisation="Clahe")
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Documentation style
|
|
133
|
+
|
|
134
|
+
Every module, function and inner helper has a NumPy-style docstring
|
|
135
|
+
(`Parameters`, `Returns`, `Examples`). Use `help(function_name)` to read
|
|
136
|
+
them.
|
|
137
|
+
|
|
138
|
+
## Author
|
|
139
|
+
|
|
140
|
+
Created and maintained by **Shounak Sanyal**.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "Computer_Vision_Assistant_Package"
|
|
3
|
+
version = "1.0"
|
|
4
|
+
authors = [
|
|
5
|
+
{ name="Shounak Sanyal", email="shounaksanyal1902@outlook.com" },
|
|
6
|
+
]
|
|
7
|
+
description = "A user friendly package assiting in the most common computer vision tasks"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Programming Language :: Python :: 3",
|
|
12
|
+
]
|
|
13
|
+
license = "MIT"
|
|
14
|
+
license-files = ["License.txt"]
|
|
15
|
+
|
|
16
|
+
[build-system]
|
|
17
|
+
requires = ["hatchling >= 1.26"]
|
|
18
|
+
build-backend = "hatchling.build"
|
|
19
|
+
|
|
20
|
+
[tool.hatch.build.targets.wheel]
|
|
21
|
+
packages = ["src/Computer_Vision_Assistant_Package"]
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""Detection metrics for object detectors.
|
|
2
|
+
|
|
3
|
+
Functions to score how well a detector's boxes match the ground-truth boxes:
|
|
4
|
+
IoU, precision / recall and mAP. All boxes are in
|
|
5
|
+
``(x_min, y_min, x_max, y_max)`` pixel format.
|
|
6
|
+
|
|
7
|
+
The overall flow is::
|
|
8
|
+
|
|
9
|
+
detection_metrics
|
|
10
|
+
|-- provide_annotations() (Basic_Utils) -> ground-truth boxes
|
|
11
|
+
|-- ai_analytics() (Basic_Utils) -> predicted boxes
|
|
12
|
+
|-- IOU_calc() -> IoU of each prediction vs the GT boxes
|
|
13
|
+
|-- mAP_calc() -> precision / recall at each IoU threshold
|
|
14
|
+
`-- AUC_calc() -> smoothed precision curve for the area
|
|
15
|
+
|
|
16
|
+
Functions
|
|
17
|
+
---------
|
|
18
|
+
IOU_calc
|
|
19
|
+
Intersection-over-Union of one box against a list of boxes.
|
|
20
|
+
mAP_calc
|
|
21
|
+
Precision and recall lists for IoU thresholds 0.50 to 0.90.
|
|
22
|
+
AUC_calc
|
|
23
|
+
Builds the (recall, smoothed precision) curve used to compute the area.
|
|
24
|
+
detection_metrics
|
|
25
|
+
End-to-end mAP@0.5 and mAP@0.5:0.95 for one image.
|
|
26
|
+
|
|
27
|
+
Author: Shounak Sanyal
|
|
28
|
+
"""
|
|
29
|
+
import os, json, cv2
|
|
30
|
+
import numpy as np
|
|
31
|
+
from .Basic_Utils import *
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def IOU_calc(target_pts, gt_pts):
|
|
35
|
+
"""Compute the IoU of one predicted box against every ground-truth box.
|
|
36
|
+
|
|
37
|
+
IoU (Intersection over Union) tells how much two boxes overlap:
|
|
38
|
+
0 means no overlap and 1 means the boxes are identical.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
target_pts : sequence of 4 numbers
|
|
43
|
+
The predicted box as ``(x_min, y_min, x_max, y_max)``.
|
|
44
|
+
gt_pts : list of sequence of 4 numbers
|
|
45
|
+
Ground-truth boxes, each as ``(x_min, y_min, x_max, y_max)``.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
IOU_arr : list of float
|
|
50
|
+
One IoU value (0 to 1) per ground-truth box, in the same order as
|
|
51
|
+
``gt_pts``.
|
|
52
|
+
|
|
53
|
+
Examples
|
|
54
|
+
--------
|
|
55
|
+
>>> IOU_calc((0, 0, 10, 10), [(5, 5, 15, 15), (0, 0, 10, 10)])
|
|
56
|
+
[0.14285714285714285, 1.0]
|
|
57
|
+
"""
|
|
58
|
+
IOU_arr=[]
|
|
59
|
+
for i in range(0, len(gt_pts)):
|
|
60
|
+
x_gt0, y_gt0,x_gt1, y_gt1=gt_pts[i]
|
|
61
|
+
x_tgt0, y_tgt0, x_tgt1, y_tgt1= target_pts
|
|
62
|
+
w_gt, h_gt, w_tgt, h_tgt= x_gt1- x_gt0, y_gt1- y_gt0, x_tgt1- x_tgt0, y_tgt1- y_tgt0
|
|
63
|
+
x_edge, y_edge= min(x_gt1, x_tgt1), min(y_gt1, y_tgt1)
|
|
64
|
+
x_ref, y_ref= max(x_gt0, x_tgt0), max(y_gt0, y_tgt0)
|
|
65
|
+
|
|
66
|
+
if (x_ref>=x_edge) or (y_ref>= y_edge):
|
|
67
|
+
Intersection=0
|
|
68
|
+
else:
|
|
69
|
+
w,h= x_edge-x_ref, y_edge-y_ref
|
|
70
|
+
Intersection= h*w
|
|
71
|
+
Union= (h_gt*w_gt)+ (h_tgt*w_tgt)- Intersection
|
|
72
|
+
IOU= Intersection/Union
|
|
73
|
+
|
|
74
|
+
IOU_arr.append(IOU)
|
|
75
|
+
|
|
76
|
+
return IOU_arr
|
|
77
|
+
|
|
78
|
+
def mAP_calc(bboxes, gt_bboxes):
|
|
79
|
+
"""Compute running precision and recall for IoU thresholds 0.50 to 0.90.
|
|
80
|
+
|
|
81
|
+
The predictions must be sorted by confidence (highest first). For each IoU
|
|
82
|
+
threshold (0.50, 0.55, ..., 0.90) the predictions are visited in order. A
|
|
83
|
+
prediction counts as a true positive if its IoU reaches the threshold and its
|
|
84
|
+
matched ground-truth box has not been used yet; otherwise it is a false
|
|
85
|
+
positive. Precision and recall are recorded after every prediction.
|
|
86
|
+
|
|
87
|
+
Parameters
|
|
88
|
+
----------
|
|
89
|
+
bboxes : array-like of float
|
|
90
|
+
The IoU value of each prediction, sorted by descending confidence.
|
|
91
|
+
gt_bboxes : array-like of int
|
|
92
|
+
For each prediction, the index of the ground-truth box it overlaps
|
|
93
|
+
most (same length and order as ``bboxes``).
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
net_precision_arr : list of list of float
|
|
98
|
+
One list per threshold; each holds the precision after every
|
|
99
|
+
prediction.
|
|
100
|
+
net_recall_arr : list of list of float
|
|
101
|
+
Same layout as ``net_precision_arr``, but for recall.
|
|
102
|
+
"""
|
|
103
|
+
thresh_limits= np.arange(0.5, 1, 0.05)
|
|
104
|
+
net_precision_arr, net_recall_arr=[],[]
|
|
105
|
+
for index in range(0, len(thresh_limits)):
|
|
106
|
+
net_positive= len(np.unique(gt_bboxes))
|
|
107
|
+
true_positive, false_positive=0,0
|
|
108
|
+
precision_arr, recall_arr=[],[]
|
|
109
|
+
checked_gt=[]
|
|
110
|
+
for i in range(0, len(bboxes)):
|
|
111
|
+
if bboxes[i]< thresh_limits[index]:
|
|
112
|
+
|
|
113
|
+
false_positive+=1
|
|
114
|
+
else:
|
|
115
|
+
if gt_bboxes[i] not in checked_gt:
|
|
116
|
+
true_positive+=1
|
|
117
|
+
checked_gt.append(gt_bboxes[i])
|
|
118
|
+
else:
|
|
119
|
+
false_positive+=1
|
|
120
|
+
|
|
121
|
+
precision= true_positive/(true_positive+false_positive)
|
|
122
|
+
recall= true_positive/net_positive
|
|
123
|
+
precision_arr.append(precision)
|
|
124
|
+
recall_arr.append(recall)
|
|
125
|
+
net_precision_arr.append(precision_arr)
|
|
126
|
+
net_recall_arr.append(recall_arr)
|
|
127
|
+
|
|
128
|
+
return net_precision_arr, net_recall_arr
|
|
129
|
+
|
|
130
|
+
def AUC_calc(precision, recall):
|
|
131
|
+
"""Build the smoothed precision-recall curve used to get the area.
|
|
132
|
+
|
|
133
|
+
Each precision value is replaced by the highest precision found at or after
|
|
134
|
+
that point, so the curve never goes up as recall increases. The recall values
|
|
135
|
+
are returned unchanged.
|
|
136
|
+
|
|
137
|
+
Parameters
|
|
138
|
+
----------
|
|
139
|
+
precision : sequence of float
|
|
140
|
+
Precision values in prediction order (one list from ``mAP_calc``).
|
|
141
|
+
recall : sequence of float
|
|
142
|
+
Recall values in the same order.
|
|
143
|
+
|
|
144
|
+
Returns
|
|
145
|
+
-------
|
|
146
|
+
x_arr : sequence of float
|
|
147
|
+
The recall values.
|
|
148
|
+
y_arr : list of float
|
|
149
|
+
The smoothed precision values, same length as ``precision``.
|
|
150
|
+
"""
|
|
151
|
+
x_arr, y_arr=[],[]
|
|
152
|
+
for i in range(0, len(precision)):
|
|
153
|
+
if precision[i]> np.max(precision[i:]):
|
|
154
|
+
y_arr.append(precision[i])
|
|
155
|
+
else:
|
|
156
|
+
y_arr.append(np.max(precision[i:]))
|
|
157
|
+
x_arr= recall
|
|
158
|
+
|
|
159
|
+
return x_arr, y_arr
|
|
160
|
+
|
|
161
|
+
def detection_metrics(json_file, img_file, model_test):
|
|
162
|
+
"""Evaluate a detector on one image and return mAP@0.5 and mAP@0.5:0.95.
|
|
163
|
+
|
|
164
|
+
Steps: load the ground truth from a COCO json, run the model, match every
|
|
165
|
+
prediction to its best-overlapping ground-truth box, sort by confidence,
|
|
166
|
+
compute precision / recall for each IoU threshold and integrate the area.
|
|
167
|
+
|
|
168
|
+
Parameters
|
|
169
|
+
----------
|
|
170
|
+
json_file : str
|
|
171
|
+
Path to the COCO-format annotation file that lists ``img_file``.
|
|
172
|
+
img_file : str
|
|
173
|
+
Path to the image to evaluate.
|
|
174
|
+
model_test : object
|
|
175
|
+
Loaded detection model (RF-DETR style) with a ``.predict(image_path)``
|
|
176
|
+
method that returns boxes, labels and confidence scores.
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
mAP_50 : float
|
|
181
|
+
Score at IoU threshold 0.50, rounded to 3 decimals.
|
|
182
|
+
mAP_50_95 : float
|
|
183
|
+
Score averaged over the IoU thresholds, rounded to 3 decimals.
|
|
184
|
+
|
|
185
|
+
Examples
|
|
186
|
+
--------
|
|
187
|
+
>>> mAP_50, mAP_50_95 = detection_metrics("annotations.json", "img_01.png", model)
|
|
188
|
+
"""
|
|
189
|
+
gt_pts, gt_indices=[],[]
|
|
190
|
+
gt_coords, gt_labels=provide_annotations(json_file, img_file)
|
|
191
|
+
|
|
192
|
+
for j in range(0, len(gt_coords)):
|
|
193
|
+
x0, y0 = int(gt_coords[j][0]), int(gt_coords[j][1])
|
|
194
|
+
x1, y1 = int(gt_coords[j][2])+ x0, int(gt_coords[j][3])+ y0
|
|
195
|
+
gt_pts.append((x0,y0, x1,y1))
|
|
196
|
+
gt_indices.append(j)
|
|
197
|
+
|
|
198
|
+
IOU_arr=[]
|
|
199
|
+
IOU_checkpoints_gt=[]
|
|
200
|
+
|
|
201
|
+
_, coords, labels, _,confidence= ai_analytics(None, img_file, model_test)
|
|
202
|
+
for j in range(0, len(coords)):
|
|
203
|
+
x0, y0 = int(coords[j][0]), int(coords[j][1])
|
|
204
|
+
x1, y1 = int(coords[j][2]), int(coords[j][3])
|
|
205
|
+
tgt_pt=(x0,y0 ,x1,y1)
|
|
206
|
+
IOU=IOU_calc(tgt_pt, gt_pts)
|
|
207
|
+
IOU_checkpoints_gt.append(gt_indices[np.argmax(IOU)])
|
|
208
|
+
IOU=round(np.max(IOU),2)
|
|
209
|
+
IOU_arr.append(IOU)
|
|
210
|
+
|
|
211
|
+
confidence_arr= np.array(confidence)
|
|
212
|
+
IOU_arr= np.array(IOU_arr)
|
|
213
|
+
IOU_checkpoints_gt= np.array(IOU_checkpoints_gt)
|
|
214
|
+
index= np.argsort(confidence_arr)[::-1]
|
|
215
|
+
IOU_arr= IOU_arr[index]
|
|
216
|
+
IOU_checkpoints_gt= IOU_checkpoints_gt[index]
|
|
217
|
+
|
|
218
|
+
net_precision, net_recall= mAP_calc(IOU_arr, IOU_checkpoints_gt)
|
|
219
|
+
net_area=0
|
|
220
|
+
for j in range(0, len(net_precision)):
|
|
221
|
+
x,y= AUC_calc(net_precision[j], net_recall[j])
|
|
222
|
+
|
|
223
|
+
area_arr=[]
|
|
224
|
+
area_i=0
|
|
225
|
+
for k in range(0, len(x)):
|
|
226
|
+
if k<len(x)-1:
|
|
227
|
+
w= x[k+1]-x[k]
|
|
228
|
+
else:
|
|
229
|
+
w=0
|
|
230
|
+
h= y[k]
|
|
231
|
+
area=(h*w)+ area_i
|
|
232
|
+
area_arr.append(area)
|
|
233
|
+
area_i= area_arr[-1]
|
|
234
|
+
net_area+=area_i
|
|
235
|
+
if j==0:
|
|
236
|
+
mAP_50= area_i
|
|
237
|
+
mAP_50_95= net_area/10
|
|
238
|
+
mAP_50, mAP_50_95= round(mAP_50,3), round(mAP_50_95,3)
|
|
239
|
+
|
|
240
|
+
print('net mAP_50', mAP_50, 'net mAP_50:95', mAP_50_95)
|
|
241
|
+
return mAP_50, mAP_50_95
|