cicada 0.9.4-java → 0.9.5-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/cicada.rb +0 -3
- data/lib/cicada/aberration_map.rb +2 -20
- data/lib/cicada/cicada_main.rb +44 -234
- data/lib/cicada/correction/correction.rb +1 -94
- data/lib/cicada/correction/in_situ_correction.rb +67 -0
- data/lib/cicada/correction/position_corrector.rb +14 -164
- data/lib/cicada/correction/unable_to_correct_error.rb +30 -0
- data/lib/cicada/file_interaction.rb +5 -98
- data/lib/cicada/fitting/p3d_fitter.rb +3 -45
- data/lib/cicada/mutable_matrix.rb +0 -21
- data/lib/cicada/version.rb +1 -5
- data/spec/cicada/cicada_main_spec.rb +62 -0
- data/spec/cicada/correction/position_corrector_spec.rb +3 -4
- data/spec/spec_helper.rb +3 -5
- metadata +28 -37
@@ -0,0 +1,30 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2013 Colin J. Fuller
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the Software), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
# SOFTWARE.
|
21
|
+
#++
|
22
|
+
|
23
|
+
module Cicada
|
24
|
+
##
|
25
|
+
# An error indicating that a position cannot be corrected (possibly due to incomplete
|
26
|
+
# coverage in the correction dataset).
|
27
|
+
class UnableToCorrectError < StandardError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -55,28 +55,18 @@ module Cicada
|
|
55
55
|
# image objects.
|
56
56
|
#
|
57
57
|
def self.serialize_image_objects(image_objects)
|
58
|
-
|
59
58
|
doc = REXML::Document.new
|
60
|
-
|
61
|
-
|
62
59
|
doc.add_element "root"
|
63
60
|
|
64
61
|
image_objects.each do |iobj|
|
65
|
-
|
66
62
|
in_doc = REXML::Document.new iobj.writeToXMLString
|
67
|
-
|
68
63
|
in_doc.root.elements[1, "serialized_form"].text = Base64.encode64(Marshal.dump(iobj))
|
69
|
-
|
70
64
|
doc.root.add in_doc.elements[1,"image_object"]
|
71
|
-
|
72
65
|
end
|
73
66
|
|
74
67
|
output = ""
|
75
|
-
|
76
68
|
doc.write(output, 2)
|
77
|
-
|
78
69
|
output
|
79
|
-
|
80
70
|
end
|
81
71
|
|
82
72
|
##
|
@@ -89,15 +79,7 @@ module Cicada
|
|
89
79
|
# @return [ImageObject] the encoded ImageObject
|
90
80
|
#
|
91
81
|
def self.image_object_from_bytes(bin_data)
|
92
|
-
|
93
82
|
Marshal.load(bin_data)
|
94
|
-
|
95
|
-
#j_bytes = bin_data.to_java_bytes
|
96
|
-
|
97
|
-
#oi = Java::java.io.ObjectInputStream.new(Java::java.io.ByteArrayInputStream.new(j_bytes))
|
98
|
-
|
99
|
-
#oi.readObject
|
100
|
-
|
101
83
|
end
|
102
84
|
|
103
85
|
##
|
@@ -109,23 +91,16 @@ module Cicada
|
|
109
91
|
# @return [Array<ImageObject>] the image objects encoded in the string
|
110
92
|
#
|
111
93
|
def self.unserialize_image_objects(data)
|
112
|
-
|
113
94
|
objs = []
|
114
|
-
|
115
95
|
doc = REXML::Document.new data
|
116
96
|
|
117
97
|
doc.elements.each("*/image_object/serialized_form") do |el|
|
118
|
-
|
119
98
|
bin_data = Base64.decode64(el.text)
|
120
|
-
|
121
99
|
objs << image_object_from_bytes(bin_data)
|
122
|
-
|
123
100
|
end
|
124
101
|
|
125
102
|
objs
|
126
|
-
|
127
103
|
end
|
128
|
-
|
129
104
|
end
|
130
105
|
|
131
106
|
|
@@ -133,7 +108,6 @@ module Cicada
|
|
133
108
|
# A collection of methods for interacting with input and output files for cicada.
|
134
109
|
#
|
135
110
|
class FileInteraction
|
136
|
-
|
137
111
|
# parameters required by the methods in this class
|
138
112
|
REQUIRED_PARAMETERS = [:dirname_set, :basename_set, :mask_relative_dirname, :mask_extra_extension, :data_directory, :correction_date, :output_positions_to_directory]
|
139
113
|
|
@@ -155,7 +129,6 @@ module Cicada
|
|
155
129
|
# separator used in the parameter file for multiple files, directories, etc.
|
156
130
|
MULTI_NAME_SEP = ","
|
157
131
|
|
158
|
-
|
159
132
|
##
|
160
133
|
# Loads an image from the specified file.
|
161
134
|
#
|
@@ -164,12 +137,9 @@ module Cicada
|
|
164
137
|
# @return [ReadOnlyImage] the image at the specified filename
|
165
138
|
#
|
166
139
|
def self.load_image(image_fn)
|
167
|
-
|
168
140
|
RImageAnalysisTools.get_image(image_fn)
|
169
|
-
|
170
141
|
end
|
171
142
|
|
172
|
-
|
173
143
|
##
|
174
144
|
# Gets the filename to which / from which image object positions will be written /
|
175
145
|
# read from a parameter dictionary.
|
@@ -182,7 +152,6 @@ module Cicada
|
|
182
152
|
File.expand_path(p[:basename_set].split(MULTI_NAME_SEP)[0] + POS_XML_EXTENSION, dir)
|
183
153
|
end
|
184
154
|
|
185
|
-
|
186
155
|
##
|
187
156
|
# Gets the filename to which human-friendly-formatted object positions will be written.
|
188
157
|
#
|
@@ -195,7 +164,6 @@ module Cicada
|
|
195
164
|
File.expand_path(p[:basename_set].split(MULTI_NAME_SEP)[0] + POS_HUMAN_EXTENSION, dir)
|
196
165
|
end
|
197
166
|
|
198
|
-
|
199
167
|
##
|
200
168
|
# Gets the filename of data to use for in situ correction from a parameter dictionary.
|
201
169
|
#
|
@@ -205,7 +173,7 @@ module Cicada
|
|
205
173
|
# @return [String] the absolute path to the in situ correction data file
|
206
174
|
#
|
207
175
|
def self.in_situ_corr_data_filename(p)
|
208
|
-
dir = [:data_directory]
|
176
|
+
dir = p[:data_directory]
|
209
177
|
File.expand_path(p[:in_situ_aberr_corr_basename_set].split(MULTI_NAME_SEP)[0] + POS_XML_EXTENSION, dir)
|
210
178
|
end
|
211
179
|
|
@@ -229,15 +197,11 @@ module Cicada
|
|
229
197
|
# @return [Array<ImageObject>] the image objects contained in the file.
|
230
198
|
#
|
231
199
|
def self.unserialize_position_data_file(fn)
|
232
|
-
|
233
200
|
data_str = nil
|
234
|
-
|
235
201
|
File.open(fn) do |f|
|
236
202
|
data_str = f.read
|
237
203
|
end
|
238
|
-
|
239
204
|
Serialization.unserialize_image_objects(data_str)
|
240
|
-
|
241
205
|
end
|
242
206
|
|
243
207
|
##
|
@@ -248,11 +212,8 @@ module Cicada
|
|
248
212
|
# @return [Array<ImageObject>] the image objects associated with the analysis
|
249
213
|
#
|
250
214
|
def self.read_position_data(p)
|
251
|
-
|
252
215
|
fn = FileInteraction.position_data_filename(p)
|
253
|
-
|
254
216
|
FileInteraction.unserialize_position_data_file(fn)
|
255
|
-
|
256
217
|
end
|
257
218
|
|
258
219
|
##
|
@@ -265,11 +226,8 @@ module Cicada
|
|
265
226
|
# @return [Array<ImageObject>] the image objects for in situ correction associated with the analysis
|
266
227
|
#
|
267
228
|
def self.read_in_situ_corr_data(p)
|
268
|
-
|
269
229
|
fn = FileInteraction.in_situ_corr_data_filename(p)
|
270
|
-
|
271
230
|
FileInteraction.unserialize_position_data_file(fn)
|
272
|
-
|
273
231
|
end
|
274
232
|
|
275
233
|
##
|
@@ -281,35 +239,22 @@ module Cicada
|
|
281
239
|
# which return each image's filename and its paired mask's filename respectively.
|
282
240
|
#
|
283
241
|
def self.list_files(p)
|
284
|
-
|
285
242
|
dirnames = p[:dirname_set].split(MULTI_NAME_SEP)
|
286
243
|
basenames = p[:basename_set].split(MULTI_NAME_SEP)
|
287
|
-
|
288
244
|
image_sets = []
|
289
245
|
|
290
246
|
dirnames.each do |d|
|
291
|
-
|
292
247
|
mask_dirname = File.join(d, p[:mask_relative_dirname])
|
293
|
-
|
294
248
|
Dir.foreach(d) do |f|
|
295
|
-
|
296
|
-
if basenames.any? { |e| f.match(e) } then
|
297
|
-
|
249
|
+
if basenames.any? { |e| f.match(e) } then
|
298
250
|
im = File.expand_path(f, d)
|
299
251
|
msk = File.expand_path(f + p[:mask_extra_extension], mask_dirname)
|
300
|
-
|
301
|
-
current = OpenStruct.new(image_fn: im, mask_fn: msk)
|
302
|
-
|
252
|
+
current = OpenStruct.new(image_fn: im, mask_fn: msk)
|
303
253
|
image_sets << current
|
304
|
-
|
305
254
|
end
|
306
|
-
|
307
255
|
end
|
308
|
-
|
309
|
-
end
|
310
|
-
|
256
|
+
end
|
311
257
|
image_sets
|
312
|
-
|
313
258
|
end
|
314
259
|
|
315
260
|
##
|
@@ -321,15 +266,10 @@ module Cicada
|
|
321
266
|
# @return [void]
|
322
267
|
#
|
323
268
|
def self.write_position_data(image_objects, p)
|
324
|
-
|
325
269
|
fn = position_data_filename(p)
|
326
|
-
|
327
270
|
write_position_data_file(image_objects,fn)
|
328
|
-
|
329
271
|
fn2 = human_friendly_position_data_filename(p)
|
330
|
-
|
331
|
-
write_human_friendly_position_data_file(image_objects, fn2)
|
332
|
-
|
272
|
+
write_human_friendly_position_data_file(image_objects, fn2)
|
333
273
|
end
|
334
274
|
|
335
275
|
##
|
@@ -341,13 +281,9 @@ module Cicada
|
|
341
281
|
# @return [void]
|
342
282
|
#
|
343
283
|
def self.write_position_data_file(image_objects, fn)
|
344
|
-
|
345
284
|
File.open(fn, 'w') do |f|
|
346
|
-
|
347
285
|
f.write(Serialization.serialize_image_objects(image_objects))
|
348
|
-
|
349
286
|
end
|
350
|
-
|
351
287
|
end
|
352
288
|
|
353
289
|
##
|
@@ -357,39 +293,25 @@ module Cicada
|
|
357
293
|
# @see write_position_data_file
|
358
294
|
#
|
359
295
|
def self.write_human_friendly_position_data_file(image_objects, fn)
|
360
|
-
|
361
296
|
CSV.open(fn, 'wb') do |csv|
|
362
|
-
|
363
297
|
obj = image_objects[0]
|
364
|
-
|
365
298
|
n_channels = obj.getFitParametersByChannel.size
|
366
|
-
|
367
299
|
headers = ["object_id"]
|
368
300
|
n_channels.times do |i|
|
369
301
|
headers.concat(["pos#{i}_x", "pos#{i}_y", "pos#{i}_z"])
|
370
302
|
end
|
371
|
-
|
372
303
|
csv << headers
|
373
304
|
|
374
305
|
image_objects.each do |im_obj|
|
375
|
-
|
376
306
|
row = [im_obj.getLabel]
|
377
|
-
|
378
307
|
n_channels.times do |i|
|
379
|
-
|
380
308
|
row.concat(im_obj.getPositionForChannel(i).toArray)
|
381
|
-
|
382
309
|
end
|
383
|
-
|
384
310
|
csv << row
|
385
|
-
|
386
311
|
end
|
387
|
-
|
388
312
|
end
|
389
|
-
|
390
313
|
end
|
391
314
|
|
392
|
-
|
393
315
|
##
|
394
316
|
# Gets the filename for storing/reading the correction based upon the supplied parameter dictionary.
|
395
317
|
#
|
@@ -398,12 +320,9 @@ module Cicada
|
|
398
320
|
# @return [String] the filename for the correction file.
|
399
321
|
#
|
400
322
|
def self.correction_filename(p)
|
401
|
-
|
402
323
|
dir = p[:data_directory]
|
403
324
|
fn = p[:correction_date]
|
404
|
-
|
405
325
|
File.expand_path(fn + CORR_XML_EXTENSION, dir)
|
406
|
-
|
407
326
|
end
|
408
327
|
|
409
328
|
##
|
@@ -415,25 +334,13 @@ module Cicada
|
|
415
334
|
# @return [void]
|
416
335
|
#
|
417
336
|
def self.write_differences(diffs, p)
|
418
|
-
|
419
337
|
dirname = p[:output_positions_to_directory]
|
420
|
-
|
421
338
|
fn = File.expand_path(p[:basename_set] + DIFFS_TXT_EXTENSION, dirname)
|
422
|
-
|
423
339
|
File.open(fn, 'w') do |f|
|
424
|
-
|
425
340
|
diffs.each do |d|
|
426
|
-
|
427
341
|
f.puts(d.to_s)
|
428
|
-
|
429
342
|
end
|
430
|
-
|
431
343
|
end
|
432
|
-
|
433
344
|
end
|
434
|
-
|
435
345
|
end
|
436
|
-
|
437
346
|
end
|
438
|
-
|
439
|
-
|
@@ -23,7 +23,6 @@
|
|
23
23
|
# * ***** END LICENSE BLOCK ***** */
|
24
24
|
|
25
25
|
require 'rimageanalysistools'
|
26
|
-
|
27
26
|
require 'facets/math/mean'
|
28
27
|
require 'facets/math/std'
|
29
28
|
|
@@ -34,7 +33,6 @@ module Cicada
|
|
34
33
|
# to some distribution.
|
35
34
|
#
|
36
35
|
class DistributionFitter
|
37
|
-
|
38
36
|
attr_accessor :parameters
|
39
37
|
|
40
38
|
##
|
@@ -44,9 +42,7 @@ module Cicada
|
|
44
42
|
# @param [ParameterDictionary, Hash] params a hash-like object containing the parameters
|
45
43
|
#
|
46
44
|
def initialize(params)
|
47
|
-
|
48
45
|
@parameters = params
|
49
|
-
|
50
46
|
end
|
51
47
|
|
52
48
|
##
|
@@ -63,7 +59,6 @@ module Cicada
|
|
63
59
|
def fit(objects, diffs)
|
64
60
|
nil
|
65
61
|
end
|
66
|
-
|
67
62
|
end
|
68
63
|
|
69
64
|
##
|
@@ -74,24 +69,20 @@ module Cicada
|
|
74
69
|
#
|
75
70
|
#
|
76
71
|
class P3DObjectiveFunction
|
77
|
-
|
78
72
|
include Java::edu.stanford.cfuller.imageanalysistools.fitting.ObjectiveFunction
|
79
73
|
|
80
74
|
##
|
81
75
|
# Constructs an empty P3DObjectiveFunction.
|
82
76
|
#
|
83
77
|
def initialize
|
84
|
-
|
85
78
|
@r = nil
|
86
79
|
@s = nil
|
87
80
|
@min_prob = nil
|
88
81
|
@use_min_prob = false
|
89
82
|
@should_fit_s = true
|
90
|
-
|
91
83
|
end
|
92
84
|
|
93
85
|
attr_accessor :r, :use_min_prob, :should_fit_s
|
94
|
-
|
95
86
|
attr_reader :s, :min_prob
|
96
87
|
|
97
88
|
##
|
@@ -117,10 +108,8 @@ module Cicada
|
|
117
108
|
# @return [void]
|
118
109
|
#
|
119
110
|
def min_prob=(min_prob)
|
120
|
-
|
121
111
|
@min_prob = min_prob
|
122
112
|
@use_min_prob = true
|
123
|
-
|
124
113
|
end
|
125
114
|
|
126
115
|
##
|
@@ -133,9 +122,7 @@ module Cicada
|
|
133
122
|
# @return [Float] the probability density at the given point
|
134
123
|
#
|
135
124
|
def p3d(r, m, s)
|
136
|
-
|
137
125
|
(Math.sqrt(2.0/Math::PI)*r/(2*m*s))*(Math.exp(-1 * (m-r)**2/(2*s**2)) - Math.exp( -1 * (m+r)**2/(2*s**2)))
|
138
|
-
|
139
126
|
end
|
140
127
|
|
141
128
|
##
|
@@ -148,47 +135,32 @@ module Cicada
|
|
148
135
|
# @return [Float] the negative log-likelihood of the data.
|
149
136
|
#
|
150
137
|
def evaluate(point)
|
151
|
-
|
152
138
|
point = point.toArray unless point.is_a? Array
|
153
|
-
|
154
139
|
m = point[0]
|
155
140
|
s = point[1]
|
156
141
|
s = @s unless @should_fit_s
|
157
|
-
|
158
142
|
return Float::MAX if (m < 0 or s < 0)
|
159
143
|
|
160
144
|
r.reduce(0.0) do |sum, ri|
|
161
|
-
|
162
145
|
temp_neg_log_p = -1.0*Math.log( p3d(ri, m, s))
|
163
|
-
|
164
|
-
if (@use_min_prob and temp_neg_log_p > @min_prob) then
|
165
|
-
|
146
|
+
if (@use_min_prob and temp_neg_log_p > @min_prob) then
|
166
147
|
sum + @min_prob
|
167
|
-
|
168
148
|
else
|
169
|
-
|
170
149
|
sum + temp_neg_log_p
|
171
|
-
|
172
150
|
end
|
173
|
-
|
174
|
-
end
|
175
|
-
|
151
|
+
end
|
176
152
|
end
|
177
|
-
|
178
153
|
end
|
179
|
-
|
180
154
|
|
181
155
|
##
|
182
156
|
# A distribution fitter that fits data to a P3D distribution.
|
183
157
|
#
|
184
158
|
class P3DFitter < DistributionFitter
|
185
|
-
|
186
159
|
# parameters required by the methods in this class
|
187
160
|
REQUIRED_PARAMETERS = []
|
188
161
|
|
189
162
|
# parmeters used but not required in this class or only required for optional functionality
|
190
163
|
OPTIONAL_PARAMETERS = [:robust_p3d_fit_cutoff]
|
191
|
-
|
192
164
|
|
193
165
|
##
|
194
166
|
# Fits the P3D mean- and standard-deviation-like parameters to the data.
|
@@ -199,36 +171,22 @@ module Cicada
|
|
199
171
|
# @return [Array] a two-element array containing the mean- and standard-deviation-like parameters.
|
200
172
|
#
|
201
173
|
def fit(objects, diffs)
|
202
|
-
|
203
174
|
of = P3DObjectiveFunction.new
|
204
|
-
|
205
175
|
of.r = diffs
|
206
|
-
|
207
176
|
tol = 1e-12
|
208
|
-
|
209
177
|
nmm = Java::edu.stanford.cfuller.imageanalysistools.fitting.NelderMeadMinimizer.new(tol)
|
210
|
-
|
211
178
|
initial_mean = Math.mean(diffs)
|
212
|
-
|
213
179
|
initial_width = Math.std(diffs)
|
214
|
-
|
215
180
|
starting_point = Java::org.apache.commons.math3.linear.ArrayRealVector.new(2, 0.0)
|
216
|
-
|
217
181
|
starting_point.setEntry(0, initial_mean)
|
218
182
|
starting_point.setEntry(1, initial_width)
|
219
|
-
|
220
|
-
if @parameters[:robust_p3d_fit_cutoff] then
|
221
|
-
|
183
|
+
if @parameters[:robust_p3d_fit_cutoff] then
|
222
184
|
of.min_prob= @parmaeters[:robust_p3d_fit_cutoff].to_f
|
223
|
-
|
224
185
|
end
|
225
186
|
|
226
187
|
nmm.optimize(of, starting_point).toArray.to_a
|
227
|
-
|
228
188
|
end
|
229
|
-
|
230
189
|
end
|
231
|
-
|
232
190
|
end
|
233
191
|
|
234
192
|
|