LiangLabUMB commited on
Commit
05f22d1
Β·
verified Β·
1 Parent(s): 122d705

Upload 4 files

Browse files
Files changed (2) hide show
  1. README.md +10 -6
  2. app.py +20 -20
README.md CHANGED
@@ -31,16 +31,20 @@ square, two taps per corner via the zoom).
31
  ### fast_counting
32
 
33
  1. Upload all four squares at once.
34
- 2. Tap the centre of the 4Γ—4 block in each of row 2. One tap places all four
35
  corners of that square.
36
  3. Press **Run**.
37
 
38
  The layout is deliberately spare, because the point is speed:
39
 
40
- 1. the four raw frames
41
- 2. the four squares β€” tap the block centre; tap again to re-place
42
- 3. per-square counts: total, live, dead, viability
43
- 4. the means, and the time taken β€” then the live-cell concentration
 
 
 
 
44
 
45
  No settings are exposed here. It uses the same defaults the comprehensive tab
46
  ships with (automatic minimum cell size, 1%/1% stereological exclusion,
@@ -67,7 +71,7 @@ instead of 1–5 sits on real printed lines just as well, so every
67
  line-agreement metric scores it perfectly. Nothing downstream can flag it.
68
 
69
  The tap fixes it because it puts the seed inside the intended block, which is
70
- the half-cell window the phase fit needs. **Still look at row 2 before running** β€”
71
  the tap makes the common case right, it does not make the check unnecessary.
72
 
73
  ### comprehensive_counting
 
31
  ### fast_counting
32
 
33
  1. Upload all four squares at once.
34
+ 2. Tap the centre of the 4Γ—4 block in each image. One tap places all four
35
  corners of that square.
36
  3. Press **Run**.
37
 
38
  The layout is deliberately spare, because the point is speed:
39
 
40
+ 1. the four squares, **two per row** so each is large enough to aim at β€”
41
+ tap the block centre; tap again to re-place
42
+ 2. per-square counts: total, live, dead, viability
43
+ 3. the means, and the time taken β€” then the live-cell concentration
44
+
45
+ There is no separate row of raw frames: until you tap it, each image *is* the
46
+ raw frame, so a second copy only cost the screen space that made the tap target
47
+ too small to judge.
48
 
49
  No settings are exposed here. It uses the same defaults the comprehensive tab
50
  ships with (automatic minimum cell size, 1%/1% stereological exclusion,
 
71
  line-agreement metric scores it perfectly. Nothing downstream can flag it.
72
 
73
  The tap fixes it because it puts the seed inside the intended block, which is
74
+ the half-cell window the phase fit needs. **Still look at each proposed square before running** β€”
75
  the tap makes the common case right, it does not make the check unnecessary.
76
 
77
  ### comprehensive_counting
app.py CHANGED
@@ -1876,7 +1876,7 @@ with gr.Blocks(title="CellposeCellCounter", theme=gr.themes.Soft()) as demo:
1876
  gr.Markdown(
1877
  "### Fast counting\n"
1878
  "Upload all four squares, tap the centre of the 4Γ—4 block in each "
1879
- "of row 2, then press **Run**.\n\n"
1880
  "The tap is what tells the detector which block you mean. It is not "
1881
  "optional: the centre of the frame is often not inside the intended "
1882
  "square, and a block placed one row off still sits on real rulings, "
@@ -1888,18 +1888,19 @@ with gr.Blocks(title="CellposeCellCounter", theme=gr.themes.Soft()) as demo:
1888
  height=95)
1889
  f_status = gr.Markdown("*Waiting for images.*")
1890
 
1891
- with gr.Row(): # row 1 -- raw frames
1892
- f_raw = [gr.Image(type="pil", label="Square %d" % (i + 1),
1893
- height=140, interactive=False,
1894
- show_download_button=False)
1895
- for i in range(4)]
1896
-
1897
- with gr.Row(): # row 2 -- detected square, tap centre to redo
1898
- f_sel = [gr.Image(type="pil",
1899
- label="Square %d β€” tap the block centre" % (i + 1),
1900
- height=165, interactive=True, format="jpeg",
1901
- show_download_button=False)
1902
- for i in range(4)]
 
1903
 
1904
  with gr.Row():
1905
  f_clear = gr.Button("βœ• Clear squares", size="sm")
@@ -1956,11 +1957,11 @@ with gr.Blocks(title="CellposeCellCounter", theme=gr.themes.Soft()) as demo:
1956
  return [(int(x), int(y)) for x, y in res["corners"]], res
1957
 
1958
  def f_on_upload(files):
1959
- raws, sels = [None] * 4, [None] * 4
1960
  fulls, prevs = [None] * 4, [None] * 4
1961
  scs, ptss = [1.0] * 4, [None] * 4
1962
  if not files:
1963
- return (*raws, *sels, *fulls, *prevs, *scs, *ptss,
1964
  "*Waiting for images.*")
1965
  paths = sorted((str(getattr(f, "name", f)) for f in files),
1966
  key=lambda p: os.path.basename(p).lower())
@@ -1973,22 +1974,21 @@ with gr.Blocks(title="CellposeCellCounter", theme=gr.themes.Soft()) as demo:
1973
  except Exception:
1974
  notes.append("%s unreadable" % os.path.basename(p))
1975
  continue
1976
- fulls[i] = raws[i] = im
1977
  prevs[i], scs[i] = make_preview(im)
1978
  sels[i] = prevs[i] # awaiting the user's tap
1979
  found += 1
1980
  msg = "**%d image%s loaded.** Now tap the centre of the 4Γ—4 block " \
1981
- "in each of row 2." % (found, "" if found == 1 else "s")
1982
  if notes:
1983
  msg += " \n⚠️ " + "; ".join(notes)
1984
  if len(paths) > 4:
1985
  msg += " \n*Ignored %d extra file(s).*" % (len(paths) - 4)
1986
- return (*raws, *sels, *fulls, *prevs, *scs, *ptss, msg)
1987
 
1988
  f_upload.change(
1989
  fn=f_on_upload, inputs=[f_upload],
1990
- outputs=[*f_raw, *f_sel, *f_full, *f_prev, *f_scale, *f_pts,
1991
- f_status])
1992
 
1993
  def _f_mk_reseed(idx):
1994
  def h(full, prev, scale, evt: gr.SelectData):
 
1876
  gr.Markdown(
1877
  "### Fast counting\n"
1878
  "Upload all four squares, tap the centre of the 4Γ—4 block in each "
1879
+ "image, then press **Run**.\n\n"
1880
  "The tap is what tells the detector which block you mean. It is not "
1881
  "optional: the centre of the frame is often not inside the intended "
1882
  "square, and a block placed one row off still sits on real rulings, "
 
1888
  height=95)
1889
  f_status = gr.Markdown("*Waiting for images.*")
1890
 
1891
+ # Two squares per row: at four across the disc renders too small to
1892
+ # see where the block centre is, which is the one thing the user has to
1893
+ # judge. There is no separate row of raw frames -- until it is tapped
1894
+ # each of these IS the raw frame, so a second copy only cost space.
1895
+ f_sel = []
1896
+ for _pair in range(2):
1897
+ with gr.Row():
1898
+ for _k in (2 * _pair, 2 * _pair + 1):
1899
+ f_sel.append(gr.Image(
1900
+ type="pil",
1901
+ label="Square %d β€” tap the block centre" % (_k + 1),
1902
+ height=460, interactive=True, format="jpeg",
1903
+ show_download_button=False))
1904
 
1905
  with gr.Row():
1906
  f_clear = gr.Button("βœ• Clear squares", size="sm")
 
1957
  return [(int(x), int(y)) for x, y in res["corners"]], res
1958
 
1959
  def f_on_upload(files):
1960
+ sels = [None] * 4
1961
  fulls, prevs = [None] * 4, [None] * 4
1962
  scs, ptss = [1.0] * 4, [None] * 4
1963
  if not files:
1964
+ return (*sels, *fulls, *prevs, *scs, *ptss,
1965
  "*Waiting for images.*")
1966
  paths = sorted((str(getattr(f, "name", f)) for f in files),
1967
  key=lambda p: os.path.basename(p).lower())
 
1974
  except Exception:
1975
  notes.append("%s unreadable" % os.path.basename(p))
1976
  continue
1977
+ fulls[i] = im
1978
  prevs[i], scs[i] = make_preview(im)
1979
  sels[i] = prevs[i] # awaiting the user's tap
1980
  found += 1
1981
  msg = "**%d image%s loaded.** Now tap the centre of the 4Γ—4 block " \
1982
+ "in each image below." % (found, "" if found == 1 else "s")
1983
  if notes:
1984
  msg += " \n⚠️ " + "; ".join(notes)
1985
  if len(paths) > 4:
1986
  msg += " \n*Ignored %d extra file(s).*" % (len(paths) - 4)
1987
+ return (*sels, *fulls, *prevs, *scs, *ptss, msg)
1988
 
1989
  f_upload.change(
1990
  fn=f_on_upload, inputs=[f_upload],
1991
+ outputs=[*f_sel, *f_full, *f_prev, *f_scale, *f_pts, f_status])
 
1992
 
1993
  def _f_mk_reseed(idx):
1994
  def h(full, prev, scale, evt: gr.SelectData):