I'm just starting to debug this, and I apologize for the complexity - but I'm hoping this might ring a bell with someone.
As I proceed to investigate, I'll try to produce a minimum implementation that duplicates the problem. Java Plugin *creates two windows *a StackWindow (which for this processing contains only 1 image - 32-bit) *a second StackWindow (containing multiple images - not used further) *these are both specialized Classes that extend StackWindow and contain objects which extend ImagePlus. It may be relevant that these windows talk to each other, and redraw their overlays based on cursor movement. *under user control, one of many different Overlays may be drawn on the first StackWindow. This overlay completely replaces the old Overlay. It is displayed perfectly. Now...I want to save the resulting image, including the new Overlay. Problem 1 - given that there *might* be several images in the stack, I tried Image->Stacks->Stack to Images This FAILS when there is only 1 image in the stack. Why? is an ImageStack with only 1 image NOT considered to be a Stack? Pushing through, I then try File->Save As->TIFF (I also tried JPG). This writes a file just fine - but when I look at it - I see the OLD Overlay. Note that this old Overlay is NOT visible on the screen when I do the Save. And, the new Overlay is *still* displayed after the Save. So...does Save As use some hidden version of the Stack which may not be in sync with what is displayed on the screen??? I also tried Image->Duplicate. I get a second copy of the image, but with the OLD Overlay. The original version remains displayed with the NEW Overlay. I'm stumped. I would be happy to send the actual plugin, and test data, to anyone with the energy to deal with it - but it's really much too much to ask. In the next day or two, I will try to write the smallest possible plugin that replicates this behavior. In the meantime - any ideas??? As it turns out, our actual need for this can be satisfied by taking a ScreenShot. So, it's not critical. But, I'm astounded that Image->Save As and Image->Duplicate do not reproduce the image as displayed on the screen. This seems to be a very basic requirement! One theory - does Image->Save As and Image->Duplicate somehow duplicate the underlying ImagePlus - and then manipulate it without display? Note that my images are using an EXTENSION of ImagePlus that re-draws the original Overlay - usually based on cursor movement. If the ImagePlus is somehow duplicated...and then manipulated off-screen...it's possible that the original Overlay is re-drawn on the off-screen version. Which leads to: is there a convenient way to ask ImageJ to save the *displayed image* (in any format). Something like "PrintWindowContents" or some such? What I want is an image file (an RGB PNG would be perfect). note: I just tried changing the TYPE of the image to RGB and then saving as TIFF. No joy. The conversion worked fine, but the resulting image had the OLD Overlay. So...I'm back to: how can I save an RGB version of an ImageJ window *as currently displayed on the screen*. I prefer an image without the framing, but I don't want to rely on the standard ScreenShot mechanism which (I think) requires me to precisely pick the corners of the window. That would be a "workaround". I'm (eventually) interested in knowing WHY Image->Save does NOT write an image file representing what is actually displayed on the screen. -- Kenneth Sloan [hidden email] Vision is the art of seeing what is invisible to others. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Hi Kenneth,
for troubleshooting, if you know how many objects to expect in the overlay, you can try this simple Javascript: imp=IJ.getImage(); IJ.log(imp.getTitle()); ovly=imp.getOverlay(); IJ.log("overlay="+ovly); It will show something like this: blobs.gif overlay=Overlay[size=1 none] Here, the 'blobs.gif' image has one object in the overlay. It might show whether there are maybe more objects in the overlay that you are aware of; maybe the old ones did not disappear but are invisible for some reason. Alternatively, use Image>Overlay>To ROi Manager to see what you have in the overlay. Please beware that not everything that looks like an overlay is necessary in the Overlay class (the basis for the Image>Overlay commands). The Overlay class was added to ImageJ around version 1.30. Prior to that, other mechanisms have been used to draw overlays (e.g., replacing the ImageCanvas with a custom one that draws the overlay). If you happen to have an overlay drawn by such a legacy method, it won't be saved with the image. If you have such legacy code, it might also hide the contents of the Overlay class ("modern-type overlay") without actually removing the overlay. --- "Stack to Images" indeed checks that there is currently more than one stack slice; for single images it produces an error message. See ij.plugin.StackEditor, method convertStackToImages (line 253). If there is only one stack slice, what else should it do? Leave the image as it is? Then the (interactive) user (who might erroneaouly believe that he/she has a stack with several slices) will be astonished that the command does nothing; maybe wait a few seconds whether the computer is slow, retry, and it still does not work. This could lead to frustration... When running it non-interactively, it is easy to check for a stack size > 1. Michael ________________________________________________________________ On 27.11.19 19:14, Kenneth Sloan wrote: > I'm just starting to debug this, and I apologize for the complexity - but I'm hoping this might ring a bell with someone. > As I proceed to investigate, I'll try to produce a minimum implementation that duplicates the problem. > > Java Plugin > *creates two windows > *a StackWindow (which for this processing contains only 1 image - 32-bit) > *a second StackWindow (containing multiple images - not used further) > *these are both specialized Classes that extend StackWindow and contain objects which > extend ImagePlus. It may be relevant that these windows talk to each other, and > redraw their overlays based on cursor movement. > *under user control, one of many different Overlays may be drawn on the first StackWindow. > This overlay completely replaces the old Overlay. It is displayed perfectly. > > Now...I want to save the resulting image, including the new Overlay. > > Problem 1 - given that there *might* be several images in the stack, I tried Image->Stacks->Stack to Images > > This FAILS when there is only 1 image in the stack. Why? is an ImageStack with only 1 image NOT considered to be > a Stack? > > Pushing through, I then try File->Save As->TIFF (I also tried JPG). > > This writes a file just fine - but when I look at it - I see the OLD Overlay. Note that this old Overlay is NOT visible on the screen when I do the Save. And, the new Overlay is *still* displayed after the Save. > > So...does Save As use some hidden version of the Stack which may not be in sync with what is displayed on the screen??? > > I also tried Image->Duplicate. I get a second copy of the image, but with the OLD Overlay. The original version remains displayed with the NEW Overlay. > > I'm stumped. > > I would be happy to send the actual plugin, and test data, to anyone with the energy to deal with it - but it's really much too much to ask. In the next day or two, I will try to write the smallest possible plugin that replicates this behavior. > > In the meantime - any ideas??? > > > As it turns out, our actual need for this can be satisfied by taking a ScreenShot. So, it's not critical. But, I'm astounded that Image->Save As and Image->Duplicate do not reproduce the image as displayed on the screen. This seems to be a very basic requirement! > > One theory - does Image->Save As and Image->Duplicate somehow duplicate the underlying ImagePlus - and then manipulate it without display? Note that my images are using an EXTENSION of ImagePlus that re-draws the original Overlay - usually based on cursor movement. If the ImagePlus is somehow duplicated...and then manipulated off-screen...it's possible that the original Overlay is re-drawn on the off-screen version. > > Which leads to: is there a convenient way to ask ImageJ to save the *displayed image* (in any format). Something like "PrintWindowContents" or some such? What I want is an image file (an RGB PNG would be perfect). > > note: I just tried changing the TYPE of the image to RGB and then saving as TIFF. No joy. The conversion worked fine, but the resulting image had the OLD Overlay. > > So...I'm back to: how can I save an RGB version of an ImageJ window *as currently displayed on the screen*. I prefer an image without the framing, but I don't want to rely on the standard ScreenShot mechanism which (I think) requires me to precisely pick the corners of the window. > > That would be a "workaround". I'm (eventually) interested in knowing WHY Image->Save does NOT write an image file representing what is actually displayed on the screen. > > > -- > Kenneth Sloan > [hidden email] > Vision is the art of seeing what is invisible to others. > > -- > ImageJ mailing list: http://imagej.nih.gov/ij/list.html > -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Michael-
I'll try your suggestions. A few comments. a) I believe all my Overlays are drawn by Java code that uses setOverlay(). The first Overlay is set (repeatedly) by an extension of ImagePlus (of perhaps StackWindow - I need to check). The second Overlay is set once by a program that has access to the ImagePlus (I think...). Up until that point, all is well - the old Overlay disappears and the new one is displayed. If an Overlay can be associated with either an ImagePlus or a StackWindow....these are details I need to investigate. This is a fairly complicated set of objects, written over a period of several years, by several authors - not all of whom had the same understanding of how ImageJ actually works. So...there may well be inconsistencies in the user-level code. b) If I have a StackWindow containing an ImageStack with just one slice, I expect Stack to Images to turn it into an ImagePlus containing a single image (not a Stack) and perhaps change the type of window to no longer be a StackWindow. This is all probably related to another oddity (to me) that when I create the StackWindow, using a Stack with only one slice, I don't get scrollbar controls - and later, when I add slices (which I can do, because it's still a Stack displayed in a StackWindow) I do NOT get the scrollbar added. I consider it reasonable to NOT display scrollbar controls when there is only one slice - but I consider it a bug to NOT have scrollbar controls when the Stack has more than 1 slice - even if the Stack had only 1 slice when the StackWindow was created. To me, this is basic - a Stack with 1 slice is still a Stack, just as a vector containing only one element is still a vector, and not a scalar (if that argument fails, try x vs {x}) So...as I write my "minimal program to replicate" - I will check to be sure that the setOverlay() calls reference the same object (ImagePlus vs StackWindow). I suspect that I will first write a VERY simple program that does not fail, and then see what features of the current plugin need to be added to make it fail. Do you know if Duplicate or Save As work with a second, hidden copy of the ImagePlus? The most confusing thing to me is that the duplicated/saved image has a DIFFERENT Overlay than the one being displayed. I can think of two possibilities: a) processing the duplicate/save causes my class which extends StackWindow or the class which extends ImagePlus to re-establish the "old" Overlay (but only on the hidden copy) b) I somehow have one Overlay attached to the ImagePlus and another attached to the StackWindow - and the display currently shows the one attached to the ImagePlus while duplicate/save uses the one attached to the StackWindow. The most confusing thing to me is that Duplicate produces a DIFFERENT display. The key may be "where does Duplicate find the old Overlay?" At the top level, the old Overlay should be long gone, and no longer even exist. Either ImageJ has made a safety copy somewhere and is reusing it - or there are two overlays attached to two different objects (the window and the ImagePlus). I'll know more in a few days. Guess what I'll be doing all of Thanksgiving... But...not today. The ice rink across the street from my apartment is open, and it's time for my first skate of the season. -- Kenneth Sloan [hidden email] Vision is the art of seeing what is invisible to others. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Dear Kenneth,
On your question: > So...I'm back to: how can I save an RGB version of an ImageJ window *as currently displayed on the screen*. Did you try: Plugins> Utilities>Capture_Image ? I successfully used this feature ages ago when I wanted as well to export (and save) RGB pictures together with their overlays. Concerning your found issues with a stack (creation) of size 1, I agree on your comments that this should be interpreted as a bug. Happy Thanksgivings! My best regards, Philippe Philippe CARL Laboratoire de Bioimagerie et Pathologies UMR 7021 CNRS - Université de Strasbourg Faculté de Pharmacie 74 route du Rhin 67401 ILLKIRCH Tel : +33(0)3 68 85 41 84 ----- Mail original ----- De: "Kenneth Sloan" <[hidden email]> À: "imagej" <[hidden email]> Envoyé: Mercredi 27 Novembre 2019 22:09:01 Objet: Re: confusing overlay behavior Michael- I'll try your suggestions. A few comments. a) I believe all my Overlays are drawn by Java code that uses setOverlay(). The first Overlay is set (repeatedly) by an extension of ImagePlus (of perhaps StackWindow - I need to check). The second Overlay is set once by a program that has access to the ImagePlus (I think...). Up until that point, all is well - the old Overlay disappears and the new one is displayed. If an Overlay can be associated with either an ImagePlus or a StackWindow....these are details I need to investigate. This is a fairly complicated set of objects, written over a period of several years, by several authors - not all of whom had the same understanding of how ImageJ actually works. So...there may well be inconsistencies in the user-level code. b) If I have a StackWindow containing an ImageStack with just one slice, I expect Stack to Images to turn it into an ImagePlus containing a single image (not a Stack) and perhaps change the type of window to no longer be a StackWindow. This is all probably related to another oddity (to me) that when I create the StackWindow, using a Stack with only one slice, I don't get scrollbar controls - and later, when I add slices (which I can do, because it's still a Stack displayed in a StackWindow) I do NOT get the scrollbar added. I consider it reasonable to NOT display scrollbar controls when there is only one slice - but I consider it a bug to NOT have scrollbar controls when the Stack has more than 1 slice - even if the Stack had only 1 slice when the StackWindow was created. To me, this is basic - a Stack with 1 slice is still a Stack, just as a vector containing only one element is still a vector, and not a scalar (if that argument fails, try x vs {x}) So...as I write my "minimal program to replicate" - I will check to be sure that the setOverlay() calls reference the same object (ImagePlus vs StackWindow). I suspect that I will first write a VERY simple program that does not fail, and then see what features of the current plugin need to be added to make it fail. Do you know if Duplicate or Save As work with a second, hidden copy of the ImagePlus? The most confusing thing to me is that the duplicated/saved image has a DIFFERENT Overlay than the one being displayed. I can think of two possibilities: a) processing the duplicate/save causes my class which extends StackWindow or the class which extends ImagePlus to re-establish the "old" Overlay (but only on the hidden copy) b) I somehow have one Overlay attached to the ImagePlus and another attached to the StackWindow - and the display currently shows the one attached to the ImagePlus while duplicate/save uses the one attached to the StackWindow. The most confusing thing to me is that Duplicate produces a DIFFERENT display. The key may be "where does Duplicate find the old Overlay?" At the top level, the old Overlay should be long gone, and no longer even exist. Either ImageJ has made a safety copy somewhere and is reusing it - or there are two overlays attached to two different objects (the window and the ImagePlus). I'll know more in a few days. Guess what I'll be doing all of Thanksgiving... But...not today. The ice rink across the street from my apartment is open, and it's time for my first skate of the season. -- Kenneth Sloan [hidden email] Vision is the art of seeing what is invisible to others. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Image → Overlay → Flatten also does what you want, and works better than Capture Image, as it will retain the image resolution and spatial scaling. Capture Image will distort the image if it is not shown on screen with a 1:1 zoom.
Stein -----Original Message----- From: ImageJ Interest Group <[hidden email]> On Behalf Of CARL Philippe (LBP) Sent: 28. november 2019 11:19 To: [hidden email] Subject: Re: confusing overlay behavior Dear Kenneth, On your question: > So...I'm back to: how can I save an RGB version of an ImageJ window *as currently displayed on the screen*. Did you try: Plugins> Utilities>Capture_Image ? I successfully used this feature ages ago when I wanted as well to export (and save) RGB pictures together with their overlays. Concerning your found issues with a stack (creation) of size 1, I agree on your comments that this should be interpreted as a bug. Happy Thanksgivings! My best regards, Philippe Philippe CARL Laboratoire de Bioimagerie et Pathologies UMR 7021 CNRS - Université de Strasbourg Faculté de Pharmacie 74 route du Rhin 67401 ILLKIRCH Tel : +33(0)3 68 85 41 84 ----- Mail original ----- De: "Kenneth Sloan" <[hidden email]> À: "imagej" <[hidden email]> Envoyé: Mercredi 27 Novembre 2019 22:09:01 Objet: Re: confusing overlay behavior Michael- I'll try your suggestions. A few comments. a) I believe all my Overlays are drawn by Java code that uses setOverlay(). The first Overlay is set (repeatedly) by an extension of ImagePlus (of perhaps StackWindow - I need to check). The second Overlay is set once by a program that has access to the ImagePlus (I think...). Up until that point, all is well - the old Overlay disappears and the new one is displayed. If an Overlay can be associated with either an ImagePlus or a StackWindow....these are details I need to investigate. This is a fairly complicated set of objects, written over a period of several years, by several authors - not all of whom had the same understanding of how ImageJ actually works. So...there may well be inconsistencies in the user-level code. b) If I have a StackWindow containing an ImageStack with just one slice, I expect Stack to Images to turn it into an ImagePlus containing a single image (not a Stack) and perhaps change the type of window to no longer be a StackWindow. This is all probably related to another oddity (to me) that when I create the StackWindow, using a Stack with only one slice, I don't get scrollbar controls - and later, when I add slices (which I can do, because it's still a Stack displayed in a StackWindow) I do NOT get the scrollbar added. I consider it reasonable to NOT display scrollbar controls when there is only one slice - but I consider it a bug to NOT have scrollbar controls when the Stack has more than 1 slice - even if the Stack had only 1 slice when the StackWindow was created. To me, this is basic - a Stack with 1 slice is still a Stack, just as a vector containing only one element is still a vector, and not a scalar (if that argument fails, try x vs {x}) So...as I write my "minimal program to replicate" - I will check to be sure that the setOverlay() calls reference the same object (ImagePlus vs StackWindow). I suspect that I will first write a VERY simple program that does not fail, and then see what features of the current plugin need to be added to make it fail. Do you know if Duplicate or Save As work with a second, hidden copy of the ImagePlus? The most confusing thing to me is that the duplicated/saved image has a DIFFERENT Overlay than the one being displayed. I can think of two possibilities: a) processing the duplicate/save causes my class which extends StackWindow or the class which extends ImagePlus to re-establish the "old" Overlay (but only on the hidden copy) b) I somehow have one Overlay attached to the ImagePlus and another attached to the StackWindow - and the display currently shows the one attached to the ImagePlus while duplicate/save uses the one attached to the StackWindow. The most confusing thing to me is that Duplicate produces a DIFFERENT display. The key may be "where does Duplicate find the old Overlay?" At the top level, the old Overlay should be long gone, and no longer even exist. Either ImageJ has made a safety copy somewhere and is reusing it - or there are two overlays attached to two different objects (the window and the ImagePlus). I'll know more in a few days. Guess what I'll be doing all of Thanksgiving... But...not today. The ice rink across the street from my apartment is open, and it's time for my first skate of the season. -- Kenneth Sloan [hidden email] Vision is the art of seeing what is invisible to others. -- ImageJ mailing list: https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fimagej.nih.gov%2Fij%2Flist.html&data=02%7C01%7Cstein.rorvik%40sintef.no%7Cd2fd8cbb374f40569dc208d773ecac0e%7Ce1f00f39604145b0b309e0210d8b32af%7C1%7C0%7C637105332653839452&sdata=8XeAm25%2FezRtVB4zU7ynS5oeleecUP7wQ0wisoRAjsQ%3D&reserved=0 -- ImageJ mailing list: https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fimagej.nih.gov%2Fij%2Flist.html&data=02%7C01%7Cstein.rorvik%40sintef.no%7Cd2fd8cbb374f40569dc208d773ecac0e%7Ce1f00f39604145b0b309e0210d8b32af%7C1%7C0%7C637105332653839452&sdata=8XeAm25%2FezRtVB4zU7ynS5oeleecUP7wQ0wisoRAjsQ%3D&reserved=0 -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
CaptureImage works fine (although I had to jump through a hoop to convince Catalina to let FIJI access the screen).
Flatten did NOT work - it produces an image with the wrong Overlay. In my application, images fit on the screen and the purpose of capturing the image+overlay is to produce a figure. So...my immediate needs are met. I am left with curiosity as to WHY "Save As", "Duplicate", and "Flatten" all produce images with an out-of-date Overlay. I'l work on it, but since it's now simply "curiosity", it may drop to low priority. I thank everyone for their quick, and helpful, responses. Summary of remaining issues: a) creating a StackWindow, adding an Overlay overlay1, replacing this with Overlay overlay2, and then applying either "Flatten", "S.ave As", or "Duplicate" produces an image with overlay1 b) creating a StackWindow with an ImageStack containing only 1 slice: *does not create scrollbar controls *does not add scrollbar controls if slices are added (but adding slices does work) *generates an error message on "Stack To Images" This last one is apparently by design - so someone thought this was correct behavior. I don't understand this - but there may well be a good reason. I will probably work around this by adding a dummy "scratch" slice to my ImageStack. This actually has a (marginal) utility for me because my immediate need was to easily generate an image with only the Overlay on a black background. I had been using Adjust->Brightness/Contrast to make the image black - but including a blank slice in the ImageStack is easier. "Always mount a scratch monkey" - five points for identifying the reference withOUT Google. Happy Thanksgiving! -- Kenneth Sloan [hidden email] Vision is the art of seeing what is invisible to others. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Hi Kenneth,
ImageJ does not keep a copy of an old (deleted) overlay in any place. Still, for me the only explanation for the odd behavior that you see is this one: The second overlay that gets lost is not based on the Overlay class, but some legacy mechanism to create an overlay. Please try this Javascript on the problematic image: IJ.log("canvas="+IJ.getImage().getCanvas()); Does it report an "ij.gui.ImageCanvas" or something else? Does Image>Overlay>Remove Overlay make the overlay disappear? If not, it is something else than a normal overlay based on the Overlay class. You can also use Image>Overlay>To Roi Manager to check whether it is a 'normal' overlay. The RoiManager will get the "normal" overlay, i.e. that given by the Overlay class. To show that there is no general problem with replacing overlays, here is a macro that creates an overlay on a stack, then creates a new overlay (replacing the old one). With "Duplicate", "Capture Image" or whatever, I see no trace of the old overlay. run("T1 Head Renderings (736K)"); makeRectangle(84, 67, 28, 66); run("Add Selection...", "stroke=red width=2 fill=none new"); setSlice(2); makeRectangle(142, 33, 7, 22); setKeyDown("shift"); makeRectangle(156, 32, 6, 25); //add to previous overlay: run("Add Selection...", "stroke=green width=2 fill=none"); makeRectangle(52, 97, 82, 6); //new overlay run("Add Selection...", "stroke=blue width=1 fill=blue new"); --- Concerning the bug where an image does not get stack sliders if the size of the ImageStack increases from 1 to >1: You can simply add imp.setStack(stack); after the stack gets one more slice to make the slider appear. But I agree that ImagePlus.updateAndDraw() could check whether the stack size is > 1 and its window is a normal ImageWindow (not a StackWindow), then do a setStack. Michael ________________________________________________________________ On 28.11.19 17:52, Kenneth Sloan wrote: > CaptureImage works fine (although I had to jump through a hoop to convince Catalina to let FIJI access the screen). > > Flatten did NOT work - it produces an image with the wrong Overlay. > > In my application, images fit on the screen and the purpose of capturing the image+overlay is to produce a figure. > > So...my immediate needs are met. I am left with curiosity as to WHY "Save As", "Duplicate", and "Flatten" all produce images with an out-of-date Overlay. I'l work on it, but since it's now simply "curiosity", it may drop to low priority. > > I thank everyone for their quick, and helpful, responses. > > Summary of remaining issues: > > a) creating a StackWindow, adding an Overlay overlay1, replacing this with Overlay overlay2, and then applying > either "Flatten", "S.ave As", or "Duplicate" produces an image with overlay1 > b) creating a StackWindow with an ImageStack containing only 1 slice: > *does not create scrollbar controls > *does not add scrollbar controls if slices are added (but adding slices does work) > *generates an error message on "Stack To Images" > > This last one is apparently by design - so someone thought this was correct behavior. I don't understand this - but there may well be a good reason. > > I will probably work around this by adding a dummy "scratch" slice to my ImageStack. This actually has a (marginal) utility for me because my immediate need was to easily generate an image with only the Overlay on a black background. I had been using Adjust->Brightness/Contrast to make the image black - but including a blank slice in the ImageStack is easier. > > "Always mount a scratch monkey" - five points for identifying the reference withOUT Google. > > Happy Thanksgiving! > > -- > Kenneth Sloan > [hidden email] > Vision is the art of seeing what is invisible to others. > > -- > ImageJ mailing list: http://imagej.nih.gov/ij/list.html > -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
The new Overlay is set by: (approximate...I'm seeing some sloppiness in my actual code that needs to be cleaned up - this is y best effort at describing the actual EFFECT - but I could be mistaken)
==================================================================== // pre-condition - imagePlus may already have an Overlay present ...code to create ArrayList<Roi> gridRoiList gridOverlay = new Overlay(); // brand new, virgin Overlay for(Roi roi : gridRoiList) gridOverlay.add(roi); imagePlus.setOverlay(gridOverlay); ==================================================================== At this point, the displayed image is perfect. ONLY the new Overlay is displayed. Now...the complication...the ImagePlus in question is my own EXTENSION to ImagePlus, which also manipulates the overlay. When that happens, the relevant code is: ========================================================================= for(Roi r : this.cursorRoiList) this.cursoerOverlay.add(r ); setOverlay(this.cursorOverlay); updateAndDraw(); ========================================================================= 'cursorOverlay' is maintained by the imagePlus extension and is private. It is created in the constructor and modified on cursor movement. The code is more complicated than I now like - because I was trying to accomodate Rois added to the Overlay by other processes. Now - it essentially removes all of its known Roi's and adds new ones. The higher level code (at the top) is more fascist. It creates a new, virgin Overlay and "sets" it as the one and only Overlay. Both sections of my code use ImagePlus.setOverlay(). It seems clear to me that the setOverlay() in the high level code completely nukes any previous Overlay attached to this ImagePlus. But now...the ImagePlus is wrapped in an ImageStack, and that is displayed in a StackWindow (even though there is - in these tests - only 1 image). It occurs to me that either ImageStack or StackWindow might somehow cache the Overlay at some point in time. I can experiment to try to determine when this might be. (...testing...it seems to be cached immediately before the gridOverlay is established). My current theory is that "Duplicate" and "Save As" (and "Flatten", I think...testing....yes! Image->Overlay->Flatten shows the cursorOverlay!) somehow use a cached Overlay (inside either ImageStack or StackWindow). The effect as seen by the user is: a) the cursor behaves normally... b) when a grid is created, the cursor Rois disappear and the gridOverlay appears c) "Duplicate" produces an image with the cursor Overlay ! d) moving the cursor in the window (with SHIFT) triggers the cursorOverlay and the gridOverlay disappers - this is what I expect. We now have two images open on the screen - my original StackWindow showing ONLY the gridOverlay, and the new "duplicate" image which is identical in every way EXCEPT that it shows the old cursorOverlay. Certainly "surprising" behavior! fortunately for my weekend - Plugins->Utilities->Capture Image produces a new window showing the image with the gridOverlay (as expected). It is at screen resolution and is an RGB image - but that's just fine for this application. If it matters - the original image is 768x768x32bits. The "captured" image is 768x768xRGB Am I perhaps confused about what ImagePlus.setOverlay() does? I was under the impression that it completely replaces any existing Overlay and installs a brand new one. That is the effect I see on the screen - until I try "Duplicate", "Save As", or "Flatten". Somehow they all manage to find the old Overlay. Is there some sort of "update" call that I'm missing? Ah...in my cursor-handling code, I do call "updateAndDraw()", but in my gridOverlay code, I just "setOverlay". It appears on the screen, so I thought I was done. Do I need to do anything else? ...this looks promising... This is also good news because if it only involves changes to the top-level code, I have an easier maintenance task. Changing the lower level code for the ImagePlus extension would cause ripples. So...bottom line - what is the PROPER Java code to tell an ImagePlus to rip out an existing Overlay and install a new one. So that it is both displayed AND noticed by "Duplicate", et al. Time for turkey... -- Kenneth Sloan [hidden email] Vision is the art of seeing what is invisible to others. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Hi Kenneth,
looking at the code again, there *are* two places where the overlay is kept: Both the ImagePlus and the ImageCanvas can store an overlay. The ImagePlus stores the overlay only if there is no canvas; I guess that this is meant for invisible images in BatchMode macros etc. So, could it be that your code overrides ImagePlus.getCanvas()? Or maybe there is no canvas when one of the overlays is created? (typically, this is the case when the image is not displayed yet). Michael ________________________________________________________________ On 28.11.19 22:58, Kenneth Sloan wrote: > The new Overlay is set by: (approximate...I'm seeing some sloppiness in my actual code that needs to be cleaned up - this is y best effort at describing the actual EFFECT - but I could be mistaken) > > ==================================================================== > // pre-condition - imagePlus may already have an Overlay present > > ...code to create ArrayList<Roi> gridRoiList > > gridOverlay = new Overlay(); // brand new, virgin Overlay > for(Roi roi : gridRoiList) gridOverlay.add(roi); > imagePlus.setOverlay(gridOverlay); > ==================================================================== > > At this point, the displayed image is perfect. ONLY the new Overlay is displayed. > > Now...the complication...the ImagePlus in question is my own EXTENSION to ImagePlus, which also manipulates the overlay. When that happens, the relevant code is: > > > ========================================================================= > for(Roi r : this.cursorRoiList) this.cursoerOverlay.add(r ); > setOverlay(this.cursorOverlay); > updateAndDraw(); > ========================================================================= > > 'cursorOverlay' is maintained by the imagePlus extension and is private. It is created in the constructor and modified on cursor movement. The code is more complicated than I now like - because I was trying to accomodate Rois added to the Overlay by other processes. Now - it essentially removes all of its known Roi's and adds new ones. > > The higher level code (at the top) is more fascist. It creates a new, virgin Overlay and "sets" it as the one and only Overlay. > > Both sections of my code use ImagePlus.setOverlay(). It seems clear to me that the setOverlay() in the high level code completely nukes any previous Overlay attached to this ImagePlus. > > But now...the ImagePlus is wrapped in an ImageStack, and that is displayed in a StackWindow (even though there is - in these tests - only 1 image). It occurs to me that either ImageStack or StackWindow might somehow cache the Overlay at some point in time. > I can experiment to try to determine when this might be. (...testing...it seems to be cached immediately before the gridOverlay is established). > > My current theory is that "Duplicate" and "Save As" (and "Flatten", I think...testing....yes! Image->Overlay->Flatten shows the cursorOverlay!) somehow use a cached Overlay (inside either ImageStack or StackWindow). > > The effect as seen by the user is: > > a) the cursor behaves normally... > b) when a grid is created, the cursor Rois disappear and the gridOverlay appears > c) "Duplicate" produces an image with the cursor Overlay ! > d) moving the cursor in the window (with SHIFT) triggers the cursorOverlay and the gridOverlay disappers - this > is what I expect. > > We now have two images open on the screen - my original StackWindow showing ONLY the gridOverlay, and the new "duplicate" image which is identical in every way EXCEPT that it shows the old cursorOverlay. > > Certainly "surprising" behavior! > > fortunately for my weekend - Plugins->Utilities->Capture Image produces a new window showing the image with the gridOverlay (as expected). It is at screen resolution and is an RGB image - but that's just fine for this application. > > If it matters - the original image is 768x768x32bits. The "captured" image is 768x768xRGB > > Am I perhaps confused about what ImagePlus.setOverlay() does? I was under the impression that it completely replaces any existing Overlay and installs a brand new one. That is the effect I see on the screen - until I try "Duplicate", "Save As", or "Flatten". Somehow they all manage to find the old Overlay. Is there some sort of "update" call that I'm missing? > > Ah...in my cursor-handling code, I do call "updateAndDraw()", but in my gridOverlay code, I just "setOverlay". It appears on the screen, so I thought I was done. Do I need to do anything else? > > ...this looks promising... > > This is also good news because if it only involves changes to the top-level code, I have an easier maintenance task. Changing the lower level code for the ImagePlus extension would cause ripples. > > So...bottom line - what is the PROPER Java code to tell an ImagePlus to rip out an existing Overlay and install a new one. So that it is both displayed AND noticed by "Duplicate", et al. > > Time for turkey... > > -- > Kenneth Sloan > [hidden email] > Vision is the art of seeing what is invisible to others. > > -- > ImageJ mailing list: http://imagej.nih.gov/ij/list.html > -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Michael-
We're getting warmer! I'm relieved to find that there *are* two Overlays stored. I was only familiar with interacting with Overlays via ImagePlus, and (naturally?) assumed that there was only one. To answer your question - no - my code does not override ImagePlus.getCanvas(). But - yes - it does create one Overlay during construction - which is before the ImagePlus is displayed. This was a design decision made by someone else, years ago. I'm not sure it's either correct or incorrect. So...I'm guessing that "Duplicate" and friends will use the Overlay stored with the ImagePlus, while my high-level program is manipulating BOTH Overlays (one referenced through the ImagePlus and the other which is replaced periodically while the Canvas is active). The gridOverlay is manipulated AFTER display of the StackWindow. Can it be that subsequent calls to ImagePlus.setOverlay() do NOT disturb the pre-existing Overlay when there *is* a Canvas? That actually makes sense, given the behavior. The cursor code creates one Overlay and modifies it incrementally. That one Overlay object may be stored (by reference) in the ImagePlus when my ImagePlus extension is created. Note that my ImagePlus extension code maintains a single Overlay variable. It is constructed, and a setOverlay() call is made BEFORE the ImagePlus is displayed. Subsequently, this code MODIFIES that Overlay object, and does more setOverlay() calls using it. I'm guessing that the object is cached. The subsequent modifications change the one referenced by the ImagePlus - and are also stored in the Canvas (once it is displayed). So, calls to ImagePlus.setOverlay() made AFTER the StackWindow is displayed will cause the new Overlay to be stored in the Canvas. Calls made using the cursorOverlay (the one created by my ImagePlus extension) are stored in the Canvas - but the changes are also visible through the reference stored in the ImagePlus. Calls made by the high-level code change ONLY the Overlay stored in the Canvas. This makes the Overlay stored in the ImagePlus INVISIBLE - but does not change that version. At first glance, I would consider this a bug. At the very least it is unexpected behavior. All of my calls are to ImagePlus.setOverlay(). I think it is reasonable for the user programmer (that would be me) to assume that there is one Overlay associated with an ImagePlus. Instead (if this model is correct), there is one Overlay associated with the ImagePlus which is used when there is a Canvas...and another which is used when the Canvas is not present (or is not necessary for the current operation). I'm not at all sure how to fix this - but armed with this information I suspect I can work around it. The question is: can I do that without modifying my ImagePlus extension. That looks difficult. Can you think of any way to update the Overlay stored with the ImagePlus when there is, in fact, a Canvas? Frankly, it seems to me that a call to ImagePlus.setOverlay() *should* update the Overlay stored with the ImagePlus (and also the one stored with the Canvas). Or, perhaps it should make the saved Overlay null WHEN the Canvas is created. I can't think of any reason to maintain inconsistent Overlays - esp. when this is not visible through the API. Perhaps my strategy will be for my high-level code to use ImagePlus.getOverlay() to fetch the existing Overlay and modify it - instead of trying to replace it. I'll try that...tomorrow. There's a bunch of code there that needs to be smoothed out anyway. Thanks for your help - I think you found the key fact. The rest is just a Small Matter Of Programming. The good news is that Plugins->Utilities->Capture Image does the "right" thing, and uses the Overlay referenced by the Canvas. So, *my* user is happy... -- Kenneth Sloan [hidden email] Vision is the art of seeing what is invisible to others. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Success!
mea culpa! It was my fault. In my extension to ImagePlus (call it MyImagePlus), someone (perhaps me, perhaps an earlier author) maintained a private copy of an Overlay used to draw a frame and cursor on the image. The method getOverlay() was overridden to return this cached Overlay. I suspect that "Duplicate" and friends call MyImagePlus.getOverlay() to get the Overlay, while Plugins->Utilities->Capture Image deals with the image actually displayed on screen. My user-level code was calling ImagePlus.setOverlay() (which was NOT overridden in MyImagePlus) and changing what was displayed on the screen. This was invisible to MyImagePlus - and thus invisible to "Duplicate" and friends. The good news is that I took this opportunity to significantly clean up the Overlay handling code in MyImagePlus and the user-level program. Most of this cleanup had nothing to do with this issue - but clean-up is always good. In retrospect, I probably could have fixed this by simply removing the override of getOverlay(). But...I didn't really understand what was going on until AFTER I had cleaned everything up. Many thanks to Michael for pointing me in the right direction. My apologies for suggesting that this demonstrated a problem with ImagePlus *sometimes* saving its own copy of an Overlay and *sometimes* pushing it into ImageCanvas. That may still bear looking into - but I no longer think it was any part of the cause of my problems. My current approach is to identify ONE location where ImagePlus.setOverlay() needs to be called, and make all other modifications by calling ImagePlus.getOverlay() to fetch the current Overlay and then manipulating the ROIs attached to that Overlay. No ImagePlus.setOverlay() is necessary - but ImagePlus.updateAndDraw() does seem to be necessary when adding new ROIs. Overlay.clear() appears to have immediate effect. -- Kenneth Sloan [hidden email] Vision is the art of seeing what is invisible to others. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Free forum by Nabble | Edit this page |