The first step in debugging is always to narrow down the problem. To do this, you can make ncurve
global:
DynamicModule[{(* ncurve = {} *) },
EventHandler[
...
Then, you can click on the image and evaluate ncurve
in a separate cell:
Length[ncurve]
248652
(You can and should put ncurve
in a DynamicModule
once you're done, of course. But for debugging, it's common practice to make local variables global and play with them in another notebook cell.)
Now you a lot more than just "nothing seems to have happened": You know that
ncurve
was set, but the display wasn't updated. That's the easy part: You just have to wrap the ImageCompose[...]
part with Dynamic[...]
and it's updated dynamically. (DynamicModule
localizes variables, like Module
, it doesn't make the contained code block dynamic, like Dynamic
.)
- those are way too many points. In fact, unless you (accidentally) manage to hit one of the few edge points in the image,
ncurve
will simply contain all the black points in the edge-image. (Which could easily hang or crash the Mathematica Frontend.)
That's because the imorc
image is zero for all non-edge pixels. What you would need is an image that contains a unique index for each connected component, or the index of the closest connected component, if it's a background pixel. Here, WatershedComponents
is very useful:
watersheds =
Image[WatershedComponents[ColorNegate[iedge], Method -> "Basins"]];
imorc = Image[ImageData[watersheds] * ImageData[iedge]];
Now, if you use PixelValue[watersheds, ...
, you get a component index, for edge- and non-edge pixels, and you can use PixelValuePositions[imorc, ...
to look up the corresponding edge pixels:
DynamicModule[{(*ncurve={}*)},
EventHandler[
Dynamic[ImageCompose[igray,
Graphics[
ListLinePlot[ncurve,
Axes -> False]]]], {"MouseClicked" :> (ncurve =
PixelValuePositions[imorc,
PixelValue[watersheds,
MousePosition["Graphics"] /. None -> {0, 0}]])}]]
Now, if you click on the image, you see a superimposed edge line. But it's probably not what you expected:
If you don't understand what you're seeing, try evaluating ListLinePlot[ncurve]
alone. ListLinePlot
chooses a PlotRange
that fits the list of points, and ImageCompose
simply composes the two resulting images, ignoring the different coordinate systems. What you really want is Show
:
DynamicModule[{(*ncurve={}*)},
EventHandler[
Dynamic@Show[igray,
ListLinePlot[ncurve]], {"MouseClicked" :> (ncurve =
PixelValuePositions[imorc,
PixelValue[watersheds,
MousePosition["Graphics"] /. None -> {0, 0}]])}]]
Also: EventHandler
is a relatively low-level function. Mathematica has higher-level functions like LocatorPane
that can make your life simpler:
DynamicModule[{mousePt = {1, 1}},
LocatorPane[Dynamic[mousePt],
Dynamic[
Show[igray,
ListLinePlot[
PixelValuePositions[imorc, PixelValue[watersheds, mousePt]]]]]]]
One last note: I've learned to avoid dynamic code during debugging as much as possible. I've lost too much work because the notebook interface hung or crashed evaluating a programming error (e.g. like displaying a list plot with 248652 points). Use a LocatorPane
to choose a point, and a separate non-dynamic cell with Show
, Graphics
, ListPlot
and friends until you're satisfied with the result. Then put them in a dynamic block. (Or actually, save your notebook, then put them in a dynamic block.)