Compare commits
No commits in common. "b744cb9e932ef3c79f01f0ee068bb7ce153d2f2c" and "4f9af8446cfdbcd8e81fdad89da57a6ceed5ec2c" have entirely different histories.
b744cb9e93
...
4f9af8446c
6 changed files with 7 additions and 53 deletions
51
README.md
51
README.md
|
@ -1,51 +0,0 @@
|
||||||
[MIT License](./LICENSE)
|
|
||||||
|
|
||||||
# Colony Counter
|
|
||||||
A simple Utility to count and measure bright spots on dark images 😸
|
|
||||||
|
|
||||||
## Features
|
|
||||||
- Image transformation results are cached and incremental.
|
|
||||||
- Provides an ugly user interface with intuitive key binds.
|
|
||||||
- Batch process/export image analysis results.
|
|
||||||
|
|
||||||
- Adjust colony recognition and filtering through a couple of simple sliders.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
- Remove false positives by clicking on them.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
- Install python (>=3.8 recommended... I made sure to explicitly use ordered dictionaries but just in case).
|
|
||||||
- Install dependencies in whichever way you prefer.
|
|
||||||
- Create the folders "in", "out" and "cache" (or run colonycounter.py).
|
|
||||||
- Adjust queue functions in source code to suit your needs (and read through [Caveats](#caveats)).
|
|
||||||
- Copy/Move your images into the "in" folder.
|
|
||||||
- Start the program by running the colonycounter.py file.
|
|
||||||
|
|
||||||
## Key Binds
|
|
||||||
| Key | Function |
|
|
||||||
|-----------------|----------------------------------------------------------------------------------------|
|
|
||||||
| q, left arrow | load previous image |
|
|
||||||
| w, right arrow | load next image |
|
|
||||||
| a | apply changes (always do this before switching images, otherwise changes will be lost) |
|
|
||||||
| r | reset changes that have not yet been applied |
|
|
||||||
| l | load saved settings from disk |
|
|
||||||
| s | save currently applied settings to disk |
|
|
||||||
| left mouse btn | add colony to list of ignored colonies |
|
|
||||||
| right mouse btn | remove colonies in the vicinity from ignore list |
|
|
||||||
| c | clear list of ignored colonies |
|
|
||||||
| e | batch process and export all images |
|
|
||||||
|
|
||||||
## Caveats
|
|
||||||
- The current processing queue expects 16bit gray scale images with the file extension .tif (tagged image file).
|
|
||||||
- watershed function does not work on 16 bit images... so there are some hard coded values to bring measurements back to 16bit brightness values
|
|
||||||
- this means a loss of resolution
|
|
||||||
- To get hour and culture type values the following folder structure is expected:
|
|
||||||
- "$DIRIN/OPTIONAL\_FOLDERS/$HOUR/$CULTURETYPE/image.tif"
|
|
||||||
- $HOUR = integer followed by the letter h
|
|
||||||
- $CULTURETYPE = whatever string identifies your culture type
|
|
||||||
- Code documentation is currently lacking
|
|
||||||
- Not all types are properly annotated
|
|
|
@ -122,6 +122,7 @@ def main():
|
||||||
[f.opqueue.__init__([normalize, to8bit, rollingball, wat]) for f in files]
|
[f.opqueue.__init__([normalize, to8bit, rollingball, wat]) for f in files]
|
||||||
[f.apply(dslice(f.opqueue,None,-1)) for f in files]
|
[f.apply(dslice(f.opqueue,None,-1)) for f in files]
|
||||||
|
|
||||||
|
# [(f.apply(f.opqueue), f.save(True, f.opqueue)) for f in files]
|
||||||
window.init(files)
|
window.init(files)
|
||||||
window.reset()
|
window.reset()
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -53,7 +53,7 @@ class FILE:
|
||||||
self.meta = pd.DataFrame(None if self.data[1]["data"][1:] == [] else self.data[1]["data"][1:], columns=self.data[1]["data"][0])
|
self.meta = pd.DataFrame(None if self.data[1]["data"][1:] == [] else self.data[1]["data"][1:], columns=self.data[1]["data"][0])
|
||||||
self.meta.insert(loc=0, column="Label", value="".join([self.fname, self.fext]))
|
self.meta.insert(loc=0, column="Label", value="".join([self.fname, self.fext]))
|
||||||
spath = self.path.split(path.sep)
|
spath = self.path.split(path.sep)
|
||||||
if len(spath) > 2 and spath[-2][:-1].isdigit():
|
if len(spath) > 2 and spath[-1] in ["BFP", "YFP"] and spath[-2][:-1].isdigit():
|
||||||
hour, culture = self.path.split(path.sep)[-2:]
|
hour, culture = self.path.split(path.sep)[-2:]
|
||||||
hour = int(hour[:-1])
|
hour = int(hour[:-1])
|
||||||
else:
|
else:
|
||||||
|
@ -82,7 +82,11 @@ class FILE:
|
||||||
if self.outlines is not None:
|
if self.outlines is not None:
|
||||||
imwrite(path.join(DIROUT, self.path, f"{self.fname}.outlines.jpg"), self.outlines)
|
imwrite(path.join(DIROUT, self.path, f"{self.fname}.outlines.jpg"), self.outlines)
|
||||||
if self.meta is not None:
|
if self.meta is not None:
|
||||||
|
print(path.join(DIROUT, self.path, f"{self.fname}.csv"))
|
||||||
self.meta.to_csv(path.join(DIROUT, self.path, f"{self.fname}.csv"), index=False)
|
self.meta.to_csv(path.join(DIROUT, self.path, f"{self.fname}.csv"), index=False)
|
||||||
|
# [l.insert(1, self.getName(False, {})) for l in self.meta["data"][1:]]
|
||||||
|
# with open(path.join(DIROUT, self.path, f"{self.fname}.csv"), "w") as f:
|
||||||
|
# [f.write(",".join([str(e) for e in l]) + "\n") for l in self.meta["data"]]
|
||||||
else:
|
else:
|
||||||
if not path.exists(path.join(DIRCACHE, self.path)):
|
if not path.exists(path.join(DIRCACHE, self.path)):
|
||||||
makedirs(path.join(DIRCACHE, self.path))
|
makedirs(path.join(DIRCACHE, self.path))
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 174 KiB |
Binary file not shown.
Before Width: | Height: | Size: 130 KiB |
|
@ -1,5 +1,5 @@
|
||||||
numpy
|
numpy
|
||||||
opencv-python == 4.3.0
|
opencv-python == 4.3.0
|
||||||
pythreshold
|
pythreshold
|
||||||
scikit-image >= 0.18.1
|
scikit-image
|
||||||
scipy
|
scipy
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue