Applying filter to only an ROI

Hi folks,

I’m hoping to take an roi, then blur only the roi area. When I do this with a standard box, it works great, but when I use e.g an ROI from a threshold , it doesn’t reset the area outside of the ROI. I’ve tried playing around with reset() and related commands, but can’t get what I’m after. I’m probably missing something simple! Any help would be greatly appreciated.

Minimal example:

from ij import IJ, ImagePlus
from ij.gui import Roi, PolygonRoi, Overlay
from ij.plugin.filter import GaussianBlur,ThresholdToSelection
from ij.process import ImageProcessor

##load an image, create a processor, blur a box roi
blobs_imp = IJ.openImage("http://imagej.nih.gov/ij/images/blobs.gif")
blobs_imp.show()
ip = blobs_imp.getProcessor().duplicate()  

roi=Roi(28,16,80,84)
ip.setRoi(roi)
GaussianBlur().blurGaussian(ip, 8)

blur_imp=ImagePlus("box blurred", ip)
blur_imp.show()



##load an image, create a processor, blur an roi from thresholding
threshold_ip = blobs_imp.getProcessor().duplicate()  

threshold_ip.setThreshold(125, 255, ImageProcessor.NO_LUT_UPDATE)

excludedImp=ImagePlus("exclusion map", threshold_ip)
excludeROI = ThresholdToSelection.run(excludedImp)
threshold_ip.setRoi(excludeROI)
thresh_imp=ImagePlus("thresh blurred", threshold_ip)

#Add an overlay to show the region that should be blurred
overlay=Overlay()
overlay.add(excludeROI)
thresh_imp.setOverlay(overlay)

#gaussian and show
GaussianBlur().blurGaussian(threshold_ip, 8)

thresh_imp.show()


Thanks!
Jim

I think you get a composite selection (press ‘i’ on the selection to get the info).

If you add the selection to the ROI Manager you can use the “Split” action to decompose the ROI’s.

Then you can apply a filter on a single ROI.

Use the macro recorder (e.g., JavaScript) to get the commands which are quite similar to Jython.

1 Like

Thanks for pointing me in the right direction with the composite ROI and using the manager! I didn’t really know that composite ROI existed before. I’m using the ROI manager to split the ROI as you recommended, then I iterate through them, apply the Gaussian filter and use ‘reset’ to revert the unmasked pixels within the ROI bounding box.

It’s a little clunkier than I would like, especially as I’m swear it did this as default a few versions ago. But here’s the code in case anyone finds it useful.

from ij import IJ, ImagePlus
from ij.gui import Roi, PolygonRoi, Overlay
from ij.plugin.filter import GaussianBlur,ThresholdToSelection
from ij.process import ImageProcessor, ByteProcessor
from ij.plugin.frame import RoiManager
##load an image, create a processor, blur a box roi
blobs_imp = IJ.openImage("http://imagej.nih.gov/ij/images/blobs.gif")
blobs_imp.show()
ip = blobs_imp.getProcessor().duplicate()  

roi=Roi(28,16,80,84)
ip.setRoi(roi)
GaussianBlur().blurGaussian(ip, 8)

blur_imp=ImagePlus("box blurred", ip)
blur_imp.show()

rm = RoiManager.getInstance()

if not rm:
	rm = RoiManager()	

##load an image, create a processor, blur an roi from thresholding
thresh_imp=blobs_imp.duplicate()
threshold_ip = thresh_imp.getProcessor()

threshold_ip.setThreshold(125, 255, ImageProcessor.NO_LUT_UPDATE)
excluded_ip=thresh_imp.createThresholdMask()
excludedImp=ImagePlus("exclusion map", excluded_ip)
excludeROI = ThresholdToSelection.run(excludedImp)
excludedImp.show()

rm.runCommand("Deselect")
rm.runCommand("Delete") 

thresh_imp.setRoi(excludeROI)
rm.addRoi(thresh_imp.getRoi())

rm.select(0)
rm.runCommand(thresh_imp, "Split")
rois = rm.getInstance().getRoisAsArray()

for i in range(1,len(rois)):
	mask=rm.getRoi(i).getMask()
	rm.selectAndMakeVisible(thresh_imp, i)
	GaussianBlur().blurGaussian(threshold_ip, 3)
	threshold_ip.reset(mask)

#gaussian and show


thresh_imp.show()

I was trying to do what I think you want to achieve while having the macro recorder recording commands, and ended up with the following macro:

run("Boats");
setAutoThreshold("Default");
run("Create Selection");
resetThreshold();
run("Gaussian Blur...", "sigma=20");
run("Select None");

Using the BeanShell mode of the recorder, I ended up with code that was easily translatable into Groovy:

import ij.IJ

imp = IJ.openImage("https://imagej.net/images/boats.gif")
IJ.setAutoThreshold(imp, "Default")
IJ.run(imp, "Create Selection", "")
IJ.resetThreshold(imp)
IJ.run(imp, "Gaussian Blur...", "sigma=20")
IJ.run(imp, "Select None", "")
imp.show()

or Jython:

from ij import IJ

imp = IJ.openImage("https://imagej.net/images/boats.gif")
IJ.setAutoThreshold(imp, "Default")
IJ.run(imp, "Create Selection", "")
IJ.resetThreshold(imp)
IJ.run(imp, "Gaussian Blur...", "sigma=20")
IJ.run(imp, "Select None", "")
imp.show()

Is that what you’re trying to achieve?


The reason why your low-level call to blurGaussian() doesn’t work as expected might be that ImageJ does some special handling in PluginFilterRunner if the plugin SUPPORTS_MASKING and you have a mask (i.e. irregular) selection active:

A simple sequence of calls such as this one might solve it for you:

threshold_ip.snapshot()

[...] # do your processing here

threshold_ip.reset(threshold_ip.getMask())

Let us know if that helps.

2 Likes

Brilliant! As I said in my first post. I had already tried the snapshot() and reset() commands, but I couldn’t seem to make them work how I wanted before. Hence the convoluted solution…

Thank you for your help!

Now I’m using:

from ij import IJ, ImagePlus
from ij.gui import Roi
from ij.plugin.filter import GaussianBlur,ThresholdToSelection
from ij.process import ImageProcessor

##load an image, create a processor, blur a box roi
blobs_imp = IJ.openImage("http://imagej.nih.gov/ij/images/blobs.gif")
blobs_imp.show()
ip = blobs_imp.getProcessor().duplicate()  

##load an image, create a processor, blur an roi from thresholding
thresh_imp=blobs_imp.duplicate()
threshold_ip = thresh_imp.getProcessor()
thresh_imp.setTitle("blurred blobs")
threshold_ip.setThreshold(110, 255, ImageProcessor.NO_LUT_UPDATE)
excludeROI = ThresholdToSelection.run(thresh_imp)
threshold_ip.setRoi(excludeROI)

threshold_ip.snapshot()
GaussianBlur().blurGaussian(threshold_ip, 3)
threshold_ip.reset(threshold_ip.getMask())
thresh_imp.show()
1 Like