kerojohan commited on
Commit
16c6411
·
verified ·
1 Parent(s): aa8f968

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +177 -7
README.md CHANGED
@@ -1,14 +1,184 @@
1
  ---
2
- title: Cavemark
3
- emoji: 🐢
4
- colorFrom: red
5
- colorTo: indigo
6
  sdk: gradio
7
- sdk_version: 6.11.0
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
- short_description: Automatic cave entrance detector for IR/NIR monochrome image
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: CaveMark
3
+ emoji: 🕳️
4
+ colorFrom: gray
5
+ colorTo: green
6
  sdk: gradio
7
+ sdk_version: 5.33.0
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
+ short_description: Automatic cave entrance detector for IR/NIR imagery
12
  ---
13
 
14
+ # CaveMark
15
+
16
+ Automatic cave entrance detector for IR/NIR monochrome imagery — no deep learning required.
17
+
18
+ CaveMark uses a classical computer vision pipeline (OpenCV + NumPy) to locate cave entrances in images captured by trail cameras, security cameras or NIR-equipped sensors in low-light or no-light conditions.
19
+
20
+ ---
21
+
22
+ ## How it works
23
+
24
+ ```
25
+ Load → Preprocess → Valid Region → IR Depth → Candidates → Score → Expand → GrabCut → Refine → Visualise
26
+ ```
27
+
28
+ 1. **Preprocess** — median denoise + large-blur background estimation + division normalisation (corrects uneven IR illumination)
29
+ 2. **Valid region** — horizontal illumination profile (80th percentile per column) builds a soft weight map that suppresses lateral dark borders caused by the camera's IR flash fall-off
30
+ 3. **IR physics depth** — per-pixel `darkness × local_uniformity` at three blur scales; cave voids absorb all IR and are spatially uniform, so they score high; textured rock/vegetation scores low even when dark
31
+ 4. **Candidate generation** — six complementary strategies:
32
+ - Multi-level thresholding (standard and heavy morphological bridging)
33
+ - Iterative seed-growth from the darkest pixels
34
+ - Otsu thresholding
35
+ - Adaptive threshold intersected with a dark base
36
+ - Valid-zone-only masking (lateral shadows masked before connected-component extraction)
37
+ 5. **Scoring** — multiplicative gates prevent wrong-size, wrong-shape, or textured blobs from winning regardless of darkness:
38
+ - Area gate: ideal 8 %–28 % of image; hard penalty below 2 % or above 45 %
39
+ - Solidity gate: very non-convex shapes penalised
40
+ - **Texture gate** *(new)*: high internal pixel std-dev penalises textured regions
41
+ - **Vertical gate** *(new)*: centroid in top 25 % of frame penalised
42
+ - Additive components: contrast vs. surround, darkness, enrichment of darkest pixels, distance-transform depth, IR physics depth, boundary gradient, valid-region alignment, aspect ratio, centroid position
43
+ 6. **Post-selection expansion** — grows the selected mask into connected dark pixels at a relaxed threshold; captures pit entrances where the initial candidate covers only the darkest core
44
+ 7. **GrabCut refinement** *(new)* — OpenCV graph-cut sharpens the boundary after expansion; eroded core = definite FG, dilated shell = probable FG, outer ring = probable BG
45
+ 8. **Refine** — morphological close + bordered flood-fill to fill interior holes + contour smoothing (wrap-around Gaussian, σ capped at 15)
46
+
47
+ ---
48
+
49
+ ## Requirements
50
+
51
+ ```
52
+ python >= 3.8
53
+ opencv-python
54
+ numpy
55
+ ```
56
+
57
+ Install with:
58
+
59
+ ```bash
60
+ pip install opencv-python numpy
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Usage
66
+
67
+ ### Single image
68
+
69
+ ```bash
70
+ python detect_cave.py input.jpg output.jpg
71
+ ```
72
+
73
+ ### Multiple images
74
+
75
+ ```bash
76
+ python detect_cave.py img1.png img2.png img3.png
77
+ ```
78
+
79
+ ### Batch mode
80
+
81
+ Run without arguments to process every `.jpg` / `.png` in the current directory (output files are excluded automatically):
82
+
83
+ ```bash
84
+ python detect_cave.py
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Output files
90
+
91
+ For each input image `NAME.png` four files are produced:
92
+
93
+ | File | Description |
94
+ |------|-------------|
95
+ | `NAME_result.png` | Original image with amber dilation ring, green overlay, contour and score label |
96
+ | `NAME_mask.png` | Binary mask (white = cave entrance) |
97
+ | `NAME_debug_valid.png` | Valid-region weight map + illumination profile curve |
98
+ | `NAME_debug_candidates.png` | All scored candidates with their scores; best candidate in white |
99
+
100
+ ---
101
+
102
+ ## Examples
103
+
104
+ Three test images are included in the repository root (`background.png`, `background2.png`, `background3.png`). Run the detector:
105
+
106
+ ```bash
107
+ python detect_cave.py
108
+ ```
109
+
110
+ ### background.png — horizontal slot entrance (1728 × 1296)
111
+
112
+ A cave entrance visible as a dark horizontal slot between a rock ceiling and a gravel floor. The image has strong IR flash fall-off on both lateral edges.
113
+
114
+ | Result | Mask |
115
+ |--------|------|
116
+ | ![result](examples/background_result.png) | ![mask](examples/background_mask.png) |
117
+
118
+ Score: **0.83** — area 7.7 %, contrast 0.61, IR depth 1.00
119
+
120
+ Valid-region weight map (lateral dark borders suppressed):
121
+
122
+ ![valid region](examples/background_debug_valid.png)
123
+
124
+ ---
125
+
126
+ ### background2.png — large vegetated entrance (1920 × 1080)
127
+
128
+ A wide cave entrance surrounded by vegetation. Uniform IR illumination — no lateral correction needed.
129
+
130
+ | Result | Mask |
131
+ |--------|------|
132
+ | ![result](examples/background2_result.png) | ![mask](examples/background2_mask.png) |
133
+
134
+ Score: **0.96** — area 16.8 %, contrast 0.92, IR depth 1.00
135
+
136
+ ---
137
+
138
+ ### background3.png — vertical pit entrance (1024 × 576)
139
+
140
+ A circular pit entrance viewed from above. The darkest core is only the deepest part; the full visible pit is recovered by post-selection expansion (8.9 % → 20.2 %) then refined by GrabCut.
141
+
142
+ | Result | Mask |
143
+ |--------|------|
144
+ | ![result](examples/background3_result.png) | ![mask](examples/background3_mask.png) |
145
+
146
+ Score: **1.00** — area 19.5 %, contrast 1.00, IR depth 1.00
147
+
148
+ Candidate scoring debug view:
149
+
150
+ ![candidates](examples/background3_debug_candidates.png)
151
+
152
+ ---
153
+
154
+ ## Scoring details
155
+
156
+ ```
157
+ final_score = additive × area_mult × solidity_mult × texture_mult × vert_gate × lateral_pen
158
+
159
+ additive =
160
+ 0.24 × contrast_score # brightness drop vs. surroundings (primary)
161
+ + 0.14 × dark_score # raw mean darkness
162
+ + 0.06 × enrichment_score # concentration of darkest 5 % of pixels
163
+ + 0.12 × depth_score # distance-transform depth (penalises narrow shadows)
164
+ + 0.10 × ir_depth_score # IR physics depth (darkness × local uniformity)
165
+ + 0.09 × gradient_score # edge sharpness at boundary
166
+ + 0.06 × valid_score # alignment with illuminated zone
167
+ + 0.03 × aspect_score # not absurdly thin
168
+ + 0.04 × position_score # mild centre preference
169
+ + 0.12 # base
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Limitations
175
+
176
+ - Assumes a single dominant cave entrance per image
177
+ - Struggles when the entrance is brighter than its surroundings (e.g. back-lit scenes)
178
+ - Very thin or fragmented entrances may score lower than large dark shadows; tweak `min_area` and threshold percentiles if needed
179
+
180
+ ---
181
+
182
+ ## License
183
+
184
+ MIT