Skip to content

Commit c3e7b53

Browse files
committed
add readme and make project ready to use
1 parent d8027b7 commit c3e7b53

File tree

4 files changed

+160
-39
lines changed

4 files changed

+160
-39
lines changed

README.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# ColorBoxDetector
2+
3+
Color-based box (and corner/parallelogram) detection utilities with multiple algorithm versions and Raspberry Pi deployment support.
4+
5+
## Features
6+
- Multiple detection pipelines (V1.2 HSV + morphology, V3 channel subtraction).
7+
- Configurable HSV color ranges via interactive ROI tools.
8+
- Support for detecting 3 colored reference boxes + a yellow locator box.
9+
- Parallelogram / corner arrangement utilities.
10+
- Single-file deploy script for Raspberry Pi: [raspi_functions.py](raspi_functions.py).
11+
- Modular refactored detector: [color_detector_refactored.py](color_detector_refactored.py).
12+
13+
## Project Layout (Key Files)
14+
- Core (versioned) scripts:
15+
- [cbd_v1.2.py](cbd_v1.2.py) (HSV + distance transform)
16+
- [cbd_v2.py](cbd_v2.py)
17+
- [cbd_v3.py](cbd_v3.py) (newer experiments)
18+
- [color_detector_refactored.py](color_detector_refactored.py)
19+
- [raspi_functions.py](raspi_functions.py) (all-in-one)
20+
- Tools (interactive config generation):
21+
- [tools/create_config.py](tools/create_config.py) (main object colors)
22+
- [tools/create_boxes_config.py](tools/create_boxes_config.py) (4 small boxes set)
23+
- [tools/new_obj.py](tools/new_obj.py) (extend existing config)
24+
- Parallelogram helpers:
25+
- [parallelogram_detector_dual_method.py](parallelogram_detector_dual_method.py)
26+
- [parallelogram_detector_v1_2.py](parallelogram_detector_v1_2.py)
27+
28+
## Configuration
29+
JSON configs are ignored by Git (`.gitignore` contains *.json) so generate them locally.
30+
31+
Main: `config.json`
32+
Secondary (4-box mode): `config_boxes.json`
33+
34+
Both contain:
35+
```
36+
{
37+
"color_ranges": {
38+
"red": [ [ [low_H,low_S,low_V], [high_H,high_S,high_V] ], ... ],
39+
"green": [...],
40+
"blue": [...],
41+
"yellow": [...]
42+
},
43+
"big_box_crop": [x, y, w, h] (optional)
44+
"boxes_crop": [x, y, w, h] (in config_boxes.json)
45+
}
46+
```
47+
48+
Loaded via:
49+
- [`load_config`](cbd_v1.2.py)
50+
- [`load_config`](raspi_functions.py) (two variants: one for `config.json` near line ~227 and one for `config_boxes.json` near line ~377)
51+
- [`load_config`](color_detector_refactored.py)
52+
53+
If missing, some scripts fall back to hard‑coded defaults.
54+
55+
## Generating Configs
56+
Interactive (requires GUI display):
57+
```
58+
python tools/create_config.py # builds config.json
59+
python tools/create_boxes_config.py # builds config_boxes.json
60+
python tools/new_obj.py # append/merge new object-specific ranges
61+
```
62+
Follow on-screen ROI selections. Color ranges are auto-generated per ROI.
63+
64+
## Detection Pipelines
65+
66+
### V1.2 (HSV + Distance Transform)
67+
Implemented in:
68+
- [`preprocess_v1_2_method`](raspi_functions.py)
69+
- Supporting utilities: [`detect_contours_and_centroids`](raspi_functions.py)
70+
71+
Flow:
72+
1. HSV threshold per color range.
73+
2. Morphological cleanup.
74+
3. Distance transform to tighten mask.
75+
4. Contour filtering (area + aspect ratio).
76+
5. Representative centroid per channel.
77+
78+
### V3 (Channel Isolation & Subtraction)
79+
Implemented in:
80+
- [`preprocess_v3`](color_detector_refactored.py)
81+
- Inline helper: `isolate_and_subtract_channel` inside that function and standalone in [raspi_functions.py](raspi_functions.py) (top section).
82+
83+
Flow:
84+
1. Split BGR.
85+
2. For target channel c: subtract other channels → enhances dominance.
86+
3. Otsu threshold.
87+
4. Morph open + close.
88+
5. Contours extracted from cleaned mask.
89+
90+
### Corner / Arrangement Logic
91+
Corner arrangement utilities (e.g., identifying relative positions) live around mid/lower sections of [raspi_functions.py](raspi_functions.py) (see functions near detection of yellow + ordering, e.g., `identify_corner_arrangement`).
92+
93+
## Raspberry Pi Deployment
94+
Use [raspi_functions.py](raspi_functions.py) for minimal dependency deployment (aggregation of all logic). Copy only needed image + config assets beside the script.
95+
## Usage
96+
1. Create a configuration file (`config.json`) in the project root. Use the interactive tool:
97+
```
98+
python tools/create_config.py
99+
```
100+
(Place the generated `config.json` next to the scripts.)
101+
102+
2. HSV-only detection (simple pipeline):
103+
```
104+
python cbd_v3.py
105+
```
106+
This uses HSV ranges from `config.json`.
107+
108+
3. Channel isolation + HSV (combined method):
109+
```
110+
python color_detector_refactored.py
111+
```
112+
Provide an image path; the script loads `config.json` automatically.
113+
114+
Notes:
115+
- Regenerate `config.json` if lighting changes.
116+
- Keep `config.json` in the same directory as the scripts.
117+
118+
## Color Range Tuning Tips
119+
- Start with evenly lit images.
120+
- Avoid over-tight ranges; include slight illumination variance.
121+
- Re-generate after lighting/environment changes.
122+
- Yellow often needs separate (smaller) morphology kernel (`MORPH_KERNEL_YELLOW` in [raspi_functions.py](raspi_functions.py)).
123+
124+
## Extending
125+
1. Add new color: update generation tool to prompt for it.
126+
2. Add algorithm variant: create `preprocess_vX` function and mirror usage pattern.
127+
3. Unify duplicate `load_config` functions if maintenance becomes difficult.
128+
129+
## Dependencies
130+
Install (typical):
131+
```
132+
pip install opencv-python numpy
133+
```
134+
(If running on Raspberry Pi, use `opencv-contrib-python`)
135+
136+
## Performance Notes
137+
- Reduce resolution before processing for speed.
138+
- Tune morphology kernel sizes (`MORPH_KERNEL_COLOR`, `MORPH_KERNEL_YELLOW`) per camera.
139+
- Cache configs; avoid reloading each frame.
140+
141+
## Troubleshooting
142+
- Blank masks: verify HSV range order and lighting.
143+
- Wrong color dominance in V3: ensure channel subtraction not saturating (inspect intermediate single-channel result).
144+
- No contours: relax min area thresholds in functions like [`detect_contours_and_centroids`](raspi_functions.py).

