Skip to content

Beetle, Colorpicker, Scalebar detection scripts - #10

Open
SMRayeed wants to merge 12 commits into
mainfrom
detection
Open

Beetle, Colorpicker, Scalebar detection scripts #10
SMRayeed wants to merge 12 commits into
mainfrom
detection

Conversation

@SMRayeed

Copy link
Copy Markdown
Member

I have added the updated scripts for detecting individual beetles, colorpickers, and scalebars.

@egrace479

Copy link
Copy Markdown
Member

@SMRayeed, could you please add a requirements file and README describing the process with these scripts in the folder?

@AlysonEast
AlysonEast requested a review from egrace479 July 14, 2026 17:45

@egrace479 egrace479 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming you don't want to rename the folder, the references to it need to be updated.

Otherwise, this looks fine.

Comment thread detection-pipeline/README.md Outdated
Comment thread detection-pipeline/README.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new detection-pipeline/ package containing scripts and documentation for detecting beetles (Grounding DINO), colorpickers (Moondream), and scalebars (Moondream) from tray images, along with pinned-ish runtime dependencies.

Changes:

  • Introduces three new detection runner scripts for beetles, colorpickers, and scalebars.
  • Adds a pipeline README describing usage, SLURM chunking, inputs/outputs, and credential setup.
  • Adds a requirements.txt capturing the Python dependencies for the pipeline.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
detection-pipeline/requirements.txt Adds dependency list for running the detection scripts.
detection-pipeline/README.md Documents pipeline purpose, setup, credentials, and how to run each module.
detection-pipeline/detection_scalebar.py Implements Moondream-based scalebar detection with overlap/area filtering and resumable output.
detection-pipeline/detection_colorpicker.py Implements Moondream-based colorpicker detection with overlap reconciliation and CSV logging.
detection-pipeline/detection_beetles.py Implements Grounding DINO-based beetle detection, cropping, and results logging.
Comments suppressed due to low confidence (1)

detection-pipeline/README.md:74

  • The install instructions cd BioREPO-Processing point to a directory that doesn’t exist in this repo. Update it to the actual subdirectory so the quickstart works copy/paste.
