Skip to content

Commit eea067b

Browse files
authored
Merge pull request #5 from HolyLab/teh/docs
Add GUI, XLSX support, and documentation
2 parents eec4d64 + 305d75a commit eea067b

File tree

15 files changed

+563
-98
lines changed

15 files changed

+563
-98
lines changed

.github/workflows/CI.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,19 @@ jobs:
6969
Pkg.develop(PackageSpec(path=pwd()))
7070
Pkg.instantiate()
7171
- uses: julia-actions/julia-buildpkg@v1
72+
with:
73+
prefix: xvfb-run
7274
- uses: julia-actions/julia-docdeploy@v1
75+
with:
76+
prefix: xvfb-run
7377
env:
7478
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
7579
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
7680
- name: Run doctests
77-
shell: julia --project=docs --color=yes {0}
81+
shell: xvfb-run julia --project=docs --color=yes {0}
7882
run: |
7983
using Documenter: DocMeta, doctest
8084
using CounterMarking
8185
DocMeta.setdocmeta!(CounterMarking, :DocTestSetup, :(using CounterMarking); recursive=true)
8286
doctest(CounterMarking)
87+

Project.toml

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,34 @@ version = "1.0.0"
55

66
[deps]
77
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
8+
Glob = "c27321d9-0574-5035-807b-f59d2c89b15c"
9+
Gtk4 = "9db2cae5-386f-4011-9d63-a5602296539b"
10+
GtkObservables = "8710efd8-4ad6-11eb-33ea-2d5ceb25a41c"
811
ImageCore = "a09fc81d-aa75-5fe9-8630-4744c3626534"
912
ImageIO = "82e4d734-157c-48bb-816b-45c225c6df19"
1013
ImageMorphology = "787d08f9-d448-5407-9aad-5290dd7ab264"
1114
ImageSegmentation = "80713f31-8817-5129-9cf8-209ff8fb23e1"
12-
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
13-
14-
[weakdeps]
1515
ImageView = "86fae568-95e7-573e-a6b2-d8a6b900c9ef"
16-
17-
[extensions]
18-
CounterMarkingImageViewExt = "ImageView"
16+
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
17+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
18+
XLSX = "fdbf4ff8-1666-58a4-91e7-1b58723a45e0"
1919

2020
[compat]
2121
FileIO = "1"
22+
Glob = "1"
23+
Gtk4 = "0.7"
24+
GtkObservables = "2"
2225
ImageCore = "0.10"
2326
ImageIO = "0.6"
2427
ImageMorphology = "0.4"
2528
ImageSegmentation = "1.9"
2629
ImageView = "0.12"
30+
JLD2 = "0.5"
31+
XLSX = "0.10"
2732
julia = "1.10"
2833

2934
[extras]
30-
ImageView = "86fae568-95e7-573e-a6b2-d8a6b900c9ef"
3135
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
3236

3337
[targets]
34-
test = ["ImageView", "Test"]
38+
test = ["Test"]

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ makedocs(;
1414
),
1515
pages=[
1616
"Home" => "index.md",
17+
"Reference" => "reference.md",
1718
],
1819
)
1920

docs/src/assets/Picture.png

2.53 MB
Loading

docs/src/assets/gui.png

824 KB
Loading

docs/src/index.md

Lines changed: 209 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,216 @@ CurrentModule = CounterMarking
44

55
# CounterMarking
66

