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/12/08 06:55] – [Path operations] added ApacheIO FilenameUtil kota | documents:120206pyip_cooking:python_imagej_cookbook [2024/10/08 17:45] (current) – [Accessing multiple files to load image sequences] kota | ||
---|---|---|---|
Line 242: | Line 242: | ||
</ | </ | ||
- | Fiji comes with ApacheIO library, and can be used quite conveniently for disintegrating file paths. | + | Fiji comes with ApacheIO library, and can be used quite conveniently for disintegrating file paths. See [[https:// |
<code python linenums: | <code python linenums: | ||
from org.apache.commons.io import FilenameUtils | from org.apache.commons.io import FilenameUtils | ||
Line 410: | Line 410: | ||
</ | </ | ||
==== Accessing multiple files to load image sequences ==== | ==== Accessing multiple files to load image sequences ==== | ||
+ | |||
+ | A simple way is to use glob package (file not loaded in this example). | ||
+ | <code python linenums: | ||
+ | import glob, os | ||
+ | from ij.io import DirectoryChooser | ||
+ | |||
+ | srcDir = DirectoryChooser(" | ||
+ | for filename in glob.glob(os.path.join(srcDir, | ||
+ | print(os.path.basename(filename)) | ||
+ | </ | ||
Here is a cool script written by Christian Tischer for loading image series using file prefix as dictionary keys. | Here is a cool script written by Christian Tischer for loading image series using file prefix as dictionary keys. | ||
Line 787: | Line 797: | ||
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 839: | Line 893: | ||
</ | </ | ||
+ | ===== 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 968: | Line 1035: | ||
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 1001: | Line 1090: | ||
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 1047: | Line 1209: | ||
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 1781: | Line 1959: | ||
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 2203: | Line 2391: | ||
===== Plugin: MorphoLibJ ===== | ===== Plugin: MorphoLibJ ===== | ||
+ | Javadoc: [[http:// | ||
==== Distance Transform Watershed 3D ==== | ==== Distance Transform Watershed 3D ==== | ||
Line 2244: | Line 2433: | ||
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 2252: | Line 2453: | ||
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 2443: | Line 2655: | ||
===== JAVADOCS ===== | ===== JAVADOCS ===== | ||
- | * 3D ImageJ Suite [[http:// | + | * 3D ImageJ Suite |
+ | * [[http:// | ||
+ | * [[https:// | ||
* [[https:// | * [[https:// | ||
* [[https:// | * [[https:// |
documents/120206pyip_cooking/python_imagej_cookbook.1638946557.txt.gz · Last modified: 2021/12/08 06:55 by kota