5
$\begingroup$

I am a Mathematica novice trying to do some interactive segmentation of microscopy images. I've been trying to understand and build upon some code from a previous StackExchange discussion (Can individual locators in LocatorPane be temporarily disabled?) about creating layers of locators that don't interfere with each other that are overlayed on the same image. My goal is to use this approach to help speed up my image segmentation so I can take a colorized WatershedComponents or MorphologicalComponents label matrix and join components together by grouping and selecting each component with the same color (i.e. layer) of locator. For example, if an image had two objects of interest in it an the segmentation has oversegmented the image so that this results in 3 components for object #1 and 5 components for object #2, I would like to simply put 3 red locators on the components of object #1 and 5 blue locators on the components of object #2 and then pass these component lists to other functions that join these components.

Here's Where I'm Running Into Trouble with Building Upon the Code Below:

i.) How can I apply locPaneSimplified function to a colorized WatershedComponents matrix so the layers and points still show up?

ii.) How can I generate an arbitrary number of overlays as needed (i.e. new layers/colors of locators on demand as determined by the user viewing the segmented image) by pressing a "New Layer" button or something similar?

iii.) How can I get rid of the Manipulate and use just a Dynamic or DynamicModule instead?

Thanks for any suggestions or simple examples you can share with me! -GR

(* 

The block of code below allows for adding arbitrary numbers of red and blue 
locators by toggling between overlays and using LocatorAutoCreate->True.  

This is simplifed from kguler's suggestions in previous StackExhange code discussion:    
https://mathematica.stackexchange.com/questions/9148/can-individual-locators-in-  
locatorpane-be-temporarily-disabled.

*)



(*locator appearance graphics*)
redCircle = Graphics[{Red, Disk[]}, ImageSize -> 10];
blueCircle = Graphics[{Blue, Disk[]}, ImageSize -> 10];
grayDisk = Graphics[{Lighter@Lighter@Gray, Disk[]}, 
ImageSize -> 10] (* used when locator is "grayed out" (i.e. made inactive) 
when another layer is selected *);


locPaneSimple[Dynamic[pts_], shape_] := 
  LocatorPane[Dynamic[pts], 
   Dynamic@Module[{}, 
     Graphics[Point /@ pts, PlotRange -> m, Axes -> True, 
      ImageSize -> {300, 300}]],

Appearance -> shape (* "Appearance" gives the style/shape of the two Locators *),

LocatorAutoCreate -> True (* allows for creating more locators by pressing Alt+Click*)

];


Manipulate[m = 15 (* m sets PlotRange *);
 Overlay[{locPaneSimple[Dynamic[pts], 
    Dynamic@If[layer == 1, redCircle, grayDisk]]  (* 
    preceding [] contains arguments to locPane.  
   If layer==1 then you get red circles at pts if layer1!=1 you get grayDisk *)  
  , 
   locPaneSimple[Dynamic[pts2], 
    Dynamic@If[layer == 2, blueCircle, grayDisk]]},
    All, Dynamic[layer]], 
    {{pts, {{6, 0}, {0, 9}}}, ControlType -> None}, 
    {{pts2, {{7, 0}, {0, 7}}}, ControlType -> None}, 
    {{layer, 1, "layer"}, {1, 2}} (* creates "layer" buttons to toggle between red and
    blue locator layers that have beenoverlayed on same plot *)

 ](* Close Manipulate *)
$\endgroup$
  • $\begingroup$ You have the right to ask about layers of course, and it's a good question, but couldn't the "New layer" button be a merge button that merges all components that currently have locators on them and then removes all locators? You could then iteratively fix up the image. $\endgroup$ – C. E. Jul 21 '14 at 21:20
  • $\begingroup$ Actually, that's what I've been doing thus far but I'm finding that in going through stacks of 100+ images all the iterations take a lot of time and I'd like to have a more streamlined way of doing it all in one fell swoop if possible. $\endgroup$ – user13999 Jul 21 '14 at 21:53
