pr28416 commited on
Commit
3a4d042
Β·
1 Parent(s): 7ad39b2

Fix major scaling bug: use same downsampled image for viewer and cropper

Browse files
Files changed (1) hide show
  1. streamlit_app.py +42 -23
streamlit_app.py CHANGED
@@ -326,12 +326,17 @@ if uploaded is not None:
326
  )
327
  current_path = paths.get(sel or "", None)
328
  if current_path:
329
- pil_img = Image.open(current_path).convert("L")
 
 
 
330
  # Get original image dimensions for physical scaling calculation
331
- orig_h, orig_w = (
332
- pil_img.size[1],
333
- pil_img.size[0],
334
- ) # PIL uses (W, H) format
 
 
335
 
336
  slice_img = st_cropper(pil_img, aspect_ratio=None, box_color="#00FF00")
337
  snp = np.array(slice_img)
@@ -346,9 +351,13 @@ if uploaded is not None:
346
  orig_width_um = s.get("width_um", 1705.6)
347
  orig_height_um = s.get("height_um", 1706.81)
348
 
349
- # Calculate pixel size from ORIGINAL image
350
- px_size_x_um = orig_width_um / orig_w
351
- px_size_y_um = orig_height_um / orig_h
 
 
 
 
352
 
353
  # Handle downscaling if slice is too large
354
  actual_h, actual_w = h, w
@@ -359,22 +368,27 @@ if uploaded is not None:
359
  snp, (actual_h, actual_w), preserve_range=True
360
  ).astype(np.uint8)
361
 
362
- # Calculate effective physical dimensions that maintain original pixel size
363
- # This tricks the function into using the correct pixel-to-micron ratio
364
- slice_width_um = actual_w * px_size_x_um
365
- slice_height_um = actual_h * px_size_y_um
366
 
367
  roi_path = os.path.join(prev_dir, "slice.png")
368
  iio.imwrite(roi_path, snp)
369
 
370
- # Calculate what the minimum radius should be in pixels for debugging
371
  min_diam_um = s.get("min_diam_um", 10.0)
372
- avg_px_size_um = np.sqrt(px_size_x_um * px_size_y_um)
373
  expected_min_radius_px = (min_diam_um / avg_px_size_um) / 2.0
374
-
375
- # Show slice info
 
 
 
 
 
 
376
  st.caption(
377
- f"πŸ“ Slice: {actual_w}Γ—{actual_h} px | Pixel size: {px_size_x_um:.3f}Γ—{px_size_y_um:.3f} Β΅m/px"
378
  )
379
  st.caption(
380
  f"πŸ” Debug: {min_diam_um}Β΅m min diameter β†’ expected ~{expected_min_radius_px:.1f}px min radius"
@@ -401,14 +415,20 @@ if uploaded is not None:
401
 
402
  with st.spinner("Detecting on slice..."):
403
  t0 = time.time()
404
-
405
  # Debug: show what we're passing to the function
406
- st.write(f"πŸ”§ Debug: Passing width_um={slice_width_um:.2f}, height_um={slice_height_um:.2f}")
407
- st.write(f"πŸ”§ Debug: Slice is {actual_w}Γ—{actual_h} px, downsample={downsample}")
 
 
 
 
408
  calc_px_size_x = slice_width_um / actual_w
409
  calc_px_size_y = slice_height_um / actual_h
410
- st.write(f"πŸ”§ Debug: Function will calculate px_size: {calc_px_size_x:.4f}Γ—{calc_px_size_y:.4f} Β΅m/px")
411
-
 
 
412
  slice_count, _ = _count_dots_on_preview(
413
  preview_png_path=roi_path,
414
  min_sigma=1.5,
@@ -630,4 +650,3 @@ if uploaded is not None:
630
 
631
  else:
632
  st.info("Upload a .tif to begin.")
633
-
 
326
  )
327
  current_path = paths.get(sel or "", None)
328
  if current_path:
329
+ # Load the same downsampled image that's shown in the viewer
330
+ img_array = load_preview(current_path)
331
+ pil_img = Image.fromarray(img_array.astype(np.uint8)).convert("L")
332
+
333
  # Get original image dimensions for physical scaling calculation
334
+ orig_img = Image.open(current_path).convert("L")
335
+ orig_h, orig_w = orig_img.size[1], orig_img.size[0] # PIL uses (W, H) format
336
+
337
+ # Get the downsampling scale factor
338
+ preview_h, preview_w = pil_img.size[1], pil_img.size[0]
339
+ scale_factor = orig_w / preview_w # How much the preview is downsampled
340
 
341
  slice_img = st_cropper(pil_img, aspect_ratio=None, box_color="#00FF00")
342
  snp = np.array(slice_img)
 
351
  orig_width_um = s.get("width_um", 1705.6)
352
  orig_height_um = s.get("height_um", 1706.81)
353
 
354
+ # Calculate pixel size from ORIGINAL image (this is the true pixel size)
355
+ true_px_size_x_um = orig_width_um / orig_w
356
+ true_px_size_y_um = orig_height_um / orig_h
357
+
358
+ # Crop dimensions are from the downsampled preview, so scale them up to original resolution
359
+ orig_crop_w = w * scale_factor
360
+ orig_crop_h = h * scale_factor
361
 
362
  # Handle downscaling if slice is too large
363
  actual_h, actual_w = h, w
 
368
  snp, (actual_h, actual_w), preserve_range=True
369
  ).astype(np.uint8)
