comparison imagej_basic_ashlar.py @ 0:fd8dfd64f25e draft

"planemo upload for repository https://github.com/ohsu-comp-bio/basic-illumination commit a8d2367c8c66eecfc2586a593acc8547a7f8611c-dirty"
author perssond
date Fri, 12 Mar 2021 00:13:46 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:fd8dfd64f25e
1 # @File(label="Select a slide to process") filename
2 # @File(label="Select the output location", style="directory") output_dir
3 # @String(label="Experiment name (base name for output files)") experiment_name
4 # @Float(label="Flat field smoothing parameter (0 for automatic)", value=0.1) lambda_flat
5 # @Float(label="Dark field smoothing parameter (0 for automatic)", value=0.01) lambda_dark
6
7 # Takes a slide (or other multi-series BioFormats-compatible file set) and
8 # generates flat- and dark-field correction profile images with BaSiC. The
9 # output format is two multi-series TIFF files (one for flat and one for dark)
10 # which is the input format used by Ashlar.
11
12 # Invocation for running from the commandline:
13 #
14 # ImageJ --ij2 --headless --run imagej_basic_ashlar.py "filename='input.ext',output_dir='output',experiment_name='my_experiment'"
15
16 import sys
17 from ij import IJ, WindowManager, Prefs
18 from ij.macro import Interpreter
19 from loci.plugins import BF
20 from loci.plugins.in import ImporterOptions
21 from loci.formats import ImageReader
22 from loci.formats.in import DynamicMetadataOptions
23 import BaSiC_ as Basic
24
25 import pdb
26
27
28 def main():
29
30 Interpreter.batchMode = True
31
32 if (lambda_flat == 0) ^ (lambda_dark == 0):
33 print ("ERROR: Both of lambda_flat and lambda_dark must be zero,"
34 " or both non-zero.")
35 return
36 lambda_estimate = "Automatic" if lambda_flat == 0 else "Manual"
37
38 print "Loading images..."
39
40 # For multi-scene .CZI files, we need raw tiles instead of the
41 # auto-stitched mosaic and we don't want labels or overview images. This
42 # only affects BF.openImagePlus, not direct use of the BioFormats reader
43 # classes which we also do (see below)
44 Prefs.set("bioformats.zeissczi.allow.autostitch", "false")
45 Prefs.set("bioformats.zeissczi.include.attachments", "false")
46
47 # Use BioFormats reader directly to determine dataset dimensions without
48 # reading every single image. The series count (num_images) is the one value
49 # we can't easily get any other way, but we might as well grab the others
50 # while we have the reader available.
51 dyn_options = DynamicMetadataOptions()
52 # Directly calling a BioFormats reader will not use the IJ Prefs settings
53 # so we need to pass these options explicitly.
54 dyn_options.setBoolean("zeissczi.autostitch", False)
55 dyn_options.setBoolean("zeissczi.attachments", False)
56 bfreader = ImageReader()
57 bfreader.setMetadataOptions(dyn_options)
58 bfreader.id = str(filename)
59 num_images = bfreader.seriesCount
60 num_channels = bfreader.sizeC
61 width = bfreader.sizeX
62 height = bfreader.sizeY
63 bfreader.close()
64
65 # The internal initialization of the BaSiC code fails when we invoke it via
66 # scripting, unless we explicitly set a the private 'noOfSlices' field.
67 # Since it's private, we need to use Java reflection to access it.
68 Basic_noOfSlices = Basic.getDeclaredField('noOfSlices')
69 Basic_noOfSlices.setAccessible(True)
70 basic = Basic()
71 Basic_noOfSlices.setInt(basic, num_images)
72
73 # Pre-allocate the output profile images, since we have all the dimensions.
74 ff_image = IJ.createImage("Flat-field", width, height, num_channels, 32);
75 df_image = IJ.createImage("Dark-field", width, height, num_channels, 32);
76
77 print("\n\n")
78
79 # BaSiC works on one channel at a time, so we only read the images from one
80 # channel at a time to limit memory usage.
81 for channel in range(num_channels):
82 print "Processing channel %d/%d..." % (channel + 1, num_channels)
83 print "==========================="
84
85 options = ImporterOptions()
86 options.id = str(filename)
87 options.setOpenAllSeries(True)
88 # concatenate=True gives us a single stack rather than a list of
89 # separate images.
90 options.setConcatenate(True)
91 # Limit the reader to the channel we're currently working on. This loop
92 # is mainly why we need to know num_images before opening anything.
93 for i in range(num_images):
94 options.setCBegin(i, channel)
95 options.setCEnd(i, channel)
96 # openImagePlus returns a list of images, but we expect just one (a
97 # stack).
98 input_image = BF.openImagePlus(options)[0]
99
100 # BaSiC seems to require the input image is actually the ImageJ
101 # "current" image, otherwise it prints an error and aborts.
102 WindowManager.setTempCurrentImage(input_image)
103 basic.exec(
104 input_image, None, None,
105 "Estimate shading profiles", "Estimate both flat-field and dark-field",
106 lambda_estimate, lambda_flat, lambda_dark,
107 "Ignore", "Compute shading only"
108 )
109 input_image.close()
110
111 # Copy the pixels from the BaSiC-generated profile images to the
112 # corresponding channel of our output images.
113 ff_channel = WindowManager.getImage("Flat-field:%s" % input_image.title)
114 ff_image.slice = channel + 1
115 ff_image.getProcessor().insert(ff_channel.getProcessor(), 0, 0)
116 ff_channel.close()
117 df_channel = WindowManager.getImage("Dark-field:%s" % input_image.title)
118 df_image.slice = channel + 1
119 df_image.getProcessor().insert(df_channel.getProcessor(), 0, 0)
120 df_channel.close()
121
122 print("\n\n")
123
124 template = '%s/%s-%%s.tif' % (output_dir, experiment_name)
125 ff_filename = template % 'ffp'
126 IJ.saveAsTiff(ff_image, ff_filename)
127 ff_image.close()
128 df_filename = template % 'dfp'
129 IJ.saveAsTiff(df_image, df_filename)
130 df_image.close()
131
132 print "Done!"
133
134
135 main()