4
$\begingroup$

I'm trying to combine several Manipulate objects into a single workflow, for semi-automating an image analysis. I have worked out how to do each individual part, but I don't know how to combine it into a single GUI.

I'm analysing cells, but I'm only interested in their outline. And some cells might have issues where I can only use part of the outline (or no part of it at all), so I want to be able to select just individual parts.

Load an example image, with very apple looking cells, and a few constants.

img = ExampleData[{"TestImage", "Apples"}];
pad = 40; imsize = 300;

So first I want to threshold the image at an appropriate point, which depends on the image itself:

Manipulate[Show[Threshold[img, th], ImageSize -> 500], {{th, 0.5}, 0, 1}]

thresholded image

For instance, maybe that is actually 0.5. I then want to save that value for use later. Here I just set it:

thres = 0.5;

I then take the image, use that threshold, and select certain subimages (the green apples, nice and sharp):

m = MorphologicalComponents[img, thres];
components = ComponentMeasurements[{m, img}, {"Area", "BoundingBox"}, 
    ((#Area > 200 && #AdjacentBorderCount ==  0 && (#Mean[[2]] > #Mean[[1]]))) &];
componentsBB = ({{-pad, -pad}, {pad, pad}} + #) & /@ components[[All, 2, 2]];
imSplit = ImageTrim[img, componentsBB];

split green apples

This gives me 6 apples in this example. Next, I want to be able to select only some of the apples to continue for further analysis, currently I'm using a ChoiceDialog, but that may not be the best option:

whichSubImages = ChoiceDialog[#, {"Include" -> True, "Exclude" -> False}] & /@ imSplit;
filteredSubImages = Pick[imSplit, whichSubImages];

I then want to be able to select points on (a modified version of) each of the subimages, and select which parts are to be included in the downstream analysis. What I'd like to do now is be able to go through each filteredSubImage and do that for each, probably with a button to save and advance.

So I want to put these three parts together:

  1. Setting the threshold
  2. Selecting which apples to analyse
  3. Selecting individual regions on the surface of the apple, and exporting their values

into a single GUI, probably with some buttons. Any help (or improvements for the functions) would be appreciated.

My current attempt is:

 splitImage[img_, threshold_] := splitImage[img, threshold] = 
  Module[{m, components, componentsBB},
   m = MorphologicalComponents[img, threshold];
   components = ComponentMeasurements[{m, img}, {"Area", "BoundingBox"}, 
     ((#Area > 1000 && #AdjacentBorderCount == 0 && (#Mean[[2]] > #Mean[[1]]))) &];
   componentsBB = ({{-pad, -pad}, {pad, pad}} + #) & /@ components[[All, 2, 2]];
   ImageTrim[Threshold[img, threshold], componentsBB]]

DynamicModule[{panelIndex = 1, thres, currentSelected = {}, x = 1, pts = {}, setpts}, 
Column[{TabView[{"Set Threshold" -> 
  Column[{Control[{{thres, 0.4, "Threshold"}, 0.3, 0.6}], 
    Dynamic@Show[Threshold[img, thres], ImageSize -> 500], 
    Dynamic@thres}], 
 "Select Apples" -> 
  Column[{Dynamic@
     TogglerBar[Dynamic[currentSelected], splitImage[img, thres], 
      Appearance -> "Row"], Dynamic[Length@currentSelected]}], 
 "Segment Apples" -> 
  Column[{Slider[Dynamic[x], {1, Dynamic@Length[currentSelected], 1}, 
     Enabled -> False], 
    Row[{Button["Previous Apple", setpts[x] = pts; x--; 
       If[ListQ[setpts[x]], pts = setpts[x], pts = {{}}], 
       Enabled -> Dynamic@If[x > 1, True, False]],
      Button["Next Apple", setpts[x] = pts; x++; 
       If[ListQ[setpts[x]], pts = setpts[x], pts = {{}}], 
       Enabled -> 
        Dynamic@If[x < Length[currentSelected], True, False]]}], 
    Panel[Row@{LocatorPane[
        Dynamic[pts, pts = Select[pts, Length[#] == 2 &]; 
         setpts[x] = pts], 
        Dynamic@Show[currentSelected[[x]], ImageSize -> imsize], 
        LocatorAutoCreate -> All, 
        Appearance -> 
         Graphics[{White, Disk[]}, ImageSize -> 20]]}]}], 
 "Save Results" -> Column[{
    Button["Print Results", 
     Print[<|"Threshold" -> Dynamic@thres, 
       "points" -> Dynamic@Table[setpts[i], {i, 1, Length[currentSelected]}]|>]]}]},
 Dynamic[panelIndex]]}]]    

which is getting there, but I have some issues with it at the moment:

  1. I can't get the slider on the third pane to save the positions of the points, only the button. I thought I'd be able to do this with Dynamic[x,{setpts[x]=pts, Automatic, pts=setpts[x]}] in the Slider, but that didn't work. The documentation of Slider talks about the need for HoldRest but I couldn't figure out what exactly I needed to do there.
  2. Each subimage except the first has a point at the centre by default. Which I think is connected to setpts does not being set properly inside the LocatorPane.
  3. As setpts is not being set properly, it is only being set on the button presses, not when you click on the tabs.

Suggestions welcome.

$\endgroup$

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Browse other questions tagged or ask your own question.