mingyang91 commited on
Commit
ec500f1
β€’
1 Parent(s): e40afe0

IoU evaluator

Browse files
.idea/detector.iml CHANGED
@@ -4,7 +4,7 @@
4
  <content url="file://$MODULE_DIR$">
5
  <excludeFolder url="file://$MODULE_DIR$/.venv" />
6
  </content>
7
- <orderEntry type="inheritedJdk" />
8
  <orderEntry type="sourceFolder" forTests="false" />
9
  </component>
10
  </module>
 
4
  <content url="file://$MODULE_DIR$">
5
  <excludeFolder url="file://$MODULE_DIR$/.venv" />
6
  </content>
7
+ <orderEntry type="jdk" jdkName="detector" jdkType="Python SDK" />
8
  <orderEntry type="sourceFolder" forTests="false" />
9
  </component>
10
  </module>
.idea/misc.xml CHANGED
@@ -3,5 +3,5 @@
3
  <component name="Black">
4
  <option name="sdkName" value="Python 3.9 (detector)" />
5
  </component>
6
- <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (detector)" project-jdk-type="Python SDK" />
7
  </project>
 
3
  <component name="Black">
4
  <option name="sdkName" value="Python 3.9 (detector)" />
5
  </component>
6
+ <component name="ProjectRootManager" version="2" project-jdk-name="detector" project-jdk-type="Python SDK" />
7
  </project>
.idea/workspace.xml CHANGED
@@ -4,10 +4,16 @@
4
  <option name="autoReloadType" value="SELECTIVE" />
5
  </component>
6
  <component name="ChangeListManager">
7
- <list default="true" id="d7806539-b6d6-42e7-bb45-1565f5d54891" name="Changes" comment="clean requirements.txt">
 
 
 
 
 
 
8
  <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
9
- <change beforePath="$PROJECT_DIR$/Dockerfile" beforeDir="false" afterPath="$PROJECT_DIR$/Dockerfile" afterDir="false" />
10
- <change beforePath="$PROJECT_DIR$/requirements.txt" beforeDir="false" afterPath="$PROJECT_DIR$/requirements.txt" afterDir="false" />
11
  </list>
12
  <option name="SHOW_DIALOG" value="false" />
13
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -41,28 +47,36 @@
41
  <option name="hideEmptyMiddlePackages" value="true" />
42
  <option name="showLibraryContents" value="true" />
43
  </component>
44
- <component name="PropertiesComponent">{
45
- &quot;keyToString&quot;: {
46
- &quot;Python.demo.executor&quot;: &quot;Run&quot;,
47
- &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
48
- &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
49
- &quot;git-widget-placeholder&quot;: &quot;main&quot;,
50
- &quot;last_opened_file_path&quot;: &quot;/Users/famer.me/PycharmProjects/detector&quot;,
51
- &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
52
- &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
53
- &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
54
- &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
55
- &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
56
- &quot;settings.editor.selected.configurable&quot;: &quot;settings.qodana&quot;,
57
- &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
 
 
 
58
  }
59
- }</component>
60
  <component name="RecentsManager">
61
  <key name="CopyFile.RECENT_KEYS">
 
 
 
 
 
62
  <recent name="$PROJECT_DIR$" />
63
  </key>
64
  </component>
65
- <component name="RunManager" selected="Python.demo">
66
  <configuration name="demo" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
67
  <module name="detector" />
68
  <option name="ENV_FILES" value="" />
@@ -86,6 +100,52 @@
86
  <option name="INPUT_FILE" value="" />
87
  <method v="2" />
88
  </configuration>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  <configuration name="detector" type="Python.FastAPI">
90
  <option name="file" value="$PROJECT_DIR$/main.py" />
91
  <module name="detector" />
@@ -103,6 +163,8 @@
103
  </configuration>
104
  <recent_temporary>
105
  <list>
 
 
106
  <item itemvalue="Python.demo" />
107
  </list>
108
  </recent_temporary>
@@ -110,7 +172,7 @@
110
  <component name="SharedIndexes">
111
  <attachedChunks>
112
  <set>
113
- <option value="bundled-python-sdk-7a29c1521ef0-c986f194a52a-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-233.11799.298" />
114
  </set>
115
  </attachedChunks>
116
  </component>
