cicada 0.9.0-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/bin/cicada +37 -0
- data/lib/cicada.rb +31 -0
- data/lib/cicada/cicada_main.rb +674 -0
- data/lib/cicada/correction/correction.rb +363 -0
- data/lib/cicada/correction/position_corrector.rb +501 -0
- data/lib/cicada/file_interaction.rb +377 -0
- data/lib/cicada/fitting/p3d_fitter.rb +235 -0
- data/lib/cicada/mutable_matrix.rb +133 -0
- data/lib/cicada/version.rb +33 -0
- data/spec/cicada/correction/correction_spec.rb +114 -0
- data/spec/cicada/correction/position_corrector_spec.rb +169 -0
- data/spec/cicada/file_interaction_spec.rb +58 -0
- data/spec/cicada/fitting/p3d_fitter_spec.rb +79 -0
- data/spec/cicada/mutable_matrix_spec.rb +89 -0
- data/spec/spec_helper.rb +50 -0
- metadata +137 -0
@@ -0,0 +1,377 @@
|
|
1
|
+
#--
|
2
|
+
# /* ***** BEGIN LICENSE BLOCK *****
|
3
|
+
# *
|
4
|
+
# * Copyright (c) 2012 Colin J. Fuller
|
5
|
+
# *
|
6
|
+
# * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# * of this software and associated documentation files (the Software), to deal
|
8
|
+
# * in the Software without restriction, including without limitation the rights
|
9
|
+
# * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# * copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# * furnished to do so, subject to the following conditions:
|
12
|
+
# *
|
13
|
+
# * The above copyright notice and this permission notice shall be included in
|
14
|
+
# * all copies or substantial portions of the Software.
|
15
|
+
# *
|
16
|
+
# * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
# * SOFTWARE.
|
23
|
+
# *
|
24
|
+
# * ***** END LICENSE BLOCK ***** */
|
25
|
+
#++
|
26
|
+
|
27
|
+
require 'ostruct'
|
28
|
+
require 'base64'
|
29
|
+
require 'rexml/document'
|
30
|
+
|
31
|
+
require 'rimageanalysistools'
|
32
|
+
require 'rimageanalysistools/get_image'
|
33
|
+
|
34
|
+
module Cicada
|
35
|
+
|
36
|
+
##
|
37
|
+
# Handles the serialization of the ImageObjects for storing them in a file.
|
38
|
+
#
|
39
|
+
# The serialized output will consist of an XML file describing the objects
|
40
|
+
# in human-readable form and including a binary data sectiobn containing the
|
41
|
+
# serialized object. This binary section is the only thing read back in, so
|
42
|
+
# changing the XML human-readable portion of the file manually will not affect
|
43
|
+
# the data read back in.
|
44
|
+
#
|
45
|
+
class Serialization
|
46
|
+
|
47
|
+
##
|
48
|
+
# Converts an array of ImageObjects to an XML-formatted string containing
|
49
|
+
# the serialized data.
|
50
|
+
#
|
51
|
+
# @param [Enumerable<ImageObject>] image_objects an Enumerable list of image objects
|
52
|
+
#
|
53
|
+
# @return [String] a string containing formatted XML and binary representations of the
|
54
|
+
# image objects.
|
55
|
+
#
|
56
|
+
def self.serialize_image_objects(image_objects)
|
57
|
+
|
58
|
+
doc = REXML::Document.new
|
59
|
+
|
60
|
+
|
61
|
+
doc.add_element "root"
|
62
|
+
|
63
|
+
image_objects.each do |iobj|
|
64
|
+
|
65
|
+
in_doc = REXML::Document.new iobj.writeToXMLString
|
66
|
+
|
67
|
+
in_doc.root.elements[1, "serialized_form"].text = Base64.encode64(Marshal.dump(iobj))
|
68
|
+
|
69
|
+
doc.root.add in_doc.elements[1,"image_object"]
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
output = ""
|
74
|
+
|
75
|
+
doc.write(output, 2)
|
76
|
+
|
77
|
+
output
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Restores an image object from a byte string.
|
83
|
+
#
|
84
|
+
# @param [String] bin_data the bytes representing the image object. This should be
|
85
|
+
# a standard byte string. The XML files use base64 encoding, and the data should already
|
86
|
+
# be unencoded.
|
87
|
+
#
|
88
|
+
# @return [ImageObject] the encoded ImageObject
|
89
|
+
#
|
90
|
+
def self.image_object_from_bytes(bin_data)
|
91
|
+
|
92
|
+
Marshal.load(bin_data)
|
93
|
+
|
94
|
+
#j_bytes = bin_data.to_java_bytes
|
95
|
+
|
96
|
+
#oi = Java::java.io.ObjectInputStream.new(Java::java.io.ByteArrayInputStream.new(j_bytes))
|
97
|
+
|
98
|
+
#oi.readObject
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# Restores image objects from an XML string containing their serialized representation.
|
104
|
+
# (This uses the base64 encoded binary information in the XML file, not the human readable portion.)
|
105
|
+
#
|
106
|
+
# @param [String] data the XML string
|
107
|
+
#
|
108
|
+
# @return [Array<ImageObject>] the image objects encoded in the string
|
109
|
+
#
|
110
|
+
def self.unserialize_image_objects(data)
|
111
|
+
|
112
|
+
objs = []
|
113
|
+
|
114
|
+
doc = REXML::Document.new data
|
115
|
+
|
116
|
+
doc.elements.each("*/image_object/serialized_form") do |el|
|
117
|
+
|
118
|
+
bin_data = Base64.decode64(el.text)
|
119
|
+
|
120
|
+
objs << image_object_from_bytes(bin_data)
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
objs
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
##
|
132
|
+
# A collection of methods for interacting with input and output files for cicada.
|
133
|
+
#
|
134
|
+
class FileInteraction
|
135
|
+
|
136
|
+
# parameters required by the methods in this class
|
137
|
+
REQUIRED_PARAMETERS = [:dirname_set, :basename_set, :mask_relative_dirname, :mask_extra_extension, :data_directory, :correction_date, :output_positions_to_directory]
|
138
|
+
|
139
|
+
# parmeters used but not required in this class or only required for optional functionality
|
140
|
+
OPTIONAL_PARAMETERS = [:in_situ_aberr_corr_basename_set]
|
141
|
+
|
142
|
+
# extension on position data (image object) files.
|
143
|
+
POS_XML_EXTENSION = "_position_data.xml"
|
144
|
+
|
145
|
+
# extension on the correction files
|
146
|
+
CORR_XML_EXTENSION = "_correction.xml"
|
147
|
+
|
148
|
+
# extension on the distance measurement files
|
149
|
+
DIFFS_TXT_EXTENSION = "_diffs.txt"
|
150
|
+
|
151
|
+
# separator used in the parameter file for multiple files, directories, etc.
|
152
|
+
MULTI_NAME_SEP = ","
|
153
|
+
|
154
|
+
|
155
|
+
##
|
156
|
+
# Loads an image from the specified file.
|
157
|
+
#
|
158
|
+
# @param [String] image_fn the image's filename
|
159
|
+
#
|
160
|
+
# @return [ReadOnlyImage] the image at the specified filename
|
161
|
+
#
|
162
|
+
def self.load_image(image_fn)
|
163
|
+
|
164
|
+
RImageAnalysisTools.get_image(image_fn)
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
##
|
170
|
+
# Gets the filename to which / from which image object positions will be written /
|
171
|
+
# read from a parameter dictionary.
|
172
|
+
# @param [ParameterDictionary, Hash] p a hash-like object specifying the filename for the positions.
|
173
|
+
#
|
174
|
+
# @return [String] the absolute path to the position file.
|
175
|
+
#
|
176
|
+
def self.position_data_filename(p)
|
177
|
+
dir = p[:data_directory]
|
178
|
+
File.expand_path(p[:basename_set].split(MULTI_NAME_SEP)[0] + POS_XML_EXTENSION, dir)
|
179
|
+
end
|
180
|
+
|
181
|
+
##
|
182
|
+
# Gets the filename of data to use for in situ correction from a parameter dictionary.
|
183
|
+
#
|
184
|
+
# @param [ParameterDictionary, Hash] p a hash-like object specifying the filename for the
|
185
|
+
# in situ correction data
|
186
|
+
#
|
187
|
+
# @return [String] the absolute path to the in situ correction data file
|
188
|
+
#
|
189
|
+
def self.in_situ_corr_data_filename(p)
|
190
|
+
dir = [:data_directory]
|
191
|
+
File.expand_path(p[:in_situ_aberr_corr_basename_set].split(MULTI_NAME_SEP)[0] + POS_XML_EXTENSION, dir)
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# Checks if the position data file already exists.
|
196
|
+
#
|
197
|
+
# @param [ParameterDictionary, Hash] p a hash-like object specifying the filename for the positions.
|
198
|
+
#
|
199
|
+
# @return [Boolean] whether the position data file exists.
|
200
|
+
#
|
201
|
+
def self.position_file_exists?(p)
|
202
|
+
File.exist?(FileInteraction.position_data_filename(p))
|
203
|
+
end
|
204
|
+
|
205
|
+
##
|
206
|
+
# Unserializes image object position data from a specified file using the methods in the Serialization
|
207
|
+
# class.
|
208
|
+
#
|
209
|
+
# @param [String] fn the name of the data file.
|
210
|
+
#
|
211
|
+
# @return [Array<ImageObject>] the image objects contained in the file.
|
212
|
+
#
|
213
|
+
def self.unserialize_position_data_file(fn)
|
214
|
+
|
215
|
+
data_str = nil
|
216
|
+
|
217
|
+
File.open(fn) do |f|
|
218
|
+
data_str = f.read
|
219
|
+
end
|
220
|
+
|
221
|
+
Serialization.unserialize_image_objects(data_str)
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
##
|
226
|
+
# Reads the image objects associated with an analysis specified by a parameter dictionary.
|
227
|
+
#
|
228
|
+
# @param [ParameterDictionary, Hash] p a hash-like object specifying the filename for the positions.
|
229
|
+
#
|
230
|
+
# @return [Array<ImageObject>] the image objects associated with the analysis
|
231
|
+
#
|
232
|
+
def self.read_position_data(p)
|
233
|
+
|
234
|
+
fn = FileInteraction.position_data_filename(p)
|
235
|
+
|
236
|
+
FileInteraction.unserialize_position_data_file(fn)
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
##
|
241
|
+
# Reads the image objects for in situ correction associated with an analysis specified by
|
242
|
+
# a parameter dictionary.
|
243
|
+
#
|
244
|
+
# @param [ParameterDictionary, Hash] p a hash-like object specifying the filename for the
|
245
|
+
# in situ correction data
|
246
|
+
#
|
247
|
+
# @return [Array<ImageObject>] the image objects for in situ correction associated with the analysis
|
248
|
+
#
|
249
|
+
def self.read_in_situ_corr_data(p)
|
250
|
+
|
251
|
+
fn = FileInteraction.in_situ_corr_data_filename(p)
|
252
|
+
|
253
|
+
FileInteraction.unserialize_position_data_file(fn)
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
##
|
258
|
+
# Lists all the files and masks to be analyzed given a parameter dictionary.
|
259
|
+
#
|
260
|
+
# @param [ParameterDictionary, Hash] p a hash-like object specifying the analysis
|
261
|
+
#
|
262
|
+
# @return [Array<OpenStruct>] an array of objects that respond to #image_fn and #mask_fn,
|
263
|
+
# which return each image's filename and its paired mask's filename respectively.
|
264
|
+
#
|
265
|
+
def self.list_files(p)
|
266
|
+
|
267
|
+
dirnames = p[:dirname_set].split(MULTI_NAME_SEP)
|
268
|
+
basenames = p[:basename_set].split(MULTI_NAME_SEP)
|
269
|
+
|
270
|
+
image_sets = []
|
271
|
+
|
272
|
+
dirnames.each do |d|
|
273
|
+
|
274
|
+
mask_dirname = File.join(d, p[:mask_relative_dirname])
|
275
|
+
|
276
|
+
Dir.foreach(d) do |f|
|
277
|
+
|
278
|
+
if basenames.any? { |e| f.match(e) } then
|
279
|
+
|
280
|
+
im = File.expand_path(f, d)
|
281
|
+
msk = File.expand_path(f + p[:mask_extra_extension], mask_dirname)
|
282
|
+
|
283
|
+
current = OpenStruct.new(image_fn: im, mask_fn: msk)
|
284
|
+
|
285
|
+
image_sets << current
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
end
|
292
|
+
|
293
|
+
image_sets
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
##
|
298
|
+
# Writes the provided image objects to file to the location specified in a parameter dictionary.
|
299
|
+
#
|
300
|
+
# @param [Enumerable<ImageObject>] image_objects the objects that will be written to file.
|
301
|
+
# @param [ParameterDictionary, Hash] p a hash-like object specifying the filename for the data.
|
302
|
+
#
|
303
|
+
# @return [void]
|
304
|
+
#
|
305
|
+
def self.write_position_data(image_objects, p)
|
306
|
+
|
307
|
+
fn = position_data_filename(p)
|
308
|
+
|
309
|
+
write_position_data_file(image_objects,fn)
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
##
|
314
|
+
# Writes the provided image objects to file to the location specified.
|
315
|
+
#
|
316
|
+
# @param [Enumerable<ImageObject>] image_objects the objects that will be written to file.
|
317
|
+
# @param [String] fn the filename of the file to which to write the data
|
318
|
+
#
|
319
|
+
# @return [void]
|
320
|
+
#
|
321
|
+
def self.write_position_data_file(image_objects, fn)
|
322
|
+
|
323
|
+
File.open(fn, 'w') do |f|
|
324
|
+
|
325
|
+
f.write(Serialization.serialize_image_objects(image_objects))
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
end
|
330
|
+
|
331
|
+
##
|
332
|
+
# Gets the filename for storing/reading the correction based upon the supplied parameter dictionary.
|
333
|
+
#
|
334
|
+
# @param [ParameterDictionary, Hash] p a hash-like object specifying the correction file location.
|
335
|
+
#
|
336
|
+
# @return [String] the filename for the correction file.
|
337
|
+
#
|
338
|
+
def self.correction_filename(p)
|
339
|
+
|
340
|
+
dir = p[:data_directory]
|
341
|
+
fn = p[:correction_date]
|
342
|
+
|
343
|
+
File.expand_path(fn + CORR_XML_EXTENSION, dir)
|
344
|
+
|
345
|
+
end
|
346
|
+
|
347
|
+
##
|
348
|
+
# Writes an array of distance measurements to file based upon the supplied parameter dictionary.
|
349
|
+
#
|
350
|
+
# @param [Enumerable<#to_s>] diffs an enumerable list of distance meaurements.
|
351
|
+
# @param [ParameterDictionary, hash] p a hash-like object specifying the file location.
|
352
|
+
#
|
353
|
+
# @return [void]
|
354
|
+
#
|
355
|
+
def self.write_differences(diffs, p)
|
356
|
+
|
357
|
+
dirname = p[:output_positions_to_directory]
|
358
|
+
|
359
|
+
fn = File.expand_path(p[:basename_set] + DIFFS_TXT_EXTENSION, dirname)
|
360
|
+
|
361
|
+
File.open(fn, 'w') do |f|
|
362
|
+
|
363
|
+
diffs.each do |d|
|
364
|
+
|
365
|
+
f.puts(d.to_s)
|
366
|
+
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
|
373
|
+
end
|
374
|
+
|
375
|
+
end
|
376
|
+
|
377
|
+
|
@@ -0,0 +1,235 @@
|
|
1
|
+
# /* ***** BEGIN LICENSE BLOCK *****
|
2
|
+
# *
|
3
|
+
# * Copyright (c) 2012 Colin J. Fuller
|
4
|
+
# *
|
5
|
+
# * Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# * of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# * in the Software without restriction, including without limitation the rights
|
8
|
+
# * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# * copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# * furnished to do so, subject to the following conditions:
|
11
|
+
# *
|
12
|
+
# * The above copyright notice and this permission notice shall be included in
|
13
|
+
# * all copies or substantial portions of the Software.
|
14
|
+
# *
|
15
|
+
# * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
# * SOFTWARE.
|
22
|
+
# *
|
23
|
+
# * ***** END LICENSE BLOCK ***** */
|
24
|
+
|
25
|
+
require 'rimageanalysistools'
|
26
|
+
|
27
|
+
require 'facets/math/mean'
|
28
|
+
require 'facets/math/std'
|
29
|
+
|
30
|
+
module Cicada
|
31
|
+
|
32
|
+
##
|
33
|
+
# Interface for a class that fits a set of scalars with associated image object
|
34
|
+
# to some distribution.
|
35
|
+
#
|
36
|
+
class DistributionFitter
|
37
|
+
|
38
|
+
attr_accessor :parameters
|
39
|
+
|
40
|
+
##
|
41
|
+
# Constructs a new distribution fitter from specified parameters. Derived
|
42
|
+
# classes should indicate which parameters are used.
|
43
|
+
#
|
44
|
+
# @param [ParameterDictionary, Hash] params a hash-like object containing the parameters
|
45
|
+
#
|
46
|
+
def initialize(params)
|
47
|
+
|
48
|
+
@parameters = params
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Fits the data with associated image objects to the distribution.
|
54
|
+
#
|
55
|
+
# *Abstract*
|
56
|
+
#
|
57
|
+
# @param [Array<ImageObject>] objects the associated image objects
|
58
|
+
# @param [Array<Numeric>] diffs the scalar data being fit (in the same order
|
59
|
+
# as the image objects)
|
60
|
+
#
|
61
|
+
# @return [Array<Numeric>] the fitted distribution parameters
|
62
|
+
#
|
63
|
+
def fit(objects, diffs)
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# An objective function that calculates the negative log likelihood of supplied data points
|
71
|
+
# being generated from a p3d distribution with specified parameters.
|
72
|
+
#
|
73
|
+
# The data points should be an array of (positive) scalars set using the attribute r.
|
74
|
+
#
|
75
|
+
#
|
76
|
+
class P3DObjectiveFunction
|
77
|
+
|
78
|
+
include Java::edu.stanford.cfuller.imageanalysistools.fitting.ObjectiveFunction
|
79
|
+
|
80
|
+
##
|
81
|
+
# Constructs an empty P3DObjectiveFunction.
|
82
|
+
#
|
83
|
+
def initialize
|
84
|
+
|
85
|
+
@r = nil
|
86
|
+
@s = nil
|
87
|
+
@min_prob = nil
|
88
|
+
@use_min_prob = false
|
89
|
+
@should_fit_s = true
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
attr_accessor :r, :use_min_prob, :should_fit_s
|
94
|
+
|
95
|
+
attr_reader :s, :min_prob
|
96
|
+
|
97
|
+
##
|
98
|
+
# Sets a static value for the parameter that is the standard deviation of the generating
|
99
|
+
# Gaussian distribution. Setting this parameter disables its fitting by the objective function.
|
100
|
+
#
|
101
|
+
# @param [Numeric] s_new the static value for the standard deviation parameter
|
102
|
+
#
|
103
|
+
# @return [void]
|
104
|
+
#
|
105
|
+
def s=(s_new)
|
106
|
+
@s = s_new
|
107
|
+
@should_fit_s = false
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# Sets a minimum probability cutoff for calculating the likelihood. Could be used for various
|
112
|
+
# robust fitting approaches.
|
113
|
+
#
|
114
|
+
# @param [Numeric] min_prob the minimum allowed probability for any data point. Probabilities
|
115
|
+
# smaller than this value will be set to this value.
|
116
|
+
#
|
117
|
+
# @return [void]
|
118
|
+
#
|
119
|
+
def min_prob=(min_prob)
|
120
|
+
|
121
|
+
@min_prob = min_prob
|
122
|
+
@use_min_prob = true
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# Calculates the probability density of the p3d distribution at a given point.
|
128
|
+
#
|
129
|
+
# @param [Numeric] r the distance at which to calculate the probability density
|
130
|
+
# @param [Numeric] m the mean-like parameter of the p3d distribution
|
131
|
+
# @param [Numeric] s the standard-deviation-like parameter of the p3d distribution
|
132
|
+
#
|
133
|
+
# @return [Float] the probability density at the given point
|
134
|
+
#
|
135
|
+
def p3d(r, m, s)
|
136
|
+
|
137
|
+
(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
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Evaluates the negative log-likelihood of the data given the parameters specified.
|
143
|
+
#
|
144
|
+
# @param [Array<Numeric>] point a 2-element array containing the mean- and standard deviation-like
|
145
|
+
# parameters. If a static standard deviation parameter is being used, something should still be
|
146
|
+
# provided here, but it will be ignored.
|
147
|
+
#
|
148
|
+
# @return [Float] the negative log-likelihood of the data.
|
149
|
+
#
|
150
|
+
def evaluate(point)
|
151
|
+
|
152
|
+
point = point.toArray unless point.is_a? Array
|
153
|
+
|
154
|
+
m = point[0]
|
155
|
+
s = point[1]
|
156
|
+
s = @s unless @should_fit_s
|
157
|
+
|
158
|
+
return Float::MAX if (m < 0 or s < 0)
|
159
|
+
|
160
|
+
r.reduce(0.0) do |sum, ri|
|
161
|
+
|
162
|
+
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
|
+
|
166
|
+
sum + @min_prob
|
167
|
+
|
168
|
+
else
|
169
|
+
|
170
|
+
sum + temp_neg_log_p
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
##
|
182
|
+
# A distribution fitter that fits data to a P3D distribution.
|
183
|
+
#
|
184
|
+
class P3DFitter < DistributionFitter
|
185
|
+
|
186
|
+
# parameters required by the methods in this class
|
187
|
+
REQUIRED_PARAMETERS = []
|
188
|
+
|
189
|
+
# parmeters used but not required in this class or only required for optional functionality
|
190
|
+
OPTIONAL_PARAMETERS = [:robust_p3d_fit_cutoff]
|
191
|
+
|
192
|
+
|
193
|
+
##
|
194
|
+
# Fits the P3D mean- and standard-deviation-like parameters to the data.
|
195
|
+
#
|
196
|
+
# @param [Array<ImageObject>] objects the image objects whose distances are being fit
|
197
|
+
# @param [Array<Numeric>] diffs the distances being fit
|
198
|
+
#
|
199
|
+
# @return [Array] a two-element array containing the mean- and standard-deviation-like parameters.
|
200
|
+
#
|
201
|
+
def fit(objects, diffs)
|
202
|
+
|
203
|
+
of = P3DObjectiveFunction.new
|
204
|
+
|
205
|
+
of.r = diffs
|
206
|
+
|
207
|
+
tol = 1e-12
|
208
|
+
|
209
|
+
nmm = Java::edu.stanford.cfuller.imageanalysistools.fitting.NelderMeadMinimizer.new(tol)
|
210
|
+
|
211
|
+
initial_mean = Math.mean(diffs)
|
212
|
+
|
213
|
+
initial_width = Math.std(diffs)
|
214
|
+
|
215
|
+
starting_point = Java::org.apache.commons.math3.linear.ArrayRealVector.new(2, 0.0)
|
216
|
+
|
217
|
+
starting_point.setEntry(0, initial_mean)
|
218
|
+
starting_point.setEntry(1, initial_width)
|
219
|
+
|
220
|
+
if @parameters[:robust_p3d_fit_cutoff] then
|
221
|
+
|
222
|
+
of.min_prob= @parmaeters[:robust_p3d_fit_cutoff].to_f
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
nmm.optimize(of, starting_point).toArray.to_a
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
|