Fiji's java GUI programming: undo the last from the shift-added multiple ROIs

I use different selection tools to draw many ROIs one-by-one on an image by pressing the shift button by hand. Sometimes I accidently make a mistake and draw a wrong ROI, and I cannot find a way to undo the last ROI. The only way is to lost all the ROIs and start from beginning. Is there a programming way to undo-the last added ROI but remains the other ROIs? Although add to the ROI manager list is a solution, but it takes more effort if the ROIs are quite a lot.

What I can thought is add a callback to the canvas event of mouse-up that trigger a function to memorize the two snapshot of ROIs. If the last ROI is wrong, just click a button to restore a step earlier.

I was thinking using matlab’s java programming to accomplish it.

How does it take more effort? You know you can press the T key to add each ROI after drawing it, right?

I would strongly urge you not to put MATLAB into the mix. Just improve the ImageJ code to do what you want. And if it works well in the general case, you could contribute your fix upstream.

If I add to ROI manager, then it goes away from image, and I cannot tell whether I have draw this roi or not, since there are dozens of random circles to draw.

My programme is heavily builded above ij and FIJI plugins plus GUI automation. I’m not familiar with java programming, so I use Matlab to talk to java component of ij.

Below is the callback function I wrote

function memorize_update_ROIs(aImagePlus)
if ~nargin
    IJ = ij.IJ;
    aImagePlus = IJ.getImage;
end
aRoi = aImagePlus.getRoi;
if isempty(aRoi)
    % just in case aimless click on image get empty roi snapshot
    return
end
% aImagePlus.setRoi(aRoi);
recentRois = evalin('base','recentRois');
nRow = size(recentRois,1);
% move 2:n to 1;n-1
recentRois(1:nRow-1,:) = recentRois(2:nRow,:);
% update bottom line
recentRois{nRow,1} = aRoi;
% overwrite base workspace
assignin('base','recentRois',recentRois);
end

You may not need the extra complexity. ROI handing in IJ is quite good out of the box.

The way to restore the lost ROI is to press Shift+E the shortcut for Edit>Selection>Restore Selection. This is also useful to, e.g., transfer ROIs between images.

It doesn’t need to. If you toggle the “Sholl All” checkbox. All the ROIs in the ROI Manager list will be visible. You can also toggle the “Labels” checkbox. This would allow you to quickly activate drawn ROis by clicking on their label.

In addition you also have the Image>Overlay commands (and respective shortcuts that allow you to stash ROIs in the non-destructive Image overlay (e.g., simply press “B” to store an ROI).

BTW, the User Guide as a dedicated section on how to handle ROIs.

2 Likes

Ah, this is indeed an easier way.
I have finish the code and found that it can restore to as many as roi status. The Shift-E seems only restore the last action.
I add a button to imagej menu bar. Click one time restore Roi status one time earlier. I can set to restore e.g. 200 most recent status. Each mouseup on the image will automatically make a snapshot.

image

1 Like

Here is the final callback code::

function restore_recent_ROIs(IJ,varargin)
if ~nargin
    IJ = ij.IJ;
end
try
    aImagePlus = IJ.getImage;
catch
    % 如果没有图片
    return
end
recentRois = evalin('base','recentRois');
nRow = size(recentRois,1);
aNewHit = max(find(~cellfun(@isempty,recentRois(:,1))));
if isempty(aNewHit)
    % no record, return
    disp(['No ROI available to restore @ ',RMDtime]);
    return
else
    % recover to last non-empty record
    aImagePlus.setRoi(recentRois{aNewHit,1});
    disp(['RESTORE an Roi record at nRow = ',num2str(aNewHit),' @ ',RMDtime]);
    % update 
    recentRois{aNewHit,1} = [];
    % overwrite base workspace
    assignin('base','recentRois',recentRois);
end
end
function memorize_update_ROIs(aImagePlus)
if ~nargin
    IJ = ij.IJ;
    aImagePlus = IJ.getImage;
end
aRoi = aImagePlus.getRoi;
if isempty(aRoi)
    % just in case aimless click on image get empty roi snapshot
    return
end
recentRois = evalin('base','recentRois');
nRow = size(recentRois,1);
aNewHit = max(find(~cellfun(@isempty,recentRois(:,1))));
if isempty(aNewHit)
    disp(['Empty Roi got by mouseUp,give up @ ',RMDtime]);
    aNewHit = 0;
end
if aNewHit < nRow
    % if bottom is not full
    recentRois{aNewHit+1,1} = aRoi;
    disp(['INSERT  an Roi record at nRow = ',num2str(aNewHit+1),' @ ',RMDtime]);
else
    % if bottom is full
    % move 2:n to 1;n-1,discard first line
    recentRois(1:nRow-1,:) = recentRois(2:nRow,:);
    % update bottom line
    recentRois{nRow,1} = aRoi;
    disp(['SWAP    an Roi  record at nRow = ',num2str(aNewHit),' @ ',RMDtime]);
end
% overwrite base workspace
assignin('base','recentRois',recentRois);
end