cd BioREPO-Processing

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread detection-pipeline/README.md Outdated
Comment on lines +154 to +159
with open(csv_path, "w", newline="") as csvfile:
fieldnames = ["image_name", "plotted_image", "num_colorpickers", "colorpicker_coords", "verify"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(rows)

Comment on lines +78 to +86
iou = calculate_iou(all_detected_boxes[0], all_detected_boxes[1])
if iou >= 0.6:
merged_box = {
"x_min": int((all_detected_boxes[0]["x_min"] + all_detected_boxes[1]["x_min"]) / 2),
"y_min": int((all_detected_boxes[0]["y_min"] + all_detected_boxes[1]["y_min"]) / 2),
"x_max": int((all_detected_boxes[0]["x_max"] + all_detected_boxes[1]["x_max"]) / 2),
"y_max": int((all_detected_boxes[0]["y_max"] + all_detected_boxes[1]["y_max"]) / 2),
}
return [merged_box], False
Comment thread detection-pipeline/detection_beetles.py Outdated
self.processor = AutoProcessor.from_pretrained(model_id)
self.model = AutoModelForZeroShotObjectDetection.from_pretrained(model_id).to(self.device)

self.llava_processor, self.llava_model = self.setup_llava_model()
Comment thread detection-pipeline/detection_beetles.py Outdated
Comment on lines +207 to +209
image = Image.open(image_path)
image.verify()
image = Image.open(image_path).convert("RGB")
SMRayeed and others added 3 commits August 12, 2026 14:50
Co-authored-by: Elizabeth Campolongo <38985481+egrace479@users.noreply.github.com>
Co-authored-by: Elizabeth Campolongo <38985481+egrace479@users.noreply.github.com>
@SMRayeed

Copy link
Copy Markdown
Member Author

@egrace479 based on the remarks of the Copilot, I revisited the codebase and found the issues for the detection_beetles.py script and fixed. Also, updated the csv-logging part for colorpicker and scalebar as suggested.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Detection and resume logic can produce duplicate or stale results, misclassify outputs, and lose processing progress.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (7)

Previously missed (7) — in code that hasn't changed since the last review.

detection-pipeline/detection_beetles.py:215

  • Containment is only tested when the lower-scored current box is smaller than the kept box. If the higher-scored box is the smaller nested one, the later enclosing box is retained and the same beetle is counted twice. Determine the smaller box independently of score before applying the containment test.
    detection-pipeline/detection_beetles.py:329
  • Input discovery is recursive, but output filenames use only the basename. Two source subdirectories containing the same filename will share a crop directory and plotted filename, overwrite each other's artifacts, and produce indistinguishable CSV records. Preserve an encoded relative path or pass the input root into Detection to derive a unique name.
    detection-pipeline/detection_beetles.py:331
  • For a -and- image, this same image-level ground-truth count is assigned to both tray1 and tray2, so both per-tray CSV records have an incorrect actual value. Either provide per-half metadata or emit one aggregate record whose detected count sums both halves.
    detection-pipeline/detection_beetles.py:359
  • This reuses an existing crop directory without removing crops from an earlier run. If a rerun finds fewer beetles, higher-numbered old PNGs remain and downstream consumers see stale specimens that are absent from the new CSV. Clear generated crops for this tray before writing the new set.
    detection-pipeline/detection_beetles.py:412
  • Because image discovery includes every recursive image, placing --output-dir under --image-dir makes a rerun ingest previously generated crops and plotted trays as new inputs, causing output growth and incorrect records. Reject nested output directories or explicitly prune the output subtree.
    detection-pipeline/detection_colorpicker.py:125
  • If --output_dir is inside --image_dir, the recursive walk includes generated Plotted_Good/Plotted_Recheck images on subsequent runs. Those images receive new flattened names and trigger additional API calls and outputs each rerun. Reject this layout or prune the output subtree during discovery.
    detection-pipeline/detection_scalebar.py:130
  • If --output_dir is inside --image_dir, the recursive walk includes generated Plotted_Good/Plotted_Recheck images on subsequent runs. Those images receive new flattened names and trigger additional API calls and outputs each rerun. Reject this layout or prune the output subtree during discovery.
  • Files reviewed: 5/5 changed files
  • Comments generated: 8
  • Review effort level: Balanced

Comment on lines +276 to +278
if self.compute_containment_ratio(cand['box'], kept['box']) > 0.6:
duplicate = True
break
for detection in all_kept_boxes:
draw.rectangle(detection['box'], outline="red", width=4)

target_dir = recheck_dir if llava_flag else good_dir
Comment on lines +388 to +389
count_df = pd.DataFrame(count_records)
count_df.to_csv(csv_path, index=False)
Comment on lines +164 to +166
target_dir = recheck_dir if recheck_flag else good_dir
plotted_image_path = os.path.join(target_dir, base_name)
image.save(plotted_image_path)
Comment on lines +170 to +172
target_dir = recheck_dir if recheck_flag else good_dir
plotted_image_path = os.path.join(target_dir, base_name)
image.save(plotted_image_path)
Comment on lines +34 to +37
- **Zero-shot specimen detection** with `IDEA-Research/grounding-dino-base` and an
**adaptive confidence sweep** (0.30 → 0.10) that stops at the first threshold
yielding valid boxes — maximizing recall on faint specimens without flooding
dense trays with noise.
Comment on lines +157 to +160
> ℹ️ A LLaVA-Next model (`llava-v1.6-mistral-7b-hf`) is loaded for optional
> conditional-generation use but is **not invoked in the current detection loop**.
> If you don't need it, commenting out `setup_llava_model()` saves considerable
> GPU memory.
Comment on lines +229 to +230
└── plotted_trays/
└── <tray_name>.png # full tray with red bounding boxes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants