Skip to content

Commit 8be1d99

Browse files
authored
Merge pull request #99 from UCL/hackathon-additions
Hackathon additions
2 parents 2b1deff + 6beb1ae commit 8be1d99

19 files changed

+1472
-55
lines changed
File renamed without changes.

example_pipeline/colon.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
3+
# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
4+
train: /colon_data/polyps_small/images/train
5+
val: /colon_data/polyps_small/images/valid
6+
test: /colon_data/polyps_small/images/valid # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794
7+
8+
# number of classes
9+
nc: 1
10+
11+
# class names
12+
names: [ 'polyp']
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": []
9+
},
10+
{
11+
"cell_type": "code",
12+
"execution_count": 1,
13+
"metadata": {},
14+
"outputs": [
15+
{
16+
"name": "stdout",
17+
"output_type": "stream",
18+
"text": [
19+
"Number of items: 2\n",
20+
"Item 1: x_min=0, y_min=0, x_max=100, y_max=105\n",
21+
"Item 2: x_min=144, y_min=225, x_max=193, y_max=278\n"
22+
]
23+
}
24+
],
25+
"source": [
26+
"import cv2\n",
27+
"import numpy as np\n",
28+
"\n",
29+
"def find_connected_components(image_path):\n",
30+
" # Read the image\n",
31+
" image = cv2.imread(image_path)\n",
32+
" \n",
33+
" # Convert the image to grayscale\n",
34+
" gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n",
35+
" \n",
36+
" # Threshold the image to create a binary image\n",
37+
" _, binary = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY)\n",
38+
" \n",
39+
" # Find connected components\n",
40+
" num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary, connectivity=8)\n",
41+
" \n",
42+
" # Initialize a list to store bounding boxes\n",
43+
" bounding_boxes = []\n",
44+
" \n",
45+
" for i in range(1, num_labels): # Skip the background label 0\n",
46+
" x_min = stats[i, cv2.CC_STAT_LEFT]\n",
47+
" y_min = stats[i, cv2.CC_STAT_TOP]\n",
48+
" width = stats[i, cv2.CC_STAT_WIDTH]\n",
49+
" height = stats[i, cv2.CC_STAT_HEIGHT]\n",
50+
" x_max = x_min + width - 1\n",
51+
" y_max = y_min + height - 1\n",
52+
" \n",
53+
" bounding_boxes.append((x_min, y_min, x_max, y_max))\n",
54+
" \n",
55+
" return num_labels - 1, bounding_boxes # Subtract 1 to exclude the background\n",
56+
"\n",
57+
"# Example usage\n",
58+
"image_path = '../images/tst_seg_tst_seg500.png'\n",
59+
"num_items, bounding_boxes = find_connected_components(image_path)\n",
60+
"print(f\"Number of items: {num_items}\")\n",
61+
"for i, (x_min, y_min, x_max, y_max) in enumerate(bounding_boxes):\n",
62+
" print(f\"Item {i+1}: x_min={x_min}, y_min={y_min}, x_max={x_max}, y_max={y_max}\")"
63+
]
64+
},
65+
{
66+
"cell_type": "code",
67+
"execution_count": 3,
68+
"metadata": {},
69+
"outputs": [
70+
{
71+
"ename": "SyntaxError",
72+
"evalue": "invalid syntax (2760322440.py, line 44)",
73+
"output_type": "error",
74+
"traceback": [
75+
"\u001b[1;36m Cell \u001b[1;32mIn[3], line 44\u001b[1;36m\u001b[0m\n\u001b[1;33m num_items, boundinimport cv2\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n"
76+
]
77+
}
78+
],
79+
"source": [
80+
"import cv2\n",
81+
"import numpy as np\n",
82+
"\n",
83+
"def find_connected_components(image_path, output_file):\n",
84+
" # Read the image\n",
85+
" image = cv2.imread(image_path)\n",
86+
" \n",
87+
" # Convert the image to grayscale\n",
88+
" gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n",
89+
" \n",
90+
" # Threshold the image to create a binary image\n",
91+
" _, binary = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY)\n",
92+
" \n",
93+
" # Find connected components\n",
94+
" num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary, connectivity=8)\n",
95+
" \n",
96+
" # Initialize a list to store bounding boxes\n",
97+
" bounding_boxes = []\n",
98+
" \n",
99+
" for i in range(1, num_labels): # Skip the background label 0\n",
100+
" x_min = stats[i, cv2.CC_STAT_LEFT]\n",
101+
" y_min = stats[i, cv2.CC_STAT_TOP]\n",
102+
" width = stats[i, cv2.CC_STAT_WIDTH]\n",
103+
" height = stats[i, cv2.CC_STAT_HEIGHT]\n",
104+
" x_max = x_min + width - 1\n",
105+
" y_max = y_min + height - 1\n",
106+
" \n",
107+
" # Convert to center coordinates and dimensions\n",
108+
" x_center = x_min + width / 2\n",
109+
" y_center = y_min + height / 2\n",
110+
" \n",
111+
" bounding_boxes.append((x_center, y_center, width, height))\n",
112+
" \n",
113+
" # Write results to a text file\n",
114+
" with open(output_file, 'w') as f:\n",
115+
" for x_center, y_center, width, height in bounding_boxes:\n",
116+
" f.write(f\"0 {x_center:.8f} {y_center:.8f} {width:.8f} {height:.8f}\\n\")\n",
117+
" \n",
118+
" return num_labels - 1, bounding_boxes # Subtract 1 to exclude the background\n",
119+
"\n",
120+
"# Example usage\n",
121+
"image_path = '../images/tst_seg_tst_seg500.png'\n",
122+
"output_file = '../labels/bounding_boxes.txt'\n",
123+
"num_items, bounding_boxes = find_connected_components(image_path, output_file)\n",
124+
"print(f\"Number of items: {num_items}\")\n",
125+
"for i, (x_center, y_center, width, height) in enumerate(bounding_boxes):\n",
126+
" print(f\"Item {i+1}: x_center={x_center}, y_center={y_center}, width={width}, height={height}\")"
127+
]
128+
},
129+
{
130+
"cell_type": "code",
131+
"execution_count": 4,
132+
"metadata": {},
133+
"outputs": [
134+
{
135+
"name": "stdout",
136+
"output_type": "stream",
137+
"text": [
138+
"Number of items: 2\n",
139+
"Item 1: x_center=0.09115523465703972, y_center=0.11830357142857142, width=0.18231046931407943, height=0.23660714285714285\n",
140+
"Item 2: x_center=0.30505415162454874, y_center=0.5625, width=0.09025270758122744, height=0.12053571428571429\n"
141+
]
142+
}
143+
],
144+
"source": [
145+
"import cv2\n",
146+
"import numpy as np\n",
147+
"import os\n",
148+
"\n",
149+
"def find_connected_components(image_path, output_dir):\n",
150+
" # Read the image\n",
151+
" image = cv2.imread(image_path)\n",
152+
" \n",
153+
" # Get image dimensions\n",
154+
" image_height, image_width = image.shape[:2]\n",
155+
" \n",
156+
" # Convert the image to grayscale\n",
157+
" gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n",
158+
" \n",
159+
" # Threshold the image to create a binary image\n",
160+
" _, binary = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY)\n",
161+
" \n",
162+
" # Find connected components\n",
163+
" num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary, connectivity=8)\n",
164+
" \n",
165+
" # Initialize a list to store bounding boxes\n",
166+
" bounding_boxes = []\n",
167+
" \n",
168+
" for i in range(1, num_labels): # Skip the background label 0\n",
169+
" x_min = stats[i, cv2.CC_STAT_LEFT]\n",
170+
" y_min = stats[i, cv2.CC_STAT_TOP]\n",
171+
" width = stats[i, cv2.CC_STAT_WIDTH]\n",
172+
" height = stats[i, cv2.CC_STAT_HEIGHT]\n",
173+
" \n",
174+
" # Convert to center coordinates and dimensions\n",
175+
" x_center = x_min + width / 2\n",
176+
" y_center = y_min + height / 2\n",
177+
" \n",
178+
" # Convert to ratios\n",
179+
" x_center /= image_width\n",
180+
" y_center /= image_height\n",
181+
" width /= image_width\n",
182+
" height /= image_height\n",
183+
" \n",
184+
" bounding_boxes.append((x_center, y_center, width, height))\n",
185+
" \n",
186+
" # Create the output file path\n",
187+
" base_name = os.path.basename(image_path)\n",
188+
" output_file = os.path.join(output_dir, os.path.splitext(base_name)[0] + '.txt')\n",
189+
" \n",
190+
" # Write results to a text file\n",
191+
" with open(output_file, 'w') as f:\n",
192+
" for x_center, y_center, width, height in bounding_boxes:\n",
193+
" f.write(f\"0 {x_center:.8f} {y_center:.8f} {width:.8f} {height:.8f}\\n\")\n",
194+
" \n",
195+
" return num_labels - 1, bounding_boxes # Subtract 1 to exclude the background\n",
196+
"\n",
197+
"# Example usage\n",
198+
"image_path = '../images/tst_seg_tst_seg500.png'\n",
199+
"output_dir = '../labels'\n",
200+
"num_items, bounding_boxes = find_connected_components(image_path, output_dir)\n",
201+
"print(f\"Number of items: {num_items}\")\n",
202+
"for i, (x_center, y_center, width, height) in enumerate(bounding_boxes):\n",
203+
" print(f\"Item {i+1}: x_center={x_center}, y_center={y_center}, width={width}, height={height}\")"
204+
]
205+
}
206+
],
207+
"metadata": {
208+
"kernelspec": {
209+
"display_name": "pgta",
210+
"language": "python",
211+
"name": "python3"
212+
},
213+
"language_info": {
214+
"codemirror_mode": {
215+
"name": "ipython",
216+
"version": 3
217+
},
218+
"file_extension": ".py",
219+
"mimetype": "text/x-python",
220+
"name": "python",
221+
"nbconvert_exporter": "python",
222+
"pygments_lexer": "ipython3",
223+
"version": "3.11.10"
224+
}
225+
},
226+
"nbformat": 4,
227+
"nbformat_minor": 2
228+
}

