Module: Panelize

Defined in:
lib/panelize.rb,
lib/panelize/version.rb

Constant Summary collapse

VERSION =
"1.1.0"

Class Method Summary collapse

Class Method Details

.add_scalebar(panel_image, params) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/panelize.rb', line 112

def add_scalebar(panel_image, params)
  scalebar_length_px = params[:scalebar]/params[:mpp]

  y_start = calculate_height(params) - 2*params[:spacing]
  x_start = params[:spacing]

  x_start.upto(x_start + scalebar_length_px - 1) do |x|
    y_start.upto(y_start + params[:spacing] - 1) do |y|
      panel_image.putPixel(x, y, [255, 255, 255].to_java(:int))
    end
  end
end

.ask_for_params(params) ⇒ Object



210
211
212
213
214
215
216
217
218
219
220
# File 'lib/panelize.rb', line 210

def ask_for_params(params)
  params[:n_rows] = ask("Enter the number of treatments (rows) to panelize: ", Integer)
  params[:col_chs] = ask("Enter the channel numbers to display (comma-separated): ", lambda { |str| str.split(/,\s*/).map(&:to_i) })
  params[:col_order] = ask ("Enter the channel order (comma-separated) (default r,g,b if no order given): "), lambda { |str| str.empty? ? [:r, :g, :b] : str.split(/,\s*/).map(&:to_sym) }
  params[:fns] = []
  params[:n_rows].times do |i|
    params[:fns] << ask("Enter the filename for treatment #{i+1}: ").gsub("'", "") #remove quotes if drag and drop fn insertion in the terminal puts them in
  end
  params[:mpp] = ask("Enter the number of microns per pixel (for calculating the length of a scalebar): ", Float)

end

.box_channel(im, ch) ⇒ Object



41
42
43
44
45
46
47
48
49
50
# File 'lib/panelize.rb', line 41

def box_channel(im, ch)
  lower = ImageCoordinate[0,0,0,0,0]
  upper = ImageCoordinate.cloneCoord(im.getDimensionSizes)
  lower[:c] = ch
  upper[:c] = ch+1
  im.setBoxOfInterest(lower, upper)
  lower.recycle
  upper.recycle
  nil
end

.calculate_channel_scale(ims, params) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/panelize.rb', line 84

def calculate_channel_scale(ims, params)
  scale = {}

  params[:col_chs].each do |ch|
    min = Float::MAX
    max = -1.0*Float::MAX

    ims.each do |im|
      box_channel(im, ch)

      h = Histogram.new(im)
      min = h.getMinValue if h.getMinValue < min
      max = h.getMaxValue if h.getMaxValue > max
    end

    scale[ch] = [min + params[:scaleundersat]/100*(max-min), max - params[:scalesat]/100*(max-min)]
  end

  scale
end

.calculate_col_pos(n, params) ⇒ Object



155
156
157
# File 'lib/panelize.rb', line 155

def calculate_col_pos(n, params)
  n*params[:size] + n*params[:spacing]
end

.calculate_height(params) ⇒ Object



147
148
149
# File 'lib/panelize.rb', line 147

def calculate_height(params)
  (params[:n_rows])*params[:size] + (params[:n_rows]-1)*params[:spacing]
end

.calculate_row_pos(n, params) ⇒ Object



151
152
153
# File 'lib/panelize.rb', line 151

def calculate_row_pos(n, params)
  n*params[:size] + n*params[:spacing]
end

.calculate_width(params) ⇒ Object



143
144
145
# File 'lib/panelize.rb', line 143

def calculate_width(params)
  (params[:col_chs].size + 1)*params[:size] + params[:col_chs].size*params[:spacing]
end

.crop(im, ul, params) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
# File 'lib/panelize.rb', line 66

def crop(im, ul, params)
  sizes = ImageCoordinate.cloneCoord(im.getDimensionSizes)
  sizes[:x] = params[:size]
  sizes[:y] = params[:size]
  ul_coord = ImageCoordinate[ul[0], ul[1], 0,0,0]
  im_crop = im.subImage(sizes, ul_coord)
  im.toImagePlus.close
  sizes.recycle
  ul_coord.recycle
  im_crop
end

.display(im, params) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/panelize.rb', line 52

def display(im, params)
  box_channel(im, params[:col_chs][0])
  max = Histogram.findMaxVal(im)
  im.clearBoxOfInterest
  imp = im.toImagePlus
  imp.setOpenAsHyperStack true
  imp.updatePosition(params[:col_chs][0]+1, 1, 1)
  imp.setDisplayRange(0, max)
  imp.setRoi 0,0, params[:size], params[:size]
  imp.show
  ask("Move the region of interest to where you want to crop and press enter when done.")
  ul = [imp.getRoi.getPolygon.xpoints[0], imp.getRoi.getPolygon.ypoints[0]]