@@ -124,7 +186,8 @@
124
  <updated>1702301546100</updated>
125
  <workItem from="1702301554378" duration="4025000" />
126
  <workItem from="1702450051021" duration="10065000" />
127
- <workItem from="1702476484538" duration="7523000" />
 
128
  </task>
129
  <task id="LOCAL-00001" summary="init commit">
130
  <option name="closed" value="true" />
@@ -222,7 +285,47 @@
222
  <option name="project" value="LOCAL" />
223
  <updated>1702483217316</updated>
224
  </task>
225
- <option name="localTasksCounter" value="13" />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  <servers />
227
  </component>
228
  <component name="TypeScriptGeneratedFilesManager">
@@ -261,9 +364,14 @@
261
  <MESSAGE value="add test image" />
262
  <MESSAGE value="remove opencv" />
263
  <MESSAGE value="clean requirements.txt" />
264
- <option name="LAST_COMMIT_MESSAGE" value="clean requirements.txt" />
 
 
 
265
  </component>
266
  <component name="com.intellij.coverage.CoverageDataManagerImpl">
267
  <SUITE FILE_PATH="coverage/detector$demo.coverage" NAME="demo Coverage Results" MODIFIED="1702302380580" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
 
 
268
  </component>
269
  </project>
 
4
  <option name="autoReloadType" value="SELECTIVE" />
5
  </component>
6
  <component name="ChangeListManager">
7
+ <list default="true" id="d7806539-b6d6-42e7-bb45-1565f5d54891" name="Changes" comment="fix confidence">
8
+ <change afterPath="$PROJECT_DIR$/evaluator.py" afterDir="false" />
9
+ <change afterPath="$PROJECT_DIR$/tests/coco8.zip" afterDir="false" />
10
+ <change afterPath="$PROJECT_DIR$/tests/project-2-at-2024-01-20-11-43-00ad4911.zip" afterDir="false" />
11
+ <change afterPath="$PROJECT_DIR$/yolo_dataset.py" afterDir="false" />
12
+ <change beforePath="$PROJECT_DIR$/.idea/detector.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/detector.iml" afterDir="false" />
13
+ <change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
14
  <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
15
+ <change beforePath="$PROJECT_DIR$/demo.py" beforeDir="false" afterPath="$PROJECT_DIR$/demo.py" afterDir="false" />
16
+ <change beforePath="$PROJECT_DIR$/model.py" beforeDir="false" />
17
  </list>
18
  <option name="SHOW_DIALOG" value="false" />
19
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
 
47
  <option name="hideEmptyMiddlePackages" value="true" />
48
  <option name="showLibraryContents" value="true" />
49
  </component>
50
+ <component name="PropertiesComponent"><![CDATA[{
51
+ "keyToString": {
52
+ "Python.demo.executor": "Run",
53
+ "Python.evaluator.executor": "Debug",
54
+ "Python.extract.executor": "Run",
55
+ "Python.yolo_dataset.executor": "Run",
56
+ "RunOnceActivity.OpenProjectViewOnStart": "true",
57
+ "RunOnceActivity.ShowReadmeOnStart": "true",
58
+ "git-widget-placeholder": "main",
59
+ "last_opened_file_path": "/Users/famer.me/PycharmProjects/detector/tests",
60
+ "node.js.detected.package.eslint": "true",
61
+ "node.js.detected.package.tslint": "true",
62
+ "node.js.selected.package.eslint": "(autodetect)",
63
+ "node.js.selected.package.tslint": "(autodetect)",
64
+ "nodejs_package_manager_path": "npm",
65
+ "settings.editor.selected.configurable": "settings.qodana",
66
+ "vue.rearranger.settings.migration": "true"
67
  }
68
+ }]]></component>
69
  <component name="RecentsManager">
70
  <key name="CopyFile.RECENT_KEYS">
71
+ <recent name="$PROJECT_DIR$/tests" />
72
+ <recent name="$PROJECT_DIR$" />
73
+ </key>
74
+ <key name="MoveFile.RECENT_KEYS">
75
+ <recent name="$PROJECT_DIR$/tests" />
76
  <recent name="$PROJECT_DIR$" />
77
  </key>
78
  </component>
79
+ <component name="RunManager" selected="Python.evaluator">
80
  <configuration name="demo" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