example_pipeline/instructions.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
This is an example pipeline on how to convert output from Blender Randomiser to COCO format labelling in preperation of fine tuning polyps detection using YOLOv7
2+
3+
# Data Preperation
4+
Once the segmentation of polyps are obtained. Use find_bounding_box.ipynb to output the bounding box information as text files.
5+
6+
show_bbox.ipynb can be used to show if the correct bounding boxes have been converted.
7+
8+
# IMPORTANT!
9+
**<span style="color:red">
10+
When Google Colab session finishes, ALL data is wiped, please save the models!
11+
</span>**
12+
## To tune the model using custom data:
13+
- clone yolov7 git and install it https://github.com/WongKinYiu/yolov7; pip install -r requirements.txt
14+
- log into wandb account (your own API - see below) DO NOT SHARE!
15+
- run python training script
16+
17+
```python train.py --epochs 100 --device 0 --entity colon_coders --workers 8 --batch-size 32 --data /content/colon.yaml --img 512 512 --cfg /content/yolov7_training_config.yaml --weights '/content/yolov7_training.pt' --name yolov7-colon --hyp data/hyp.scratch.custom.yaml```
18+
19+
## Google colab instructions
20+
- upload polyps.zip to google drive
21+
- upload colon.yaml, yolov7_training.pt, yolov7_training_config.yaml to google drive
22+
- open google colab and mount drive
23+
- unzip polyps.zip
24+
```python
25+
import zipfile
26+
with zipfile.ZipFile("/content/drive/MyDrive/polyps.zip", 'r') as zip_ref:
27+
zip_ref.extractall("/content/colon_data")
28+
```
29+
- Important: remove the cache files (otherwise the model will use the cache file to load the data which has the incorrect file paths)
30+
- could use to code in show_bbox.ipynb to see if data and bounding boxes has been loaded correctly
31+
- install yolo7
32+
```python
33+
!git clone https://github.com/WongKinYiu/yolov7
34+
%cd yolov7
35+
!pip install -r requirements.txt
36+
```
37+
- set up wandb
38+
```python
39+
!pip install wandb
40+
import wandb
41+
wandb.login()
42+
```
43+
- tune model: make sure colon.yaml has the correct file paths for data, also make sure --data, --cfg and --weights has the correct file paths
44+
45+
```python train.py --epochs 100 --device 0 --entity colon_coders --workers 8 --batch-size 32 --data /content/colon.yaml --img 512 512 --cfg /content/yolov7_training_config.yaml --weights '/content/yolov7_training.pt' --name yolov7-colon --hyp data/hyp.scratch.custom.yaml```
46+
- When training is finished, model output is saved under yolov7/runs/train
47+
48+
## Run on test data
49+
!python test.py --data /content/colon.yaml --img 512 --batch 32 --conf 0.001 --iou 0.65 --device 0 --weights runs/train/yolov7-colon2/weights/best.pt --name yolov7_colon_val
50+
51+
## Notes
52+
- The data location is specified in the config file colon.yaml
53+
- Training config is specified in yolov7_training_config.yaml
54+
55+
## Weights and Biases
56+
Weights and Biases is a very good tool to use to track training progress. YoloV7 uses this tool and it is very easy to set up
57+
- https://wandb.ai/site/research sign up for the free account
58+
- log into your account, go to top right, under your name select "user profile"
59+
- go to section "danger zone" and reveal your API code
60+
- this code is then used to log in to wandb when prompted
61+
- when you finish you can change the API or throw it away.
62+
- when training is in progress, go to WandB website, click on top left, you should see the project YOLO which will show the current training session

example_pipeline/show_bbox.ipynb

Lines changed: 99 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)