diff --git a/src/gui.jl b/src/gui.jl index 1acefee..bca9e43 100644 --- a/src/gui.jl +++ b/src/gui.jl @@ -30,8 +30,12 @@ function gui( crop_bottom::Int = 0, crop_left::Int = 0, crop_right::Int = 0, + min_size = 100, # minimum size of segments to keep colorproj = RGB{Float32}(1, 1, -2), # used for identifying the stimulus + expectedpixels = 40000, # "" expectedloc = nothing, # "" + max_size_frac = 0.1, # sets largest allowed spot size + min_size_pixels = 10 # sets smallest allowed spot size ) channelpct(x) = string(round(Int, x * 100)) * '%' @@ -122,7 +126,7 @@ function gui( update_threshold = change -> begin newvalue = round(threshold + change; digits=2) try - seg = segment_image(rescaledimg; threshold = newvalue) + seg = segment_image(rescaledimg; threshold = newvalue, min_size = min_size) nsegs = length(segment_labels(seg)) nsegs > length(colors) && @warn "More than $(length(colors)) segments ($(nsegs)). Excluded ones will be displayed in white and will not be selectable" empty!(labels2idx) @@ -134,7 +138,7 @@ function gui( push!(idx2labels, idx=>l) end centroidsacc, _ = get_centroidsacc(seg.image_indexmap) - istim = labels2idx[stimulus_index(seg, centroidsacc; colorproj = colorproj, expectedloc = expectedloc)] + istim = labels2idx[stimulus_index(seg, centroidsacc; colorproj = colorproj, expectedpixels = expectedpixels, expectedloc = expectedloc)] for (j, cb) in enumerate(cbs) # set_gtk_property!(cb, "active", j <= nsegs) cb[] = (j == istim || j == preclick) @@ -182,7 +186,7 @@ function gui( img = color.(load(file))[crop_top+1:end-crop_bottom, crop_left+1:end-crop_right] rescaledimg = isnothing(bkgimg) ? img : (img ./ bkgimg .* bkgmean) - seg = segment_image(rescaledimg; threshold = threshold) + seg = segment_image(rescaledimg; threshold = threshold, min_size = min_size) nsegs = length(segment_labels(seg)) nsegs > length(colors) && @warn "More than $(length(colors)) segments ($(nsegs)). Excluded ones will be displayed in white and will not be selectable" empty!(labels2idx) @@ -194,7 +198,7 @@ function gui( push!(idx2labels, idx=>l) end centroidsacc, _ = get_centroidsacc(seg.image_indexmap) - istim = labels2idx[stimulus_index(seg, centroidsacc; colorproj = colorproj, expectedloc = expectedloc)] + istim = labels2idx[stimulus_index(seg, centroidsacc; colorproj = colorproj, expectedpixels = expectedpixels, expectedloc = expectedloc)] for (j, cb) in enumerate(cbs) # set_gtk_property!(cb, "active", j <= nsegs) cb[] = (j == istim || j == preclick) @@ -214,7 +218,7 @@ function gui( pixelskeep = map(i -> i ∈ keep, labels_map(seg)) L = label_components(pixelskeep) newseg = SegmentedImage(img, L) - spotdict, stimulus = spots(newseg; colorproj = colorproj, expectedloc = expectedloc) + spotdict, stimulus = spots(newseg; colorproj = colorproj, expectedpixels = expectedpixels, expectedloc = expectedloc, max_size_frac = max_size_frac, min_size_pixels = min_size_pixels) push!(results, (file, spotdict, stimulus, newseg)) end diff --git a/src/segment.jl b/src/segment.jl index 192e740..347fd92 100644 --- a/src/segment.jl +++ b/src/segment.jl @@ -10,7 +10,7 @@ function segment_image( img::AbstractMatrix{<:Color}; threshold::Real = 0.2, # threshold for color similarity in region growing prune::Bool = true, # prune small segments - min_size::Int = 500, # minimum size of segments to keep + min_size::Int = 100, # minimum size of segments to keep ) seg = unseeded_region_growing(img, threshold) if prune @@ -22,27 +22,27 @@ end segment_image(img::AbstractMatrix{<:Colorant}; kwargs...) = segment_image(color.(img); kwargs...) """ - idx = stimulus_index(seg::SegmentedImage, centroidsacc; colorproj = RGB(1, 1, -2), expectedloc = nothing) + idx = stimulus_index(seg::SegmentedImage, centroidsacc; colorproj = RGB(1, 1, -2), expectedpixels = 50000, expectedloc = nothing) Given a segmented image `seg`, return the index of the segment that scores -highest on the product of (1) projection (dot product) with `colorproj` and (2) -number of pixels. +highest on the quotient of (1) projection (dot product) with `colorproj` with (2) +the absolute value of the difference between the number of pixels with `expectedpixels`. Optionally, if images were taken with a fixed location for the stimulus, a segment's score is divided by the squared distance of its centroid (via `centroidsacc`) from the position given by `expectedloc`. """ -function stimulus_index(seg::SegmentedImage, centroidsacc; colorproj = RGB{Float32}(1, 1, -2), expectedloc = nothing) +function stimulus_index(seg::SegmentedImage, centroidsacc; colorproj = RGB{Float32}(1, 1, -2), expectedpixels = 40000, expectedloc = nothing) if !isnothing(expectedloc) proj = map(segment_labels(seg)) do l l == 0 && return 0 val = centroidsacc[l] centroid = [round(Int, val[1] / val[3]), round(Int, val[2] / val[3])] - return l => (colorproj ⋅ segment_mean(seg, l) * segment_pixel_count(seg, l) / max(1, sum(abs2, centroid .- expectedloc))) + return l => (colorproj ⋅ segment_mean(seg, l) / max(1, abs(segment_pixel_count(seg, l) - expectedpixels)) / max(1, sum(abs2, centroid .- expectedloc))) end (i, _) = argmax(last, proj) return i else - proj = [l => (colorproj ⋅ segment_mean(seg, l)) * segment_pixel_count(seg, l) for l in segment_labels(seg)] + proj = [l => (colorproj ⋅ segment_mean(seg, l)) / max(1, abs(segment_pixel_count(seg, l) - expectedpixels)) for l in segment_labels(seg)] (i, _) = argmax(last, proj) return i end @@ -110,18 +110,18 @@ Spots larger than `max_size_frac * npixels` (default: 10% of the image) are igno function spots( seg::SegmentedImage; max_size_frac=0.1, # no spot is bigger than max_size_frac * npixels + min_size_pixels=10, # smallest allowed spot kwargs... ) centroidsacc, nadj = get_centroidsacc(seg.image_indexmap) istim = stimulus_index(seg, centroidsacc; kwargs...) - stimulus = Ref{Pair{Int,Spot}}() filter!(centroidsacc) do (key, val) if key == istim stimulus[] = key => Spot(val[3], (round(Int, val[1] / val[3]), round(Int, val[2] / val[3]))) return false end - return val[3] <= max_size_frac * length(seg.image_indexmap) + return min_size_pixels <= val[3] <= max_size_frac * length(seg.image_indexmap) # # is the centroid within the segment? # x, y = round(Int, val[1] / val[3]), round(Int, val[2] / val[3]) # l = seg.image_indexmap[x, y] @@ -148,6 +148,7 @@ function spots( indexmap::Matrix{Int}, istim::Int; max_size_frac=0.1, + min_size_pixels=10, kwargs... ) centroidsacc, nadj = get_centroidsacc(indexmap) @@ -157,7 +158,7 @@ function spots( stimulus[] = key => Spot(val[3], (round(Int, val[1] / val[3]), round(Int, val[2] / val[3]))) return false end - return val[3] <= max_size_frac * length(indexmap) + return min_size_pixels <= val[3] <= max_size_frac * length(indexmap) end return Dict(l => Spot(val[3], (round(Int, val[1] / val[3]), round(Int, val[2] / val[3]))) for (l, val) in centroidsacc), stimulus[] end