81
  <module name="detector" />
82
  <option name="ENV_FILES" value="" />
 
100
  <option name="INPUT_FILE" value="" />
101
  <method v="2" />
102
  </configuration>
103
+ <configuration name="evaluator" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
104
+ <module name="detector" />
105
+ <option name="ENV_FILES" value="" />
106
+ <option name="INTERPRETER_OPTIONS" value="" />
107
+ <option name="PARENT_ENVS" value="true" />
108
+ <envs>
109
+ <env name="PYTHONUNBUFFERED" value="1" />
110
+ </envs>
111
+ <option name="SDK_HOME" value="" />
112
+ <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
113
+ <option name="IS_MODULE_SDK" value="true" />
114
+ <option name="ADD_CONTENT_ROOTS" value="true" />
115
+ <option name="ADD_SOURCE_ROOTS" value="true" />
116
+ <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
117
+ <option name="SCRIPT_NAME" value="$PROJECT_DIR$/evaluator.py" />
118
+ <option name="PARAMETERS" value="" />
119
+ <option name="SHOW_COMMAND_LINE" value="false" />
120
+ <option name="EMULATE_TERMINAL" value="false" />
121
+ <option name="MODULE_MODE" value="false" />
122
+ <option name="REDIRECT_INPUT" value="false" />
123
+ <option name="INPUT_FILE" value="" />
124
+ <method v="2" />
125
+ </configuration>
126
+ <configuration name="yolo_dataset" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
127
+ <module name="detector" />
128
+ <option name="ENV_FILES" value="" />
129
+ <option name="INTERPRETER_OPTIONS" value="" />
130
+ <option name="PARENT_ENVS" value="true" />
131
+ <envs>
132
+ <env name="PYTHONUNBUFFERED" value="1" />
133
+ </envs>
134
+ <option name="SDK_HOME" value="" />
135
+ <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
136
+ <option name="IS_MODULE_SDK" value="true" />
137
+ <option name="ADD_CONTENT_ROOTS" value="true" />
138
+ <option name="ADD_SOURCE_ROOTS" value="true" />
139
+ <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
140
+ <option name="SCRIPT_NAME" value="$PROJECT_DIR$/yolo_dataset.py" />
141
+ <option name="PARAMETERS" value="" />
142
+ <option name="SHOW_COMMAND_LINE" value="false" />
143
+ <option name="EMULATE_TERMINAL" value="false" />
144
+ <option name="MODULE_MODE" value="false" />
145
+ <option name="REDIRECT_INPUT" value="false" />
146
+ <option name="INPUT_FILE" value="" />
147
+ <method v="2" />
148
+ </configuration>
149
  <configuration name="detector" type="Python.FastAPI">
150
  <option name="file" value="$PROJECT_DIR$/main.py" />
151
  <module name="detector" />
 
163
  </configuration>
164
  <recent_temporary>
165
  <list>
166
+ <item itemvalue="Python.evaluator" />
167
+ <item itemvalue="Python.yolo_dataset" />
168
  <item itemvalue="Python.demo" />
169
  </list>
170
  </recent_temporary>
 
172
  <component name="SharedIndexes">
173
  <attachedChunks>
174
  <set>
175
+ <option value="bundled-python-sdk-50da183f06c8-2887949eec09-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-233.13135.95" />
176
  </set>
177
  </attachedChunks>
178
  </component>
 
186
  <updated>1702301546100</updated>
187
  <workItem from="1702301554378" duration="4025000" />
188
  <workItem from="1702450051021" duration="10065000" />
189
+ <workItem from="1702476484538" duration="9613000" />
190
+ <workItem from="1705757850315" duration="10355000" />
191
  </task>
192
  <task id="LOCAL-00001" summary="init commit">
193
  <option name="closed" value="true" />
 
285
  <option name="project" value="LOCAL" />
286
  <updated>1702483217316</updated>
287
  </task>