cbd_v3.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# Channel isolation method with contour merging
22

3-
import glob
43
import subprocess
54
import cv2
65
import numpy as np
@@ -200,17 +199,10 @@ def detect_and_extract_contours(img_path):
200199
print("Nothing detected, defaulting to blue")
201200
return "b"
202201

203-
def image_job():
204-
# rpicam-still --output ./image.png --timeout 200 --width 1920 --height 1080 --rotation 180
205-
subprocess.run(["rpicam-still", "--output", img_path, "--timeout", "200", "--width", "1920", "--height", "1080", "--rotation", "180"])
206-
return detect_and_extract_contours(img_path)
207-
208202

209203
if __name__ == '__main__':
210-
for i in glob.glob("C:/Users/efeca/Desktop/imgs/*.png"):
211-
print(i)
212-
print(detect_and_extract_contours(i))
213-
cv2.waitKey(0)
214-
cv2.destroyAllWindows()
215-
216-
# print(detect_and_extract_contours("C:/Users/efeca/Desktop/imgs/i6.png"))
204+
image_path = input("Enter the path to the image file: ").strip()
205+
print(detect_and_extract_contours(image_path))
206+
cv2.waitKey(0)
207+
cv2.destroyAllWindows()
208+

color_detector_refactored.py

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -509,32 +509,18 @@ def image_job(img_path="./image.png"):
509509
return final_result
510510

511511

512-
513-
# ===================== LEGACY FUNCTION COMPATIBILITY =====================
514-
515-
def get_box_color(img_path):
516-
"""Legacy function for backward compatibility."""
517-
return detect_color_v1_2(img_path)
518-
519-
520-
def detect_and_extract_contours(img_path):
521-
"""Legacy function for backward compatibility."""
522-
return detect_color_v3(img_path)
523-
524-
525512
def main():
526-
import glob
527-
for img_path in glob.glob(r"C:\Users\efeca\Desktop\imgs\*.png"):
528-
print(f"Processing {img_path}")
529-
530-
v1_2 = detect_color_v1_2(img_path)
531-
v3 = detect_color_v3(img_path)
532-
533-
print(f"v1.2 detected: {v1_2}, v3 detected: {v3}")
534-
535-
# Use decision logic to combine results
536-
final_result = decider(v1_2, v3)
537-
print(f"Final detected color: {final_result}")
513+
img_path = input("Enter the path to the image file: ").strip()
514+
print(f"Processing {img_path}")
515+
516+
v1_2 = detect_color_v1_2(img_path)
517+
v3 = detect_color_v3(img_path)
518+
519+
print(f"v1.2 detected: {v1_2}, v3 detected: {v3}")
520+
521+
# Use decision logic to combine results
522+
final_result = decider(v1_2, v3)
523+
print(f"Final detected color: {final_result}")
538524

539525
if __name__ == '__main__':
540526
main()

parallelogram_detector_v1_2.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,6 @@ def main():
288288
cv2.destroyAllWindows()
289289
except Exception as e:
290290
print(f"Error: {e}")
291-
break
292291

293292
if __name__ == '__main__':
294293
main()

0 commit comments

Comments
 (0)