5
$\begingroup$
 shape1 := Graphics[{#, Circle[{0, 0}, 1.5], Disk[]}, ImageSize -> 10] &;
 shape2 := Graphics[{Lighter@#, Disk[]}, ImageSize -> 10] &;

 ClearAll[lOF];
 lOF[nOfOverlays_, colors_List, opts : OptionsPattern[]] :=
    DynamicModule[{layer = 1,
                   pts = ConstantArray[{{100, 100}, {700, 700}}, nOfOverlays], 
                   col = PadRight[colors, nOfOverlays, Last@colors]}, 
   Column[{Overlay[{Graphics[Circle[], ImageSize -> 900], 
                    Sequence @@ MapThread[
                                locPaneSimple[Dynamic[pts[[#]]], 
                                    Dynamic@If[layer== 1+#, shape1[#2], shape2[#2]]] &, 
                                {Range[nOfOverlays], col}]} ,
                   All, Dynamic[layer], opts],
           Row[{Button["Advance Layer", layer++;layer = Mod[layer, nOfOverlays, 1]], 
                Button["Previous Layer", layer--; layer = Max[layer, 1]], 
                Dynamic["     layer= " <> ToString[layer]]}]  } 
                  ] 
         ]  

 lOF[4, ColorData[1, "ColorList"], Alignment -> Center]

enter image description here

$\endgroup$
  • $\begingroup$ Beautiful! Thanks for your help with this. $\endgroup$ – user13999 Jul 23 '14 at 3:37
1
$\begingroup$

I have updated the code so that now it is able to create a stack of locator overlays on an image of interest (here a simple Circle[] but I am overlaying the locators on Colorized WatershedComponents matrices resulting from microscopy images of cells) and I have also dispensed with the Manipulate and replaced it with a function with a DynamicModule. However, I am still stuck on how to produce a function that creates an arbitrary number of overlays (rather than the 5 hard-coded layers I show in the code below).

I have tried partially automating the creation of the Locator Panes by using the Map function and then prepending the bottom layer image to this list of Locator Panes before using the Overlay function on the whole thing, but this does not produce the desired results (layers of locators seem to be able to interfere with each other and do not respond when I advance the "layer buttons" I have created).

This is the code I have been trying to use to automate this that does not do the job (this would be in the body of the LocatorOverlayFuncUpdated if it worked):

  locatorList=locPaneSimple[Dynamic[pts[[#]]], Dynamic@If[layer == #,  
  locAppearanceListMapped[[#]], grayDisk]] & /@ {1, 2, 3, 4, 5}; 


  bottomLayerImage=Graphics[Circle[], ImageSize -> 900];

  locatorListPrepended=Prepend[locatorList,bottomLayerImage];          

Below is code that does work but hard-codes the number of locator layers rather than allows LocatorOverlayFuncUpdated to catch a user-defined number of layers of locators to create. Any help getting past this stumbling block would be greatly appreciated. Thanks! -GR

(* 7/22/14 @ 2:45 pm

This block of code builds off StackExchange code and works with 
waterShedded label matrix resulting from image 
processing of a microscopy image to display Overlayed layers of 
locators of different colors that don't interfere with each other.
 *)


(*locator appearance graphics*)

blackCircle = Graphics[{Black, Disk[]}, ImageSize -> 10];
redCircle = Graphics[{Red, Disk[]}, ImageSize -> 10];
blueCircle = Graphics[{Blue, Disk[]}, ImageSize -> 10];
greenCircle = Graphics[{Darker[Green], Disk[]}, ImageSize -> 10];
purpleCircle = Graphics[{Purple, Disk[]}, ImageSize -> 10];
grayDisk = 
Graphics[{Lighter@Lighter@Gray, Disk[]}, ImageSize -> 10] 
(* used when locator is "grayed out" (i.e. made inactive) when another layer is   
selected *);

(* this function is modified from one originally created by kguler 
   (from StackExchange).  Creates Locator Panes for Overlaying inside 
the LocatorOverlayFunc *)

locPaneSimple[Dynamic[pts_], shape_] := 
  LocatorPane[Dynamic[pts], 
    Graphics[{Opacity[0], Rectangle[]}, ImageSize -> 900] 

(* Note that this Rectangle Graphics Object is just a transparent dummy 
object that is the same size as the displayed image of interest at the bottom
 of the Overlay stack of images *) ,

Appearance -> shape(* sets appearance of Locator(s) *),
LocatorAutoCreate -> True] (* close LocatorPane *);




LocatorOverlayFuncUpdated[numberOfOverlaysToCreate_] :=

(* note that at present numberOfOverlaysToCreate argument does not do anything but
 I am hoping this function can be modified so it can create the desired number of 
 overlays on demand *)

 DynamicModule[{layer = 1, 
 pts = {{{100, 100}, {700, 700}}, {{100, 100}, {700, 700}}, {{100, 
   100}, {700, 700}}, {{100, 100}, {700, 700}}, {{100, 100}, {700,
    700}}}},


Column[{

 Overlay[{

  Graphics[Circle[], ImageSize -> 900],

  locPaneSimple[Dynamic[pts[[1]]], 
   Dynamic@If[layer == 2, blackCircle, grayDisk]]  ,

  locPaneSimple[Dynamic[pts[[2]]], 
   Dynamic@If[layer == 3, redCircle, grayDisk]],

  locPaneSimple[Dynamic[pts[[3]]], 
   Dynamic@If[layer == 4, blueCircle, grayDisk]],

  locPaneSimple[Dynamic[pts[[4]]], 
   Dynamic@If[layer == 5, greenCircle, grayDisk]] ,

  locPaneSimple[Dynamic[pts[[5]]], 
   Dynamic@If[layer == 6, purpleCircle, grayDisk]]  

  }(* close Overlay bracket *)

 , All, Dynamic[layer]] (*close Overlay *)

, (*comma is Column separator *)


Row[{Button["Advance Layer", layer++], 
  Button["Previous Layer", layer--], 
  Dynamic["     layer= " <> ToString[layer]]}]  (*close Row *)



 } (*close Column bracket *)
] (*close Column *)


]  (* Close DynamicModule *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.