288
+ <task id="LOCAL-00013" summary="clean requirements.txt">
289
+ <option name="closed" value="true" />
290
+ <created>1702484185625</created>
291
+ <option name="number" value="00013" />
292
+ <option name="presentableId" value="LOCAL-00013" />
293
+ <option name="project" value="LOCAL" />
294
+ <updated>1702484185625</updated>
295
+ </task>
296
+ <task id="LOCAL-00014" summary="use env">
297
+ <option name="closed" value="true" />
298
+ <created>1702484512308</created>
299
+ <option name="number" value="00014" />
300
+ <option name="presentableId" value="LOCAL-00014" />
301
+ <option name="project" value="LOCAL" />
302
+ <updated>1702484512308</updated>
303
+ </task>
304
+ <task id="LOCAL-00015" summary="use /run/secrets">
305
+ <option name="closed" value="true" />
306
+ <created>1702484869890</created>
307
+ <option name="number" value="00015" />
308
+ <option name="presentableId" value="LOCAL-00015" />
309
+ <option name="project" value="LOCAL" />
310
+ <updated>1702484869890</updated>
311
+ </task>
312
+ <task id="LOCAL-00016" summary="use /run/secrets">
313
+ <option name="closed" value="true" />
314
+ <created>1702484897551</created>
315
+ <option name="number" value="00016" />
316
+ <option name="presentableId" value="LOCAL-00016" />
317
+ <option name="project" value="LOCAL" />
318
+ <updated>1702484897551</updated>
319
+ </task>
320
+ <task id="LOCAL-00017" summary="fix confidence">
321
+ <option name="closed" value="true" />
322
+ <created>1702485964999</created>
323
+ <option name="number" value="00017" />
324
+ <option name="presentableId" value="LOCAL-00017" />
325
+ <option name="project" value="LOCAL" />
326
+ <updated>1702485964999</updated>
327
+ </task>
328
+ <option name="localTasksCounter" value="18" />
329
  <servers />
330
  </component>
331
  <component name="TypeScriptGeneratedFilesManager">
 
364
  <MESSAGE value="add test image" />
365
  <MESSAGE value="remove opencv" />
366
  <MESSAGE value="clean requirements.txt" />
367
+ <MESSAGE value="use env" />
368
+ <MESSAGE value="use /run/secrets" />
369
+ <MESSAGE value="fix confidence" />
370
+ <option name="LAST_COMMIT_MESSAGE" value="fix confidence" />
371
  </component>
372
  <component name="com.intellij.coverage.CoverageDataManagerImpl">
373
  <SUITE FILE_PATH="coverage/detector$demo.coverage" NAME="demo Coverage Results" MODIFIED="1702302380580" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
374
+ <SUITE FILE_PATH="coverage/detector$evaluator.coverage" NAME="evaluator Coverage Results" MODIFIED="1705768159641" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
375
+ <SUITE FILE_PATH="coverage/detector$extract.coverage" NAME="yolo_dataset Coverage Results" MODIFIED="1705764465837" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
376
  </component>
377
  </project>
demo.py CHANGED
@@ -1,4 +1,3 @@
1
-
2
  import time
3
  from PIL import Image
4
  import streamlit as st
@@ -38,4 +37,4 @@ def main():
38
 
39
 
40
  if __name__ == '__main__':
41
- main()
 
 
1
  import time
2
  from PIL import Image
3
  import streamlit as st
 
37
 
38
 
39
  if __name__ == '__main__':
40
+ main()
evaluator.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Callable
2
+
3
+ from PIL.Image import Image
4
+ from coco_eval import CocoEvaluator
5
+ from pycocotools.coco import COCO
6
+ from tqdm import tqdm
7
+
8
+ from yolo_dataset import YoloDataset
9
+ from yolo_fire import model
10
+
11
+ image_loader = Callable[[str], Image]
12
+
13
+
14
+ def evaluate(coco_gt: COCO, loader: image_loader, confidence_threshold=0.6):
15
+ # initialize evaluator with ground truth (gt)
16
+ evaluator = CocoEvaluator(coco_gt=coco_gt, iou_types=["bbox"])
17
+
18
+ print("Running evaluation...")
19
+ for image_id, annotations in tqdm(coco_gt.imgToAnns.items()):
20
+ # get the inputs
21
+ image = coco_gt.imgs[image_id]
22
+ results = model(source=loader(image["file_name"]))
23
+ for result in results:
24
+ coco_anns = yolo_boxes_to_coco_annotations(image_id, result.boxes, confidence_threshold=confidence_threshold)
25
+ if len(coco_anns) == 0:
26
+ continue
27
+ evaluator.update(coco_anns)
28
+
29
+ if len(evaluator.eval_imgs["bbox"]) == 0:
30
+ print("No detections!")
31
+ return
32
+ evaluator.synchronize_between_processes()
33
+ evaluator.accumulate()
34
+ evaluator.summarize()
35
+
36
+
37
+ def yolo_boxes_to_coco_annotations(image_id: int, yolo_boxes, confidence_threshold=0.6):
38
+ return [
39
+ {
40
+ "image_id": image_id,
41
+ "category_id": box.cls.tolist()[0],
42
+ "area": box.xywh.tolist()[0][2] * box.xywh.tolist()[0][3],
43
+ "bbox": box.xywh.tolist()[0],
44
+ "score": box.conf.tolist()[0],
45
+ }
46
+ for box in yolo_boxes if box.conf.tolist()[0] > confidence_threshold
47
+ ]
48
+
49
+
50
+ if __name__ == '__main__':
51
+ yolo_dataset = YoloDataset.from_zip_file('tests/coco8.zip')
52
+ coco_gt = yolo_dataset.to_coco()
53
+ evaluate(coco_gt=coco_gt, loader=yolo_dataset.load_image, confidence_threshold=0.1)
model.py DELETED
@@ -1,93 +0,0 @@
1
- import torch
2
- import random
3
- from PIL import ImageDraw
4
- import torchvision.transforms as T
5
-
6
- # COCO Classes
7
- CLASSES = [
8
- 'N/A', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
9
- 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A',
10
- 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse',
11
- 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack',
12
- 'umbrella', 'N/A', 'N/A', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis',
13
- 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove',
14
- 'skateboard', 'surfboard', 'tennis racket', 'bottle', 'N/A', 'wine glass',
15
- 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich',
16
- 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake',
17
- 'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table', 'N/A',
18
- 'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard',
19
- 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A',
20
- 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier',
21
- 'toothbrush'
22
- ]
23
-
24
- # Standard PyTorch mean-std Input Image Normalization
25
- transform = T.Compose([
26
- T.Resize(500),
27
- T.ToTensor(),
28
- T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
29
- ])
30
-
31
-
32
- # For Output Bounding Box Post-processing
33
- def box_cxcywh_to_xyxy(x):
34
- x_c, y_c, w, h = x.unbind(1)
35
- b = [(x_c - 0.5 * w), (y_c - 0.5 * h),
36
- (x_c + 0.5 * w), (y_c + 0.5 * h)]
37
- return torch.stack(b, dim=1)
38
-
39
-
40
- def rescale_bboxes(out_bbox, size):
41
- img_w, img_h = size
42
- b = box_cxcywh_to_xyxy(out_bbox)
43
- b = b * torch.tensor([img_w, img_h, img_w, img_h], dtype=torch.float32)
44
- return b
45
-
46
-
47
- # Pre-processing on Image
48
- def image_processing(im, model, transform, confidence=0.9):
49
- # im = Image.open(image_path)
50
- img = transform(im).unsqueeze(0)
51
-
52
- outputs = model(img)
53
- probas = outputs['pred_logits'].softmax(-1)[0, :, :-1]
54
- keep = probas.max(-1).values > confidence
55
- bboxes_scaled = rescale_bboxes(outputs['pred_boxes'][0, keep], im.size)
56
-
57
- return probas[keep], bboxes_scaled
58
-
59
-
60
- # Helper Functions for Plotting BBoxes
61
- def plot_one_box(x, img, color=None, label=None, line_thickness=None):
62
- width, height = img.size
63
- tl = line_thickness or round(0.002 * (width + height) / 2) + 1 # line/font thickness
64
- color = color or (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
65
- c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))
66
- img_draw = ImageDraw.Draw(img)
67
- img_draw.rectangle((c1[0], c1[1], c2[0], c2[1]), outline=color, width=tl)
68
- if label:
69
- tf = max(tl - 1, 1) # font thickness
70
- x1, y1, x2, y2 = img_draw.textbbox(c1, label, stroke_width=tf)
71
- img_draw.rectangle((x1, y1, x2, y2), fill=color)
72
- img_draw.text((x1, y1), label, fill=(255, 255, 255))
73
-
74
-
75
- # Ploting Bounding Box on img
76
- def add_bboxes(pil_img, prob, bboxes):
77
- for p, coord in zip(prob, bboxes.tolist()):
78
- cl = p.argmax()
79
- text = f'{CLASSES[cl]}: {p[cl]: 0.2f}'
80
- plot_one_box(x=coord, img=pil_img, label=text)
81
-
82
- return pil_img
83
-
84
-
85
- def detect(im, confidence):
86
- # Load model
87
- model = torch.hub.load('facebookresearch/detr', 'detr_resnet101', pretrained=True)
88
- model.eval()
89
-
90
- scores, boxes = image_processing(im, model, transform, confidence / 100)
91
- im = add_bboxes(im, scores, boxes)
92
-
93
- return im
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/coco8.zip ADDED
Binary file (443 kB). View file
 