370
 
371
+ # Calculate effective physical dimensions using the TRUE pixel size from original image
372
+ slice_width_um = actual_w * true_px_size_x_um
373
+ slice_height_um = actual_h * true_px_size_y_um
 
374
 
375
  roi_path = os.path.join(prev_dir, "slice.png")
376
  iio.imwrite(roi_path, snp)
377
 
378
+ # Calculate what the minimum radius should be in pixels for debugging
379
  min_diam_um = s.get("min_diam_um", 10.0)
380
+ avg_px_size_um = np.sqrt(true_px_size_x_um * true_px_size_y_um)
381
  expected_min_radius_px = (min_diam_um / avg_px_size_um) / 2.0
382
+
383
+ # Show slice info with proper debugging
384
+ st.caption(
385
+ f"πŸ“ Original: {orig_w}Γ—{orig_h} px β†’ Preview: {preview_w}Γ—{preview_h} px (scale: {scale_factor:.1f}x)"
386
+ )
387
+ st.caption(
388
+ f"πŸ“ Slice: {actual_w}Γ—{actual_h} px β†’ {orig_crop_w:.0f}Γ—{orig_crop_h:.0f} px in original"
389
+ )
390
  st.caption(
391
+ f"πŸ“ True pixel size: {true_px_size_x_um:.4f}Γ—{true_px_size_y_um:.4f} Β΅m/px"
392
  )
393
  st.caption(
394
  f"πŸ” Debug: {min_diam_um}Β΅m min diameter β†’ expected ~{expected_min_radius_px:.1f}px min radius"
 
415
 
416
  with st.spinner("Detecting on slice..."):
417
  t0 = time.time()
418
+
419
  # Debug: show what we're passing to the function
420
+ st.write(
421
+ f"πŸ”§ Debug: Passing width_um={slice_width_um:.2f}, height_um={slice_height_um:.2f}"
422
+ )
423
+ st.write(
424
+ f"πŸ”§ Debug: Slice is {actual_w}Γ—{actual_h} px, downsample={downsample}"
425
+ )
426
  calc_px_size_x = slice_width_um / actual_w
427
  calc_px_size_y = slice_height_um / actual_h
428
+ st.write(
429
+ f"πŸ”§ Debug: Function will calculate px_size: {calc_px_size_x:.4f}Γ—{calc_px_size_y:.4f} Β΅m/px"
430
+ )
431
+
432
  slice_count, _ = _count_dots_on_preview(
433
  preview_png_path=roi_path,
434
  min_sigma=1.5,
 
650
 
651
  else:
652
  st.info("Upload a .tif to begin.")