end

.goObject



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/panelize.rb', line 222

def go
  params = Trollop::options do 
    opt :spacing, "Spacing between image panels in pixels", type: :integer, default: 5
    opt :size, "Size of the image in pixels", type: :integer, default: 256
    opt :scalebar, "Size of the scalebar in microns", type: :float, default: 5.0
    opt :scalesat, "Amount in percent by which to saturate images", type: :float, default: 15.0
    opt :scaleundersat, "Amount in percent by which to undersaturate images", type: :float, default: 5.0
  end

  ask_for_params(params)

  ims = []
  params[:fns].each do |fn|
    ims << load_and_crop(fn, params)
  end

  scale = calculate_channel_scale(ims, params)
  panels = make_panels(ims, scale, params)
  add_scalebar(panels, params)
  save_image(panels)
end

.initialize_panel(params) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/panelize.rb', line 159

def initialize_panel(params)
  w = calculate_width(params)
  h = calculate_height(params)

  im = ColorProcessor.new(w, h)
  w.times do |x|
    h.times do |y|
      im.putPixel(x, y, [255, 255, 255].to_java(:int))
    end
  end

  im
end

.load_and_crop(fn, params) ⇒ Object



78
79
80
81
82
# File 'lib/panelize.rb', line 78

def load_and_crop(fn, params)
  im = RImageAnalysisTools.get_image(fn)
  ul = display(im, params)
  crop(im, ul, params)
end

.make_panels(ims, scale, params) ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/panelize.rb', line 174

def make_panels(ims, scale, params)
  panels = initialize_panel(params)

  params[:n_rows].times do |row|
    params[:col_chs].size.times do |col|
      place_panel(panels, {y: calculate_row_pos(row, params), x: calculate_col_pos(col, params)}, ims[row], params[:col_chs][col], [:r, :g, :b], scale)
    end

    zero_im = ImageFactory.createWritable(ims[0])
    zero_im.each { |ic| zero_im[ic] = 0.0 }

    #zero out merge first in case not all channels are being used
    [:r, :g, :b].each do |ch, i|
      next if params[:col_chs].include? ch
      place_panel(panels, {y:calculate_row_pos(row, params), x: calculate_col_pos(params[:col_chs].size, params)}, zero_im, params[:col_chs][0], [ch], scale)
    end
    
    params[:col_order].each_with_index do |ch, i|
      if params[:col_chs].size > i then
        place_panel(panels, {y:calculate_row_pos(row, params), x: calculate_col_pos(params[:col_chs].size, params)}, ims[row], params[:col_chs][i], [ch], scale)
      else 
        place_panel(panels, {y:calculate_row_pos(row, params), x: calculate_col_pos(params[:col_chs].size, params)}, zero_im, params[:col_chs][0], [ch], scale)
      end
    end
  end

  panels
end

.place_panel(panel_image, start_coord, image, channel, rgb_chs, scales) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/panelize.rb', line 126

def place_panel(panel_image, start_coord, image, channel, rgb_chs, scales)
  box_channel(image, channel)

  rgb_mult = [0, 0, 0]
  rgb_mult[0] = 1 if rgb_chs.include? :r
  rgb_mult[1] = 1 if rgb_chs.include? :g
  rgb_mult[2] = 1 if rgb_chs.include? :b

  image.each do |ic|
    v = scale_to_8_bit(image[ic], scales[ic[:c]])
    curr_val = panel_image.getPixel(ic[:x] + start_coord[:x], ic[:y] + start_coord[:y], nil)
    panel_image.putPixel(ic[:x] + start_coord[:x], ic[:y] + start_coord[:y], rgb_mult.map.with_index { |e, i| e*v + (1-e)*curr_val[i]}.to_java(:int))
  end

  nil
end

.save_image(panels) ⇒ Object



203
204
205
206
207
208
# File 'lib/panelize.rb', line 203

def save_image(panels)
  fs = FileSaver.new(ImagePlus.new("panels", panels))
  fn = "panels_#{Time.now.to_i}.tif"
  fs.saveAsTiff(fn)
  puts "Panels saved as #{fn}"
end

.scale_to_8_bit(value, scale) ⇒ Object



105
106
107
108
109
110
# File 'lib/panelize.rb', line 105

def scale_to_8_bit(value, scale)
  value = 255*(value - scale[0])/(scale[1]-scale[0])
  value = 0 if value < 0
  value = 255 if value > 255
  value
end