tests/project-2-at-2024-01-20-11-43-00ad4911.zip ADDED
Binary file (925 kB). View file
 
yolo_dataset.py ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Author: Ming Yang
2
+ # Date: 2023/01/20
3
+ # Description: Traverse the zip file but not decompress it.
4
+ # Suppose the zip file contains yolo format annotation files.
5
+ # /
6
+ # β”œβ”€β”€ classes.txt
7
+ # β”œβ”€β”€ images
8
+ # β”‚ β”œβ”€β”€ 1.jpg
9
+ # β”‚ β”œβ”€β”€ 2.jpg
10
+ # β”‚ └── ...
11
+ # └── labels
12
+ # β”œβ”€β”€ 1.txt
13
+ # β”œβ”€β”€ 2.txt
14
+ # └── ...
15
+ import io
16
+ import json
17
+ from datetime import datetime
18
+ from typing import Optional
19
+ from zipfile import ZipFile
20
+ from PIL import Image
21
+ from pycocotools import coco
22
+ from pycocotools.coco import COCO
23
+
24
+ yolo_label = {
25
+ 'class': str,
26
+ 'class_id': int,
27
+ 'x_center': float,
28
+ 'y_center': float,
29
+ 'width': float,
30
+ 'height': float
31
+ }
32
+
33
+ yolo_image = {
34
+ 'image_name': str,
35
+ 'image': Image,
36
+ 'labels': list[yolo_label]
37
+ }
38
+
39
+ coco_annotation = {
40
+ "id": int,
41
+ "image_id": int, # the id of the image that the annotation belongs to
42
+ "category_id": int, # the id of the category that the annotation belongs to
43
+ # "segmentation": RLE or [polygon],
44
+ "area": float,
45
+ "bbox": [float, float, float, float], # [x,y,width,height]
46
+ "iscrowd": bool, # 0 or 1,
47
+ }
48
+
49
+ coco_category = {
50
+ "id": int,
51
+ "name": str,
52
+ "supercategory": Optional[str],
53
+ }
54
+
55
+ coco_image = {
56
+ "id": int,
57
+ "width": int,
58
+ "height": int,
59
+ "file_name": str,
60
+ "date_captured": Optional[datetime],
61
+ }
62
+
63
+ coco_dataset = {
64
+ "images": list[coco_image], # list of all images in the dataset
65
+ "annotations": list[coco_annotation], # list of all annotations in the dataset
66
+ "categories": list[coco_category] # list of all categories
67
+ }
68
+
69
+
70
+ class YoloImage:
71
+ def __init__(self, image_name: str, image: Image, labels: list[yolo_label]):
72
+ self.image_name = image_name
73
+ self.image = image
74
+ self.labels = labels
75
+
76
+ def __repr__(self):
77
+ return f'YoloImage(image_name={self.image_name}, image={self.image}, labels={self.labels})'
78
+
79
+ def to_coco_image(self, id: int) -> coco_image:
80
+ return {
81
+ "id": id,
82
+ "width": self.image.width,
83
+ "height": self.image.height,
84
+ "file_name": self.image_name,
85
+ }
86
+
87
+ def to_coco_annotations(self, image_id: int, ann_id_start: int) -> list[coco_annotation]:
88
+ ann_id = ann_id_start
89
+ annotations: list[coco_annotation] = []
90
+ for label in self.labels:
91
+ ann_id = ann_id + 1
92
+ annotations.append({
93
+ "id": ann_id,
94
+ "image_id": image_id,
95
+ "category_id": label['class_id'],
96
+ "area": label['width'] * label['height'],
97
+ "bbox": [label['x_center'] - label['width'] / 2, label['y_center'] - label['height'] / 2,
98
+ label['width'], label['height']],
99
+ "iscrowd": False,
100
+ })
101
+ return annotations
102
+
103
+
104
+ class YoloDataset:
105
+ _zip_file: ZipFile
106
+ _classes: list[str]
107
+ _images: list[str]
108
+ _labels: list[str]
109
+
110
+ def __init__(self, zip_file: ZipFile, classes=None, images=None, labels=None):
111
+ if labels is None:
112
+ labels = []
113
+ if images is None:
114
+ images = []
115
+ if classes is None:
116
+ classes = []
117
+ self._zip_file = zip_file
118
+ self._classes = classes
119
+ self._images = images
120
+ self._labels = labels
121
+
122
+ @staticmethod
123
+ def from_zip_file(zip_file: str) -> 'YoloDataset':
124
+ zip_file = ZipFile(zip_file, 'r')
125
+ namelist = zip_file.namelist()
126
+ root_name = namelist[0]
127
+ namelist = list(filter(lambda x: not zip_file.getinfo(x).is_dir(), namelist))
128
+ if 'classes.txt' in namelist:
129
+ classes = zip_file.read('classes.txt').decode('utf-8').split('\n')
130
+ else:
131
+ classes = []
132
+ images = list(filter(lambda x: x.startswith(root_name + 'images'), namelist))
133
+ labels = list(filter(lambda x: x.startswith(root_name + 'labels'), namelist))
134
+ assert len(images) == len(labels) and len(images) > 0
135
+ images.sort()
136
+ labels.sort()
137
+ for image, label in zip(images, labels):
138
+ image_name = image.split('/')[-1]
139
+ label_name = label.split('/')[-1]
140
+ assert image_name.split('.')[0] == label_name.split('.')[0]
141
+ return YoloDataset(zip_file, classes, images, labels)
142
+
143
+ def __len__(self):
144
+ return len(self._images)
145
+
146
+ def __getitem__(self, index: int) -> YoloImage:
147
+ image_name = self._images[index]
148
+ labels = self._zip_file.read(self._labels[index]).decode('utf-8').split('\n')
149
+ labels = list(filter(lambda x: len(x) > 0, labels))
150
+ labels = list(map(lambda x: x.split(' '), labels))
151
+ labels = list(map(lambda x: {
152
+ 'class': self._classes[int(x[0])] if len(self._classes) > int(x[0]) else 'unknown',
153
+ 'class_id': int(x[0]),
154
+ 'x_center': float(x[1]),
155
+ 'y_center': float(x[2]),
156
+ 'width': float(x[3]),
157
+ 'height': float(x[4])
158
+ }, labels))
159
+
160
+ return YoloImage(image_name, Image.open(self._zip_file.open(self._images[index])), labels)
161
+
162
+ def __iter__(self):
163
+ for i in range(len(self)):
164
+ yield self[i]
165
+
166
+ def load_image(self, image_name: str) -> Image:
167
+ return Image.open(self._zip_file.open(image_name))
168
+
169
+ def to_coco(self) -> COCO:
170
+ images: list[coco_image] = []
171
+ annotations: list[coco_annotation] = []
172
+ categories: list[coco_category] = []
173
+ ann_id = 0
174
+ for i in range(len(self)):
175
+ image = self[i]
176
+ images.append(image.to_coco_image(i))
177
+ annotations.extend(image.to_coco_annotations(i, ann_id))
178
+ ann_id = ann_id + len(image.labels)
179
+ for i in range(len(self._classes)):
180
+ categories.append({
181
+ "id": i,
182
+ "name": self._classes[i],
183
+ "supercategory": None,
184
+ })
185
+
186
+ coco_ds = coco.COCO()
187
+ coco_ds.dataset = {
188
+ "images": images,
189
+ "annotations": annotations,
190
+ "categories": categories,
191
+ }
192
+ coco_ds.createIndex()
193
+ return coco_ds
194
+
195
+
196
+ if __name__ == '__main__':
197
+ dataset = YoloDataset.from_zip_file('tests/coco8.zip')
198
+ coco = dataset.to_coco()
199
+ print(coco)