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.
@@ -32,11 +32,6 @@ require 'facets/enumerable/ewise'
32
32
 
33
33
  module Cicada
34
34
 
35
- ##
36
- # An error indicating that a position cannot be corrected (probably due to incomplete
37
- # coverage in the correction dataset).
38
- class UnableToCorrectError < StandardError; end
39
-
40
35
  ##
41
36
  # Stores data for a standard 3d high-resolution colocalization correction, including
42
37
  # positions for a number of objects used for correction, and local quadratic fits of
@@ -82,22 +77,16 @@ module Cicada
82
77
  # @param [Integer] correction_channel the channel being corrected
83
78
  #
84
79
  def initialize(c_x, c_y, c_z, distance_cutoffs, image_objects, reference_channel, correction_channel)
85
-
86
80
  @correction_x = c_x
87
81
  @correction_y = c_y
88
82
  @correction_z = c_z
89
83
  @reference_channel = reference_channel
90
84
  @correction_channel = correction_channel
91
85
  @distance_cutoffs = distance_cutoffs
92
-
93
86
  n_dims = 3
94
-
95
87
  @positions_for_correction = MMatrix.build(image_objects.size, n_dims) do |r, c|
96
-
97
88
  image_objects[r].getPositionForChannel(reference_channel).toArray[c]
98
-
99
89
  end
100
-
101
90
  end
102
91
 
103
92
  ##
@@ -108,16 +97,11 @@ module Cicada
108
97
  # @return [void]
109
98
  #
110
99
  def write_to_file(fn)
111
-
112
100
  File.open(fn, 'w') do |f|
113
-
114
101
  f.puts(write_to_xml)
115
-
116
102
  end
117
-
118
103
  end
119
104
 
120
-
121
105
  ##
122
106
  # Writes all the points used for correction to XML within a supplied correction
123
107
  # XML element
@@ -127,16 +111,11 @@ module Cicada
127
111
  # @return [void]
128
112
  #
129
113
  def write_all_correction_point_xml(correction_element)
130
-
131
114
  @distance_cutoffs.each_with_index do |e,i|
132
-
133
115
  write_correction_point_xml(correction_element, i)
134
-
135
116
  end
136
-
137
117
  end
138
118
 
139
-
140
119
  ##
141
120
  # Writes a single point used for correction to XML within a supplied correction
142
121
  # XML element
@@ -147,26 +126,18 @@ module Cicada
147
126
  # @return [void]
148
127
  #
149
128
  def write_correction_point_xml(correction_element, i)
150
-
151
129
  cp = correction_element.add_element XML_STRINGS[:correction_point_element]
152
-
153
130
  cp.attributes[XML_STRINGS[:x_pos_attr]]= @positions_for_correction[i,0]
154
131
  cp.attributes[XML_STRINGS[:y_pos_attr]]= @positions_for_correction[i,1]
155
132
  cp.attributes[XML_STRINGS[:z_pos_attr]]= @positions_for_correction[i,2]
156
-
157
133
  point_dims_to_corr = {XML_STRINGS[:x_param_element] => @correction_x,
158
134
  XML_STRINGS[:y_param_element] => @correction_y,
159
135
  XML_STRINGS[:z_param_element] => @correction_z}
160
136
 
161
-
162
137
  point_dims_to_corr.each do |dim_el, corr_txt|
163
-
164
138
  p = cp.add_element dim_el
165
-
166
139
  p.text = corr_txt[i].to_a.join(", ")
167
-
168
140
  end
169
-
170
141
  end
171
142
 
172
143
  ##
@@ -178,15 +149,10 @@ module Cicada
178
149
  # @return [void]
179
150
  #
180
151
  def write_correction_binary_data_element(correction_element)
181
-
182
152
  bd = correction_element.add_element XML_STRINGS[:binary_data_element]
183
-
184
153
  bd.attributes[XML_STRINGS[:encoding_attr]]= XML_STRINGS[:encoding_name]
185
-
186
154
  bin_data = Base64.encode64(Marshal.dump(self))
187
-
188
155
  bd.text = bin_data
189
-
190
156
  end
191
157
 
192
158
  ##
@@ -195,27 +161,16 @@ module Cicada
195
161
  # @return [String] the correction data encoded as XML
196
162
  #
197
163
  def write_to_xml
198
-
199
164
  doc = REXML::Document.new
200
-
201
165
  ce = doc.add_element XML_STRINGS[:correction_element]
202
-
203
166
  ce.attributes[XML_STRINGS[:n_points_attr]] = @distance_cutoffs.size
204
-
205
167
  ce.attributes[XML_STRINGS[:ref_channel_attr]] = @reference_channel
206
-
207
168
  ce.attributes[XML_STRINGS[:corr_channel_attr]] = @correction_channel
208
-
209
169
  write_all_correction_point_xml(ce)
210
-
211
170
  write_correction_binary_data_element(ce)
212
-
213
171
  doc_string = ""
214
-
215
172
  doc.write doc_string, 2
216
-
217
173
  doc_string
218
-
219
174
  end
220
175
 
221
176
  ##
@@ -226,19 +181,14 @@ module Cicada
226
181
  # @return [Correction] the correction contained in the file.
227
182
  #
228
183
  def self.read_from_file(fn)
229
-
230
184
  return nil unless File.exist?(fn)
231
185
 
232
186
  xml_str = ""
233
-
234
187
  File.open(fn) do |f|
235
-
236
188
  xml_str = f.read
237
-
238
189
  end
239
190
 
240
191
  read_from_xml(xml_str)
241
-
242
192
  end
243
193
 
244
194
 
@@ -250,13 +200,9 @@ module Cicada
250
200
  # @return [Correction] the correction contained in the string.
251
201
  #
252
202
  def self.read_from_xml(xml_str)
253
-
254
203
  doc = REXML::Document.new xml_str
255
-
256
204
  bin_el = doc.root.elements[1, XML_STRINGS[:binary_data_element]]
257
-
258
205
  Marshal.load(Base64.decode64(bin_el.text))
259
-
260
206
  end
261
207
 
262
208
 
@@ -271,15 +217,10 @@ module Cicada
271
217
  # @return [Vector] the distance from the specified point to each image object.
272
218
  #
273
219
  def calculate_normalized_dists_to_centroids(x,y)
274
-
275
220
  dists_to_centroids = @positions_for_correction.column(0).map { |x0| (x0-x)**2 }
276
-
277
221
  dists_to_centroids += @positions_for_correction.column(1).map { |y0| (y0-y)**2 }
278
-
279
222
  dists_to_centroids = dists_to_centroids.map { |e| Math.sqrt(e) }
280
-
281
223
  dists_to_centroids.map2(@distance_cutoffs) { |e1, e2| e1/e2 }
282
-
283
224
  end
284
225
 
285
226
  ##
@@ -290,17 +231,11 @@ module Cicada
290
231
  # @return [Vector] the weights for each local fit used for correction
291
232
  #
292
233
  def calculate_weights(x, y)
293
-
294
234
  dist_ratio = calculate_normalized_dists_to_centroids(x,y)
295
-
296
235
  dist_ratio_mask = MVector.zero(dist_ratio.size)
297
-
298
236
  dist_ratio_mask = dist_ratio.map { |e| e <= 1 ? 1 : 0 }
299
-
300
237
  weights = dist_ratio.map { |e| -3*e**2 + 1 + 2*e**3 }
301
-
302
238
  weights.map2(dist_ratio_mask) { |e1, e2| e1*e2 }
303
-
304
239
  end
305
240
 
306
241
  ##
@@ -314,41 +249,28 @@ module Cicada
314
249
  # of the selected image objects used for correction; and the weights of the fits
315
250
  #
316
251
  def find_points_for_correction(x,y)
317
-
318
252
  weights = calculate_weights(x,y)
319
-
320
253
  count_weights = weights.count { |e| e > 0 }
321
-
322
254
  raise UnableToCorrectError, "Incomplete coverage in correction dataset at (x,y) = (#{x}, #{y})." if count_weights == 0
323
255
 
324
256
  cx = MMatrix.zero(count_weights, @correction_x[0].size)
325
257
  cy = MMatrix.zero(count_weights, @correction_y[0].size)
326
258
  cz = MMatrix.zero(count_weights, @correction_z[0].size)
327
-
328
259
  x_vec = MVector.zero(count_weights)
329
260
  y_vec = MVector.zero(count_weights)
330
-
331
261
  kept_weights = MVector.zero(count_weights)
332
-
333
262
  kept_counter = 0
334
263
 
335
264
  weights.each_with_index do |w, i|
336
-
337
265
  if w > 0 then
338
-
339
266
  cx.replace_row(kept_counter, @correction_x[i])
340
267
  cy.replace_row(kept_counter, @correction_y[i])
341
- cz.replace_row(kept_counter, @correction_z[i])
342
-
268
+ cz.replace_row(kept_counter, @correction_z[i])
343
269
  x_vec[kept_counter] = x - positions_for_correction[i,0]
344
270
  y_vec[kept_counter] = y - positions_for_correction[i,1]
345
-
346
271
  kept_weights[kept_counter] = weights[i]
347
-
348
272
  kept_counter += 1
349
-
350
273
  end
351
-
352
274
  end
353
275
 
354
276
  OpenStruct.new(cx: cx,
@@ -357,7 +279,6 @@ module Cicada
357
279
  x_vec: x_vec,
358
280
  y_vec: y_vec,
359
281
  weights: kept_weights)
360
-
361
282
  end
362
283
 
363
284
  ##
@@ -369,41 +290,27 @@ module Cicada
369
290
  # for the specified position.
370
291
  #
371
292
  def correct_position(x, y)
372
-
373
293
  points = find_points_for_correction(x,y)
374
-
375
294
  x_corr = 0.0
376
295
  y_corr = 0.0
377
296
  z_corr = 0.0
378
-
379
297
  all_correction_parameters = MMatrix.columns([MVector.unit(points.x_vec.size),
380
298
  points.x_vec,
381
299
  points.y_vec,
382
300
  points.x_vec.map { |e| e**2 },
383
301
  points.y_vec.map { |e| e**2 },
384
302
  points.x_vec.map2(points.y_vec) { |e1, e2| e1*e2 }])
385
-
386
-
387
303
  all_correction_parameters.row_size.times do |i|
388
-
389
304
  x_corr += all_correction_parameters.row(i).inner_product(points.cx.row(i))*points.weights[i]
390
305
  y_corr += all_correction_parameters.row(i).inner_product(points.cy.row(i))*points.weights[i]
391
306
  z_corr += all_correction_parameters.row(i).inner_product(points.cz.row(i))*points.weights[i]
392
-
393
307
  end
394
308
 
395
309
  sum_weights = points.weights.reduce(0.0) { |a,e| a + e }
396
-
397
310
  x_corr /= sum_weights
398
311
  y_corr /= sum_weights
399
312
  z_corr /= sum_weights
400
-
401
313
  MVector[x_corr, y_corr, z_corr]
402
-
403
314
  end
404
-
405
315
  end
406
-
407
316
  end
408
-
409
-
@@ -0,0 +1,67 @@
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
+ require 'rimageanalysistools/fitting/bisquare_linear_fit'
24
+
25
+ module Cicada
26
+ class InSituCorrection
27
+ attr_accessor :reference_channel, :in_situ_corr_second_channel, :correction_channel, :parameters, :corr_parameters
28
+
29
+ def initialize(ref_ch, in_situ_ch, corr_ch, iobjs, disable_intercept)
30
+ self.reference_channel = ref_ch
31
+ self.in_situ_corr_second_channel = in_situ_ch
32
+ self.correction_channel = corr_ch
33
+ @disable_intercept = disable_intercept
34
+
35
+ calculate_in_situ_corr(iobjs)
36
+ end
37
+
38
+ def disable_intercept?
39
+ @disable_intercept
40
+ end
41
+
42
+ def calculate_in_situ_corr(iobjs)
43
+ corr_diffs = Matrix.rows(iobjs.map { |iobj| iobj.getCorrectedVectorDifferenceBetweenChannels(reference_channel, in_situ_corr_second_channel).toArray })
44
+ expt_diffs = Matrix.rows(iobjs.map { |iobj| iobj.getCorrectedVectorDifferenceBetweenChannels(reference_channel, correction_channel).toArray })
45
+
46
+ bslf = BisquareLinearFit.new
47
+ bslf.disableIntercept if disable_intercept?
48
+ all_parameters = 0.upto(corr_diffs.column_size - 1).collect do |i|
49
+ bslf.fit_rb(corr_diffs.column(i), expt_diffs.column(i)).toArray
50
+ end
51
+
52
+ self.corr_parameters = all_parameters.transpose
53
+ end
54
+
55
+ def apply(iobjs)
56
+ corrected_differences = iobjs.map do |iobj|
57
+ corr_diff = iobj.getCorrectedVectorDifferenceBetweenChannels(reference_channel, in_situ_corr_second_channel).toArray.to_a
58
+ expt_diff = iobj.getCorrectedVectorDifferenceBetweenChannels(reference_channel, correction_channel).toArray.to_a
59
+ correction = (corr_diff.ewise * corr_parameters[0]).ewise + corr_parameters[1]
60
+ Vector.elements(expt_diff.ewise - correction, false)
61
+ end
62
+
63
+ corrected_differences
64
+ end
65
+ end
66
+ end
67
+
@@ -25,17 +25,15 @@
25
25
  #++
26
26
 
27
27
  require 'cicada/mutable_matrix'
28
-
29
28
  require 'cicada/correction/correction'
29
+ require 'cicada/correction/in_situ_correction'
30
30
 
31
31
  require 'ostruct'
32
32
  require 'logger'
33
33
 
34
34
  require 'pqueue'
35
-
36
35
  require 'facets/enumerable/ewise'
37
36
  require 'facets/math/mean'
38
-
39
37
  require 'rimageanalysistools/fitting/bisquare_linear_fit'
40
38
  require 'rimageanalysistools/thread_queue'
41
39
 
@@ -73,7 +71,6 @@ module Cicada
73
71
  @logger = Logger.new(STDOUT)
74
72
  end
75
73
 
76
-
77
74
  ##
78
75
  # Creates a RealVector (org.apache.commons.math3.linear.RealVector) that is a copy of
79
76
  # the contents of the supplied vector.
@@ -83,20 +80,13 @@ module Cicada
83
80
  # @return [RealVector] the commons math RealVector containing the same elements
84
81
  #
85
82
  def self.convert_to_realvector(vec)
86
-
87
83
  conv = ArrayRealVector.new(vec.size, 0.0)
88
-
89
84
  vec.each_with_index do |e, i|
90
-
91
85
  conv.setEntry(i, e)
92
-
93
86
  end
94
-
95
87
  conv
96
-
97
88
  end
98
89
 
99
-
100
90
  ##
101
91
  # Generates a correction from a specified array of image objects.
102
92
  #
@@ -105,86 +95,58 @@ module Cicada
105
95
  # @return [Correction] the correction generated from the input objects
106
96
  #
107
97
  def generate_correction(iobjs)
108
-
109
98
  #TODO refactor into smaller chunks
110
-
111
99
  ref_ch = parameters[:reference_channel].to_i
112
100
  corr_ch = parameters[:channel_to_correct].to_i
113
-
114
101
  unless parameters[:determine_correction] then
115
-
116
102
  return Correction.read_from_file(FileInteraction.correction_filename(parameters))
117
-
118
103
  end
119
104
 
120
105
  correction_x = []
121
106
  correction_y = []
122
107
  correction_z = []
123
-
124
108
  distance_cutoffs = MVector.zero(iobjs.size)
125
109
 
126
110
  iobjs.each_with_index do |obj, ind|
127
-
128
111
  obj_pos = obj.getPositionForChannel(ref_ch)
129
-
130
- distances_to_objects = iobjs.map { |obj2| obj2.getPositionForChannel(ref_ch).subtract(obj_pos).getNorm }
131
-
112
+ distances_to_objects = iobjs.map { |obj2| obj2.getPositionForChannel(ref_ch).subtract(obj_pos).getNorm }
132
113
  pq = PQueue.new
133
-
134
114
  np = @parameters[:num_points].to_i
135
115
 
136
116
  distances_to_objects.each do |d|
137
-
138
117
  if pq.size < np + 1 then
139
-
140
118
  pq.push d
141
-
142
119
  elsif d < pq.top then
143
-
144
120
  pq.pop
145
121
  pq.push d
146
-
147
122
  end
148
-
149
123
  end
150
124
 
151
-
152
125
  first_exclude = pq.pop
153
-
154
126
  last_dist = pq.pop
155
-
156
127
  distance_cutoff = (last_dist + first_exclude)/2.0
157
-
158
128
  distance_cutoffs[ind] = distance_cutoff
159
129
 
160
130
  objs_ind_to_fit = (0...iobjs.size).select { |i| distances_to_objects[i] < distance_cutoff }
161
-
162
131
  objs_to_fit = iobjs.values_at(*objs_ind_to_fit)
163
132
 
164
133
  diffs_to_fit = MMatrix[*objs_to_fit.map { |e| e.getVectorDifferenceBetweenChannels(ref_ch, corr_ch).toArray }]
165
134
  x_to_fit = objs_to_fit.map { |e| e.getPositionForChannel(ref_ch).getEntry(0) }
166
135
  y_to_fit = objs_to_fit.map { |e| e.getPositionForChannel(ref_ch).getEntry(1) }
167
-
168
136
  x = Vector[*x_to_fit.map { |e| e - obj_pos.getEntry(0) }]
169
137
  y = Vector[*y_to_fit.map { |e| e - obj_pos.getEntry(1) }]
170
138
 
171
139
  correction_parameters = Matrix.columns([MVector.unit(objs_to_fit.size), x, y, x.map { |e| e**2 }, y.map { |e| e**2 }, x.map2(y) { |ex, ey| ex*ey }])
172
-
173
140
  cpt = correction_parameters.transpose
174
-
175
141
  cpt_cp = cpt * correction_parameters
176
-
177
142
  cpt_cp_lup = cpt_cp.lup
178
143
 
179
144
  correction_x << cpt_cp_lup.solve(cpt * diffs_to_fit.column(0))
180
145
  correction_y << cpt_cp_lup.solve(cpt * diffs_to_fit.column(1))
181
146
  correction_z << cpt_cp_lup.solve(cpt * diffs_to_fit.column(2))
182
-
183
-
184
147
  end
185
148
 
186
149
  Correction.new(correction_x, correction_y, correction_z, distance_cutoffs, iobjs, ref_ch, corr_ch)
187
-
188
150
  end
189
151
 
190
152
  ##
@@ -196,9 +158,7 @@ module Cicada
196
158
  # @return [Vector] the vector scaled to physical units (by parameter naming convention, in nm)
197
159
  #
198
160
  def apply_scale(vec)
199
-
200
161
  vec.map2(@pixel_to_distance_conversions) { |e1, e2| e1*e2 }
201
-
202
162
  end
203
163
 
204
164
  ##
@@ -211,46 +171,28 @@ module Cicada
211
171
  # wavelengths for each image object provided.
212
172
  #
213
173
  def apply_correction(c, iobjs)
214
-
215
174
  ref_ch = @parameters[:reference_channel].to_i
216
175
  corr_ch = @parameters[:channel_to_correct].to_i
217
-
218
176
  vec_diffs = iobjs.map { |e| e.getVectorDifferenceBetweenChannels(ref_ch, corr_ch) }
219
-
220
177
  vec_diffs.map! { |e| apply_scale(Vector[*e.toArray]) }
221
-
222
178
  corrected_vec_diffs = []
223
179
 
224
- if @parameters[:correct_images] then
225
-
180
+ if c.nil? then
181
+ corrected_vec_diffs = vec_diffs
182
+ else
226
183
  iobjs.each do |iobj|
227
-
228
184
  begin
229
-
230
185
  corrected_vec_diffs << correct_single_object(c, iobj, ref_ch, corr_ch)
231
-
232
186
  iobj.setCorrectionSuccessful(true)
233
-
234
187
  rescue UnableToCorrectError => e
235
-
236
188
  iobj.setCorrectionSuccessful(false)
237
-
238
189
  end
239
-
240
190
  end
241
-
242
- corrected_vec_diffs.map! { |e| apply_scale(e) }
243
-
244
- else
245
-
246
- corrected_vec_diffs = vec_diffs
247
-
191
+ corrected_vec_diffs.map! { |e| apply_scale(e) }
248
192
  end
249
-
193
+
250
194
  print_distance_components(vec_diffs, corrected_vec_diffs)
251
-
252
195
  corrected_vec_diffs.map { |e| e.norm }
253
-
254
196
  end
255
197
 
256
198
  ##
@@ -262,32 +204,23 @@ module Cicada
262
204
  # @return [void]
263
205
  #
264
206
  def print_distance_components(vec_diffs, corrected_vec_diffs)
265
-
266
207
  mean_uncorr_vec = [0.0, 0.0, 0.0]
267
-
268
208
  vec_diffs.each do |e|
269
-
270
209
  mean_uncorr_vec = mean_uncorr_vec.ewise + e.to_a
271
-
272
210
  end
273
211
 
274
212
  mean_corr_vec = [0.0, 0.0, 0.0]
275
-
276
213
  corrected_vec_diffs.each do |e|
277
-
278
214
  mean_corr_vec = mean_corr_vec.ewise + e.to_a
279
-
280
215
  end
281
216
 
282
217
  mean_uncorr_vec.map! { |e| e / vec_diffs.length }
283
-
284
218
  mean_corr_vec.map! { |e| e / corrected_vec_diffs.length }
285
219
 
286
220
  self.logger.info("mean components uncorrected: [#{mean_uncorr_vec.join(', ')}]")
287
221
  self.logger.info("mean distance uncorrected: #{Vector[*mean_uncorr_vec].norm}")
288
222
  self.logger.info("mean components corrected: [#{mean_corr_vec.join(', ')}]")
289
223
  self.logger.info("mean distance corrected: #{Vector[*mean_corr_vec].norm}")
290
-
291
224
  end
292
225
 
293
226
  ##
@@ -301,19 +234,13 @@ module Cicada
301
234
  # @return [Vector] the corrected (x,y,z) vector difference between the two channels
302
235
  #
303
236
  def correct_single_object(c, iobj, ref_ch, corr_ch)
304
-
305
237
  corr = c.correct_position(iobj.getPositionForChannel(ref_ch).getEntry(0), iobj.getPositionForChannel(corr_ch).getEntry(1))
306
-
307
238
  if parameters[:invert_z_axis] then
308
-
309
239
  corr.setEntry(2, -1.0*corr.getEntry(2))
310
-
311
240
  end
312
241
 
313
242
  iobj.applyCorrectionVectorToChannel(corr_ch, PositionCorrector.convert_to_realvector(corr))
314
-
315
243
  Vector.elements(iobj.getCorrectedVectorDifferenceBetweenChannels(ref_ch, corr_ch).toArray)
316
-
317
244
  end
318
245
 
319
246
  ##
@@ -322,11 +249,8 @@ module Cicada
322
249
  # @return @see #generate_in_situ_correction_from_iobjs
323
250
  #
324
251
  def generate_in_situ_correction
325
-
326
252
  iobjs_for_in_situ_corr = FileInteraction.read_in_situ_corr_data(@parameters)
327
-
328
253
  generate_in_situ_correction_from_iobjs(iobjs_for_in_situ_corr)
329
-
330
254
  end
331
255
 
332
256
  ##
@@ -335,64 +259,28 @@ module Cicada
335
259
  # @param [Array<ImageObject>] an array containing the image objects from which the in situ
336
260
  # correction will be generated
337
261
  #
338
- # @return [Array< Array<Numeric> >] an array containing the x, y, and z corrections; each
339
- # correction is a 2-element array containing the slope and intercept for the fit in each
340
- # dimension. The intercept will be zero if disabled in the parameter file.
262
+ # @return [InSituCorrection] an InSituCorrection object containing the necessary information
263
+ # to perform the correction.
341
264
  #
342
265
  def generate_in_situ_correction_from_iobjs(iobjs_for_in_situ_corr)
343
-
344
266
  ref_ch = @parameters[:reference_channel].to_i
345
267
  corr_ch = @parameters[:channel_to_correct].to_i
346
268
  cicada_ch = @parameters[:in_situ_aberr_corr_channel]
347
269
 
348
- corr_diffs = Matrix.rows(iobjs_for_in_situ_corr.map { |iobj| iobj.getCorrectedVectorDifferenceBetweenChannels(ref_ch, cicada_ch).toArray })
349
- expt_diffs = Matrix.rows(iobjs_for_in_situ_corr.map { |iobj| iobj.getCorrectedVectorDifferenceBetweenChannels(ref_ch, corr_ch).toArray })
350
-
351
- bslf = BisquareLinearFit.new
352
-
353
- bslf.disableIntercept if @parameters[:disable_in_situ_corr_constant_offset]
354
-
355
- all_parameters = 0.upto(corr_diffs.column_size - 1).collect do |i|
356
-
357
- bslf.fit_rb(corr_diffs.column(i), expt_diffs.column(i)).toArray
358
-
359
- end
360
-
361
- all_parameters
362
-
270
+ InSituCorrection.new(ref_ch, cicada_ch, corr_ch, iobjs_for_in_situ_corr, @parameters[:disable_in_situ_corr_constant_offset])
363
271
  end
364
272
 
365
273
  ##
366
274
  # Applies an in situ aberration correction to an array of image objects.
367
275
  #
368
276
  # @param [Enumerable<ImageObject>] iobjs the objects to be corrected
369
- # @param [Array< Array<Numeric> >] corr_params the in situ correction parameters (an array
370
- # for each dimension containing the correction's slope and intercept).
371
- #
277
+ # @param [InSituCorrection] isc the in situ correction object.
278
+ #
372
279
  # @return [Array< Array <Numeric> >] an array of the corrected vector distance between
373
280
  # wavelengths for each image object being corrected.
374
281
  #
375
- def apply_in_situ_correction(iobjs, corr_params)
376
-
377
- corr_params = corr_params.transpose
378
-
379
- ref_ch = @parameters[:reference_channel].to_i
380
- corr_ch = @parameters[:channel_to_correct].to_i
381
- cicada_ch = @parameters[:in_situ_aberr_corr_channel]
382
-
383
- corrected_differences = iobjs.map do |iobj|
384
-
385
- corr_diff = iobj.getCorrectedVectorDifferenceBetweenChannels(ref_ch, cicada_ch).toArray.to_a
386
- expt_diff = iobj.getCorrectedVectorDifferenceBetweenChannels(ref_ch, corr_ch).toArray.to_a
387
-
388
- correction = (corr_diff.ewise * corr_params[0]).ewise + corr_params[1]
389
-
390
- Vector.elements(expt_diff.ewise - correction, false)
391
-
392
- end
393
-
394
- corrected_differences
395
-
282
+ def apply_in_situ_correction(iobjs, isc)
283
+ isc.apply(iobjs)
396
284
  end
397
285
 
398
286
  ##
@@ -404,96 +292,58 @@ module Cicada
404
292
  # @return [Float] the (3d) TRE
405
293
  #
406
294
  def determine_tre(iobjs)
407
-
408
295
  ref_ch = @parameters[:reference_channel].to_i
409
296
  corr_ch = @parameters[:channel_to_correct].to_i
410
-
411
297
  results = []
412
-
413
298
  max_threads = 1
414
-
415
299
  if @parameters[:max_threads]
416
300
  max_threads = @parameters[:max_threads].to_i
417
301
  end
418
302
 
419
303
  tq = Executors.newFixedThreadPool(max_threads)
420
-
421
304
  mut = Mutex.new
422
305
 
423
306
  iobjs.each_with_index do |iobj, i|
424
-
425
307
  RImageAnalysisTools::ThreadQueue.new_scope_with_vars(iobj, iobjs, i) do |obj, objs, ii|
426
-
427
308
  tq.submit do
428
-
429
309
  self.logger.debug("Calculating TRE. Progress: #{ii} of #{objs.length}") if ii.modulo(10) == 0
430
-
431
310
  temp_objs = objs.select { |e| e != obj }
432
-
433
311
  c = generate_correction(temp_objs)
434
-
435
312
  pos = obj.getPositionForChannel(ref_ch)
436
-
437
313
  result = OpenStruct.new
438
-
439
314
  begin
440
-
441
315
  corr = c.correct_position(pos.getEntry(0), pos.getEntry(1))
442
-
443
316
  result.success = true
444
-
445
317
  tre_vec = Vector[*obj.getVectorDifferenceBetweenChannels(ref_ch, corr_ch).toArray] - corr
446
-
447
318
  tre_vec = tre_vec.map2(@pixel_to_distance_conversions) { |e1, e2| e1*e2 }
448
-
449
319
  result.tre = tre_vec.norm
450
-
451
320
  result.tre_xy = Math.hypot(tre_vec[0], tre_vec[1])
452
-
453
321
  rescue UnableToCorrectError => e
454
-
455
322
  result.success = false
456
-
457
323
  end
458
324
 
459
325
  mut.synchronize do
460
-
461
326
  results << result
462
-
463
327
  end
464
328
 
465
329
  result
466
-
467
330
  end
468
-
469
331
  end
470
-
471
332
  end
472
333
 
473
334
  tq.shutdown
474
-
475
335
  until tq.isTerminated do
476
-
477
336
  sleep 0.4
478
-
479
337
  end
480
338
 
481
339
  tre_values = results
482
-
483
340
  tre_values.select! { |e| e.success }
484
-
485
341
  tre_3d = Math.mean(tre_values) { |e| e.tre }
486
-
487
342
  tre_2d = Math.mean(tre_values) { |e| e.tre_xy }
488
-
489
343
  self.logger.info("TRE: #{tre_3d}")
490
344
  self.logger.info("X-Y TRE: #{tre_2d}")
491
345
 
492
346
  tre_3d
493
-
494
347
  end
495
-
496
348
  end
497
-
498
349
  end
499
-