7-
Documentation for [CounterMarking](https://github.com/HolyLab/CounterMarking.jl).
7+
[CounterMarking](https://github.com/HolyLab/CounterMarking.jl) analyzes experiments on [scent-marking in mice](https://www.sciencedirect.com/science/article/pii/S0003347287800167),
8+
specifically images of urine countermarking visualized by the [ninhydrin reaction](https://pubs.acs.org/doi/full/10.1021/jf030490p):
9+
10+
![A ninhydrin-stained image](assets/Picture.png)
11+
12+
The yellow spot corresponds to a stimulus provided by the experimenter, and the small light-blue spots are deposited marks.
13+
14+
Tips on image quality:
15+
16+
- Put the stimulus near one of the four corners
17+
- Ensure lighting is fairly uniform
18+
- Try to ensure the entire image is of the filter paper, and that there aren't any black edges to the image (see lower left corner in the example above)
19+
- Make sure that any extraneous marks (e.g., the black writing in the image above) are of a very different color from scent marks.
20+
21+
## Tutorial
22+
23+
### Installation and setup (one time setup)
24+
25+
There are several ways to organize your data, but one recommended approach is to have a parent "project" folder, and then store images collected on different days in subfolders named by date:
26+
27+
```sh
28+
MyCounterMarkingFolder
29+
Project.toml
30+
2025-03-15/
31+
2025-03-17/
32+
...
33+
```
34+
35+
We'll create the `Project.toml` for running the analysis. From the command line within `MyCounterMarkingFolder`, the steps below will:
36+
37+
- start Julia
38+
- get into `pkg>` mode
39+
- activate a new project
40+
- install the packages you'll use
41+
42+
Here are the steps, starting from the OS command line:
43+
44+
```
45+
MyCounterMarkingFolder$ julia
46+
<banner shows up>
47+
48+
julia> ] # this enters pkg mode
49+
pkg> activate .
50+
51+
pkg> add CounterMarking ImageView Glob FileIO ImageIO
52+
```
53+
54+
This should create the `Project.toml` file in `MyCounterMarkingFolder`. If this succeeds, you shouldn't have to do this again.
55+
56+
57+
From this point on, start Julia like this:
58+
59+
```sh
60+
MyCounterMarkingFolder$ julia --project
61+
```
62+
63+
and it will automatically "activate" this project and you'll have access to all those packages.
64+
65+
!!! tip
66+
If you ever need to update the packages (e.g., to get any improvements
67+
to `CounterMarking.jl`), you can update packages with `pkg> up`. See the
68+
[Pkg documentation](https://pkgdocs.julialang.org/v1/getting-started/) for
69+
more information.
70+
71+
## Processing with the GUI
72+
73+
From within `MyCounterMarkingFolder` created above, start Julia like this:
74+
75+
```sh
76+
MyCounterMarkingFolder$ julia --project
77+
```
78+
79+
Then load the packages:
80+
81+
```
82+
julia> using CounterMarking, Glob
83+
```
84+
85+
Then specify the images you want to process:
86+
87+
```
88+
julia> gui("results_file_name", glob"Picture*.png")
89+
```
90+
91+
This will save your results to `"results_file_name.xlsx"` and `"results_file_name.jld2"`.
92+
The syntax `glob"pattern"` means "all files that match this pattern", where `*` means "one or more characters".
93+
See [this tutorial](https://www.malikbrowne.com/blog/a-beginners-guide-glob-patterns/) for more information about glob syntax.
94+
Alternatively, you can supply a list of files:
95+
96+
```
97+
julia> gui("results_file_name", ["PictureA.png", "mouse7.png"])
98+
```
99+
100+
However you launch it, you should see something like this:
101+
102+
![GUI](assets/gui.png)
103+
104+
On the top is the raw image. On the bottom is the segmented image; you should visually compare the two to check whether you're pleased with the quality of the segmentation.
105+
(If not, click "Skip" to omit that file from analysis.)
106+
107+
If you like the segmentation, your tasks are:
108+
- click on all the checkboxes with colors that correspond to urine spots. You'll notice that the stimulus spot is pre-clicked (you can correct its choice if it didn't pick correctly). Most of the time there will be only one you need to check, but you can click more than one.
109+
In this example image, all the urine spots are marked red, so you'd check the box that has the red border. Leave the stimulus spot checked, too.
110+
- click "Done & Next" to advance to the next image in the sequence
111+
112+
After it finishes cycling through all the images, it will save your results and close the window.
113+
114+
## Processing manually
115+
116+
### Step 1: start Julia with the right project
117+
118+
From within `MyCounterMarkingFolder` created above, start Julia like this:
119+
120+
```sh
121+
MyCounterMarkingFolder$ julia --project
122+
```
123+
124+
### Step 2: load the packages you'll need
125+
126+
From inside Julia, load the packages:
127+
128+
```
129+
julia> using CounterMarking, ImageView, FileIO
130+
```
131+
132+
CounterMarking is this package, used to perform and organize the analysis.
133+
[ImageView](https://github.com/JuliaImages/ImageView.jl) is an image display tool.
134+
[FileIO](https://github.com/JuliaIO/FileIO.jl) loads many different file formats, including images.
135+
136+
### Step 3: load a test image
137+
138+
If you want to use an image in one of the subfolders, use something like
139+
140+
```
141+
julia> img = load("2025-03-15/picture1.png");
142+
```
143+
144+
You'll need to replace the material inside quotes with the actual path and filename of your image.
145+
146+
Alternately, if you want to use the test image that comes with CounterMarking.jl, do the following:
147+
148+
```
149+
julia> img = load(joinpath(pkgdir(CounterMarking), "docs", "src", "assets", "Picture.png"));
150+
```
151+
152+
### Step 4: visualize the image
153+
154+
It's usually a good idea to visually check that what you're working with makes sense:
155+
156+
```
157+
julia> dct = imshow(img);
158+
```
159+
160+
Note that as you move your mouse cursor over the image, a little text box in the lower left updates with the position and information about the color of the pixel under your cursor.
161+
That can occasionally be handy, especially for checking locations of spots.
162+
163+
If all looks as expected, you can close the window.
164+
165+
### Step 5: segment the image
166+
167+
We'll split this image into different regions:
168+
169+
```
170+
julia> seg = segment_image(img)
171+
Pruning segments smaller than 50 pixels
172+
Segmented Image with:
173+
labels map: 1220×2441 Matrix{Int64}
174+
number of labels: 153
175+
176+
julia> dct = randshow(img, seg);
177+
```
178+
179+
After the second command, [`randshow`](@ref), you'll see two images: the original at the top, and the "segmented" image below. This displays the different segments (regions) using a randomly-chosen color, which can be handy for checking how well the analysis did in identifying separate spots. You can alternatively use [`meanshow`](@ref) to show each segment using the average color of all pixels in that segment.
180+
181+
If you Ctrl-click and drag on the image, you'll zoom in on both images. This can be handy for inspecting fine details. Ctrl-double-click takes you back to the full view.
182+
183+
!!! tip
184+
If you don't like how [`segment_image`](@ref) performed, read its documentation to learn about some of the options you have for controlling it.
185+
186+
### Step 6: save the spots to an Excel file
187+
188+
The columns marked "raw" correspond to pixel locations in the original image; the columns marked "UL" come from flipping the image to place the stimulus spot in the Upper Left of the image.
189+
This way of "standardizing" the location makes certain analyses easier.
190+
191+
```
192+
julia> writexlsx("mydata.xlsx", seg)
193+
```
194+
195+
Optionally specify a full directory path, e.g.,
196+
197+
```
198+
julia> writexlsx(raw"C:\Users\me\somefolder\mydata.xlsx", seg)
199+
```
200+
201+
(You don't need `raw` on Linux or Mac, but it is helpful on Windows.)
202+
203+
### Step 7: process a whole directory of images at once
204+
205+
If you have many images in one folder, you can process them all using a single command:
206+
207+
```
208+
julia> process_images("2025-03-15/results.xlsx", "2025-03-15/*.png")
209+
```
210+
211+
### Step 8: create a "density map" of marks across multiple images
212+
213+
If you have many images collected under the same conditions (e.g., with different subject animals but the same stimuli), you can effectively overlay the entire collection of images:
8214

9-
```@index
10215
```
216+
julia> dmap = density_map("2025-03-15/maleU-*.png");
11217
12-
```@autodocs
13-
Modules = [CounterMarking]
218+
julia> dct = imshow(dmap);
14219
```

docs/src/reference.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Reference
2+
3+
```@index
4+
```
5+
6+
```@autodocs
7+
Modules = [CounterMarking]
8+
```

ext/CounterMarkingImageViewExt.jl

Lines changed: 0 additions & 40 deletions
This file was deleted.

src/CounterMarking.jl

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,20 @@ using ImageCore
44
using ImageSegmentation
55
using ImageMorphology: label_components
66
using FileIO
7+
using JLD2
8+
using XLSX
9+
using Glob
10+
using Gtk4
11+
using GtkObservables
12+
using ImageView
13+
using Random
714

815
export segment_image, stimulus_index, spots, Spot, upperleft
9-
export randshow, meanshow
16+
export writexlsx, process_images
17+
export randshow, meanshow, gui
1018

1119
include("segment.jl")
12-
include("stubs.jl")
20+
include("xlxs.jl")
21+
include("gui.jl")
1322

1423
end

0 commit comments

Comments
 (0)