documents:120206pyip_cooking:python_imagej_cookbook
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
documents:120206pyip_cooking:python_imagej_cookbook [2021/08/27 09:06] – [Merging ARFF data files in another way, train and apply classifier] kota | documents:120206pyip_cooking:python_imagej_cookbook [2022/10/16 07:12] (current) – [Using Java8 Stream] kota | ||
---|---|---|---|
Line 3: | Line 3: | ||
This page was last edited at: ~~LASTMOD~~ | This page was last edited at: ~~LASTMOD~~ | ||
- | For learning image processing using Fiji and Jython scripting, go to excellent tutorials written by Albert Cardona, such as [[https:// | + | For learning image processing using Fiji and Jython scripting, go to excellent tutorials written by Albert Cardona, such as [[https:// |
This page is like a cookbook: there are no details about how to do programming, | This page is like a cookbook: there are no details about how to do programming, | ||
Line 91: | Line 91: | ||
for j in range(imp.getHeight()): | for j in range(imp.getHeight()): | ||
+ | </ | ||
+ | |||
+ | ===== ImageJ2 / SciJava ===== | ||
+ | |||
+ | ==== Running a script from another script ==== | ||
+ | |||
+ | <code python> | ||
+ | #@ ScriptService scriptService | ||
+ | |||
+ | fullscript = "#@ String A_STRING\n" | ||
+ | "#@ Boolean (label=' | ||
+ | |||
+ | scriptmodule = scriptService.run(" | ||
+ | scriptInputmaps = scriptmodule.getInputs() | ||
+ | |||
+ | print scriptmodule.getOutputs() | ||
+ | print scriptInputmaps | ||
+ | # how can we know the dialog was Canceled? | ||
+ | print scriptmodule.isInputResolved(' | ||
</ | </ | ||
Line 222: | Line 241: | ||
print ff.getName() | print ff.getName() | ||
</ | </ | ||
+ | |||
+ | Fiji comes with ApacheIO library, and can be used quite conveniently for disintegrating file paths. See [[https:// | ||
+ | <code python linenums: | ||
+ | from org.apache.commons.io import FilenameUtils | ||
+ | |||
+ | srcpath = '/ | ||
+ | |||
+ | |||
+ | baseName = FilenameUtils.getBaseName(srcpath) | ||
+ | print " | ||
+ | |||
+ | ext = FilenameUtils.getExtension(srcpath) | ||
+ | print " | ||
+ | |||
+ | filename = FilenameUtils.getName(srcpath) | ||
+ | print "File name: ", filename | ||
+ | |||
+ | pathWOext = FilenameUtils.removeExtension(srcpath) | ||
+ | print " | ||
+ | |||
+ | # outputs | ||
+ | # | ||
+ | # Basename: | ||
+ | # Extension: | ||
+ | # File name: data.csv | ||
+ | # Fullpath without ext: / | ||
+ | </ | ||
+ | |||
+ | |||
+ | |||
==== Loading a textfile as String ==== | ==== Loading a textfile as String ==== | ||
Line 738: | Line 787: | ||
zip command creates a list of tuples from elements of arrays a and b. | zip command creates a list of tuples from elements of arrays a and b. | ||
+ | ==== Using Java8 Stream ==== | ||
+ | |||
+ | Stream-related syntax introduced from Java8 is useful for writing clear codes, but cannot be directly used in Jython. Below is a way to use StreamAPI, by introducing Jython classes implementing the Consumer interface. I took this idea from [[https:// | ||
+ | |||
+ | <code python> | ||
+ | from java.util.Arrays import asList | ||
+ | from java.util.function import Predicate, Consumer, Function | ||
+ | from java.util.stream import Collectors | ||
+ | from java.util import Arrays | ||
+ | |||
+ | |||
+ | class jc(Consumer): | ||
+ | def __init__(self, | ||
+ | self.accept=fn | ||
+ | |||
+ | class jf(Function): | ||
+ | def __init__(self, | ||
+ | self.apply = fn | ||
+ | |||
+ | class jp(Predicate): | ||
+ | def __init__(self, | ||
+ | self.test = fn | ||
+ | | ||
+ | def jprint(x): | ||
+ | print x | ||
+ | |||
+ | tt = [" | ||
+ | c = Arrays.stream(tt).count() | ||
+ | print c | ||
+ | |||
+ | print " | ||
+ | Arrays.stream(tt).forEach(jc(lambda x: jprint(" | ||
+ | |||
+ | print " | ||
+ | Arrays.stream(tt).parallel().forEach(jc(lambda x: jprint(" | ||
+ | |||
+ | print "has b?", Arrays.stream(tt).anyMatch(jp(lambda x: x==" | ||
+ | print "has z?", Arrays.stream(tt).anyMatch(jp(lambda x: x==" | ||
+ | |||
+ | # convert to Java List<> | ||
+ | jtt = Arrays.asList(tt) | ||
+ | |||
+ | jtt.stream().forEach(jc(lambda x: jprint(" | ||
+ | </ | ||
===== Event Listener ===== | ===== Event Listener ===== | ||
Line 790: | Line 883: | ||
</ | </ | ||
+ | ===== GUI: wait for user ===== | ||
+ | |||
+ | To pause the script processing and wait for the user input (e.g. creating amanual ROI), use WaitForUserDialog class. | ||
+ | |||
+ | <code python> | ||
+ | from ij.gui import WaitForUserDialog | ||
+ | |||
+ | print(" | ||
+ | wud = WaitForUserDialog(" | ||
+ | print(" | ||
+ | wud.show() | ||
+ | print(" | ||
+ | </ | ||
===== HashMap ===== | ===== HashMap ===== | ||
Line 919: | Line 1025: | ||
outimp.show() | outimp.show() | ||
</ | </ | ||
+ | |||
+ | Another example with the map function | ||
+ | |||
+ | <code python> | ||
+ | # splits multichannel-zstack hyperstack and apply zprojection | ||
+ | from ij import IJ | ||
+ | from ij.plugin import ZProjector | ||
+ | from ij.plugin import ChannelSplitter | ||
+ | |||
+ | def sumzp( imp ): | ||
+ | zp = ZProjector(imp) | ||
+ | zp.setMethod(ZProjector.SUM_METHOD) | ||
+ | zp.doProjection() | ||
+ | zpimp = zp.getProjection() | ||
+ | return zpimp | ||
+ | |||
+ | imp = IJ.getImage() | ||
+ | imps = ChannelSplitter.split( imp ) | ||
+ | zpimps = map(sumzp, imps) | ||
+ | zpimps[0].show() | ||
+ | </ | ||
+ | |||
==== Threshold to create a mask (Binary) ==== | ==== Threshold to create a mask (Binary) ==== | ||
Line 952: | Line 1080: | ||
maskimp.show() | maskimp.show() | ||
</ | </ | ||
+ | |||
+ | === Stack to Mask by a threshold value === | ||
+ | |||
+ | Here is an example script to create a mask from an 8-bit stack using intensity thresholding. | ||
+ | The threshold value is derived by the Otsu algorithm using the full stack histogram. | ||
+ | |||
+ | < | ||
+ | from ij import IJ, ImagePlus, ImageStack | ||
+ | from ij.plugin import ChannelSplitter | ||
+ | from ij.process import StackStatistics | ||
+ | from fiji.threshold import Auto_Threshold | ||
+ | |||
+ | #imp = IJ.openImage(" | ||
+ | imp = IJ.getImage() | ||
+ | imps = ChannelSplitter.split( imp ) | ||
+ | imp1 = imps[0] | ||
+ | imp1bin = imp1.duplicate() | ||
+ | |||
+ | # get auto threshold value | ||
+ | stats = StackStatistics(imp1bin) | ||
+ | histdouble = stats.histogram() | ||
+ | |||
+ | # need this conversion from double to int | ||
+ | histint = map(lambda x:int(x), histdouble) | ||
+ | th = Auto_Threshold.Otsu(histint) | ||
+ | |||
+ | for i in range(imp1bin.getStackSize()): | ||
+ | ip = imp1bin.getStack().getProcessor( i + 1) | ||
+ | ip.threshold(th) | ||
+ | |||
+ | IJ.run(imp1bin, | ||
+ | imp1bin.show() | ||
+ | </ | ||
+ | |||
+ | To do this by accessing the pixel array of the stack, here is the way. It takes a longer time than above, so this is just to show the technique to process by pixel values using float processor pixel array object. | ||
+ | |||
+ | <code python> | ||
+ | |||
+ | from ij import IJ, ImagePlus, ImageStack | ||
+ | from ij.plugin import ChannelSplitter | ||
+ | from ij.process import StackStatistics | ||
+ | from ij.process import FloatProcessor | ||
+ | from fiji.threshold import Auto_Threshold | ||
+ | import jarray | ||
+ | |||
+ | imp = IJ.openImage(" | ||
+ | #imp = IJ.getImage() | ||
+ | imps = ChannelSplitter.split( imp ) | ||
+ | imp1 = imps[0] | ||
+ | ww = imp1.getWidth() | ||
+ | hh = imp1.getHeight() | ||
+ | binstack = ImageStack( ww, hh) | ||
+ | |||
+ | # get auto threshold value | ||
+ | stats = StackStatistics(imp1) | ||
+ | histdouble = stats.histogram() | ||
+ | histint = map(lambda x:int(x), histdouble) | ||
+ | th = Auto_Threshold.Otsu(histint) | ||
+ | |||
+ | for i in range(imp1.getStackSize()): | ||
+ | slicepixA = imp1.getStack().duplicate().convertToFloat().getPixels(i + 1) | ||
+ | # pixmin = reduce(min, slicepixA) | ||
+ | # pixmax = reduce(max, slicepixA) | ||
+ | # print " | ||
+ | slicepixA = map(lambda x: 0.0 if x<th else 255.0, slicepixA) | ||
+ | fp = FloatProcessor( ww, hh, slicepixA, None) | ||
+ | bp = fp.convertToByteProcessor() | ||
+ | binstack.addSlice(str(i+1), | ||
+ | |||
+ | binimp = ImagePlus(" | ||
+ | binimp.show() | ||
+ | </ | ||
+ | |||
==== ROI manager ==== | ==== ROI manager ==== | ||
Line 998: | Line 1199: | ||
istats = ip.getStatistics() | istats = ip.getStatistics() | ||
print istats.mean | print istats.mean | ||
+ | </ | ||
+ | |||
+ | === Saving All ROIs as a single zip file === | ||
+ | |||
+ | <code py> | ||
+ | import os, jarray | ||
+ | from ij.plugins.frame.RoiManager | ||
+ | |||
+ | outdir = "/ | ||
+ | roizipname = " | ||
+ | roizippath = os.path.join(outdir, | ||
+ | rm = RoiManager.getInstance() | ||
+ | if rm.getCount() > 0: | ||
+ | roiindex = jarray.array(range(0, | ||
+ | rm.setSelectedIndexes(roiindex) | ||
+ | rm.runCommand(' | ||
</ | </ | ||
Line 1345: | Line 1562: | ||
For more explanation about this processing, see [[http:// | For more explanation about this processing, see [[http:// | ||
+ | |||
+ | ==== Background Subtraction (Rolling Ball) ==== | ||
+ | |||
+ | Menu item [Process > Subtract Background] | ||
+ | |||
+ | <code python> | ||
+ | from ij import IJ | ||
+ | from ij.plugin.filter import BackgroundSubtracter | ||
+ | |||
+ | imp = IJ.getImage() | ||
+ | |||
+ | ip = imp.getProcessor() | ||
+ | radius = 50.0 | ||
+ | createBackground = False | ||
+ | lightBackground = False | ||
+ | useParaboloid = False | ||
+ | doPresmooth = False | ||
+ | correctCorners = False | ||
+ | |||
+ | bs = BackgroundSubtracter() | ||
+ | bs.rollingBallBackground(ip, | ||
+ | imp.updateAndDraw() | ||
+ | </ | ||
+ | |||
+ | If the image is in RGB, then use a different method (rollingBallBrightnessBackground). | ||
+ | |||
+ | For more explanation about this processing, see [[https:// | ||
==== ImageCalculator ==== | ==== ImageCalculator ==== | ||
Line 1705: | Line 1949: | ||
fullimps[0].show() | fullimps[0].show() | ||
</ | </ | ||
+ | |||
+ | If you do not want to open all images (called sereies) in multi-image CZI files, replace | ||
+ | < | ||
+ | open.setOpenAllSeries(True) | ||
+ | </ | ||
+ | with | ||
+ | < | ||
+ | options.setSeriesOn(seriesIndex, | ||
+ | </ | ||
+ | with " | ||
See here for more on metadata parsing and so on: [[https:// | See here for more on metadata parsing and so on: [[https:// | ||
Line 2127: | Line 2381: | ||
===== Plugin: MorphoLibJ ===== | ===== Plugin: MorphoLibJ ===== | ||
+ | Javadoc: [[http:// | ||
==== Distance Transform Watershed 3D ==== | ==== Distance Transform Watershed 3D ==== | ||
Line 2168: | Line 2423: | ||
outimp.setTitle(imp.getShortTitle() + " | outimp.setTitle(imp.getShortTitle() + " | ||
outimp.show() | outimp.show() | ||
+ | </ | ||
+ | |||
+ | ==== Kill Border Objects, 2D Binary image ==== | ||
+ | |||
+ | <code py> | ||
+ | from ij import IJ, ImagePlus | ||
+ | from inra.ijpb.morphology import Reconstruction | ||
+ | |||
+ | imp = IJ.getImage() #binary image | ||
+ | newip = Reconstruction.killBorders(imp.getProcessor()) | ||
+ | newimp = ImagePlus(" | ||
+ | newimp.show() | ||
</ | </ | ||
Line 2176: | Line 2443: | ||
The plugin webpage is here: [[https:// | The plugin webpage is here: [[https:// | ||
+ | |||
+ | The real power of 3D Suite is using it as a library from scripts and plugins. Many useful classes are implemented for processing, segmenting, and most notably measuring 3D objects. | ||
+ | |||
+ | Source codes are located under framagit: | ||
+ | |||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | |||
+ | The Javadoc I created (Core and Plugins are merged): | ||
+ | |||
+ | * [[https:// | ||
==== Measureing Spherical 3D ROI positions ==== | ==== Measureing Spherical 3D ROI positions ==== | ||
Line 2311: | Line 2589: | ||
See explanation in [[http:// | See explanation in [[http:// | ||
+ | |||
+ | ==== Shell Command ==== | ||
+ | |||
+ | To run Shell command in OSX, here is an example. | ||
+ | |||
+ | <code python> | ||
+ | from java.lang import Runtime | ||
+ | from java.util import Scanner | ||
+ | |||
+ | def runShellCommand( cmd ): | ||
+ | proc = Runtime.getRuntime().exec(cmd) | ||
+ | istream = proc.getInputStream() | ||
+ | scan = Scanner(istream).useDelimiter(" | ||
+ | for ss in scan: | ||
+ | print ss | ||
+ | |||
+ | |||
+ | runShellCommand( " | ||
+ | runShellCommand( "ls -la" ) | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== Is docker daemon running? ==== | ||
+ | |||
+ | Check if the docker daemon is running (): | ||
+ | |||
+ | <code python linenums: | ||
+ | from java.lang import Runtime | ||
+ | from java.util import Scanner | ||
+ | |||
+ | |||
+ | def checkDockerRunning( cmd ): | ||
+ | proc = Runtime.getRuntime().exec(cmd) | ||
+ | inputst = proc.getInputStream() | ||
+ | s = Scanner(inputst).useDelimiter(" | ||
+ | if not s.hasNext(): | ||
+ | print " | ||
+ | return False | ||
+ | for ss in s: | ||
+ | print ss | ||
+ | if ss.startswith(" | ||
+ | return True | ||
+ | else: | ||
+ | print " | ||
+ | return False | ||
+ | |||
+ | # below is for OSX. WIth win, just " | ||
+ | cmd = "/ | ||
+ | if checkDockerRunning( cmd ): | ||
+ | print " | ||
+ | else: | ||
+ | print " | ||
+ | </ | ||
===== JAVADOCS ===== | ===== JAVADOCS ===== | ||
- | * 3D ImageJ Suite [[http:// | + | * 3D ImageJ Suite |
+ | * [[http:// | ||
+ | * [[https:// | ||
* [[https:// | * [[https:// | ||
* [[https:// | * [[https:// |
documents/120206pyip_cooking/python_imagej_cookbook.txt · Last modified: 2022/10/16 07:12 by kota