Class: Panomosity::GeneralizedNeighborhood
- Inherits:
-
Object
- Object
- Panomosity::GeneralizedNeighborhood
show all
- Extended by:
- Utils
- Includes:
- Utils
- Defined in:
- lib/panomosity/generalized_neighborhood.rb
Constant Summary
collapse
- CONTROL_POINT_ATTRIBUTES =
[:dist_avg, :dist_std, :x_avg, :x_std, :y_avg, :y_std]
- ATTRIBUTES =
[:center, :scope, :control_points, :count] + CONTROL_POINT_ATTRIBUTES
- DEFAULT_DISTANCE =
100
Class Attribute Summary collapse
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Methods included from Utils
calculate_average, calculate_average_and_std, remove_outliers
Constructor Details
Returns a new instance of GeneralizedNeighborhood.
141
142
143
144
145
146
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 141
def initialize(center:, scope:, options: {})
@center = center
@scope = scope
@options = options
@measure = Measure.new
end
|
Class Attribute Details
.horizontal_neighborhoods_by_similar_neighborhood ⇒ Object
Returns the value of attribute horizontal_neighborhoods_by_similar_neighborhood.
17
18
19
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 17
def horizontal_neighborhoods_by_similar_neighborhood
@horizontal_neighborhoods_by_similar_neighborhood
end
|
.horizontal_similar_neighborhoods ⇒ Object
Returns the value of attribute horizontal_similar_neighborhoods.
17
18
19
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 17
def horizontal_similar_neighborhoods
@horizontal_similar_neighborhoods
end
|
.neighborhoods ⇒ Object
Returns the value of attribute neighborhoods.
17
18
19
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 17
def neighborhoods
@neighborhoods
end
|
.options ⇒ Object
Returns the value of attribute options.
17
18
19
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 17
def options
@options
end
|
.vertical_neighborhoods_by_similar_neighborhood ⇒ Object
Returns the value of attribute vertical_neighborhoods_by_similar_neighborhood.
17
18
19
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 17
def vertical_neighborhoods_by_similar_neighborhood
@vertical_neighborhoods_by_similar_neighborhood
end
|
.vertical_similar_neighborhoods ⇒ Object
Returns the value of attribute vertical_similar_neighborhoods.
17
18
19
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 17
def vertical_similar_neighborhoods
@vertical_similar_neighborhoods
end
|
Instance Attribute Details
#measure ⇒ Object
Returns the value of attribute measure.
11
12
13
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 11
def measure
@measure
end
|
#options ⇒ Object
Returns the value of attribute options.
11
12
13
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 11
def options
@options
end
|
Class Method Details
.attributes ⇒ Object
23
24
25
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 23
def attributes
{ name: name }
end
|
.calculate_all(panorama:, options: {}) ⇒ Object
35
36
37
38
39
40
41
42
43
44
45
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 35
def calculate_all(panorama:, options: {})
@neighborhoods = []
@options = options
Pair.create_pairs_from_panorama(panorama)
calculate_from_pairs
calculate_from_neighborhoods(type: :horizontal)
calculate_from_neighborhoods(type: :vertical)
@neighborhoods
end
|
.calculate_from_neighborhoods(type:) ⇒ Object
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 64
def calculate_from_neighborhoods(type:)
count = options[:regional_distance_similarities_count] || 3
attempts = options[:max_reduction_attempts] || 2
calculate_similar_neighborhoods(type: type, count: count)
if neighborhoods.empty?
logger.warn 'total neighborhoods came up empty, neighborhood default count to 2'
calculate_similar_neighborhoods(type: type, count: 2)
raise 'still could not find neighborhoods' if neighborhoods.empty?
end
std_outlier_reduction(type: type, max_reduction_attempts: attempts)
calculate_neighborhoods_by_similar_neighborhood(type: type)
end
|
.calculate_from_pairs ⇒ Object
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 47
def calculate_from_pairs
logger.debug 'calculating neighborhoods from pairs'
Pair.all.each do |pair|
control_points = pair.control_points.select(&:not_generated?)
control_points.each do |control_point|
base_params = { center: control_point, scope: pair, options: options }
position_params = { measure: { type: :position } }
neighborhood = calculate_neighborhood(**base_params.merge(position_params))
pair.generalized_neighborhoods << neighborhood
distance_params = { measure: { type: :distance, distances: { x1: neighborhood.dist_std } } }
distance_neighborhood = calculate_neighborhood(**base_params.merge(distance_params))
neighborhood.reference = distance_neighborhood
pair.generalized_neighborhoods << distance_neighborhood
end
end
end
|
.calculate_neighborhood(center:, scope:, options:, measure: {}) ⇒ Object
80
81
82
83
84
85
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 80
def calculate_neighborhood(center:, scope:, options:, measure: {})
neighborhood = new(center: center, scope: scope, options: options)
neighborhood.update_measure(measure)
@neighborhoods << neighborhood.calculate
neighborhood
end
|
.calculate_neighborhoods_by_similar_neighborhood(type: :horizontal) ⇒ Object
126
127
128
129
130
131
132
133
134
135
136
137
138
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 126
def calculate_neighborhoods_by_similar_neighborhood(type: :horizontal)
instance_variable_set("@#{type}_neighborhoods_by_similar_neighborhood", [])
similar_neighborhoods(type: type).each do |neighborhood|
base_params = { center: neighborhood, scope: self, options: options }
distance_params = { measure: { type: :distance, distances: { x1: neighborhood.dist_std } } }
neighborhoods_by_similar_neighborhood(type: type) << calculate_neighborhood(**base_params.merge(distance_params))
end
neighborhoods_by_similar_neighborhood(type: type).sort_by! { |n| -n.count }
neighborhoods_by_similar_neighborhood(type: type).max_by(5) { |n| n.count }.each do |n|
logger.debug "#{n.dist_avg} #{n.dist_std} #{n.count} x#{n.x_avg} y#{n.y_avg}"
end
end
|
.calculate_similar_neighborhoods(type: :horizontal, count: 3) ⇒ Object
106
107
108
109
110
111
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 106
def calculate_similar_neighborhoods(type: :horizontal, count: 3)
similar_neighborhoods = neighborhoods.select(&:measure_position?).select(&:"#{type}?").select do |neighborhood|
neighborhood.scope.similar_neighborhoods << neighborhood if neighborhood.reference.count >= count
end
self.send(:"#{type}_similar_neighborhoods=", similar_neighborhoods)
end
|
.horizontal ⇒ Object
27
28
29
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 27
def horizontal
horizontal_neighborhoods_by_similar_neighborhood
end
|
.logger ⇒ Object
19
20
21
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 19
def logger
@logger ||= Panomosity.logger
end
|
.neighborhoods_by_similar_neighborhood(type: :horizontal) ⇒ Object
102
103
104
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 102
def neighborhoods_by_similar_neighborhood(type: :horizontal)
type == :horizontal ? @horizontal_neighborhoods_by_similar_neighborhood : @vertical_neighborhoods_by_similar_neighborhood
end
|
.similar_neighborhoods(type: :horizontal) ⇒ Object
87
88
89
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 87
def similar_neighborhoods(type: :horizontal)
type == :horizontal ? @horizontal_similar_neighborhoods : @vertical_similar_neighborhoods
end
|
.similar_neighborhoods!(type: :horizontal) ⇒ Object
91
92
93
94
95
96
97
98
99
100
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 91
def similar_neighborhoods!(type: :horizontal)
neighborhoods = similar_neighborhoods(type: type)
if neighborhoods.nil? || neighborhoods.empty?
error = "No similar #{type} neighborhoods found"
raise NoSimilarNeighborhoodsError, error
else
neighborhoods
end
end
|
.std_outlier_reduction(type: :horizontal, max_reduction_attempts: 2, reduction_attempts: 0) ⇒ Object
113
114
115
116
117
118
119
120
121
122
123
124
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 113
def std_outlier_reduction(type: :horizontal, max_reduction_attempts: 2, reduction_attempts: 0)
return if reduction_attempts >= max_reduction_attempts
logger.debug "twice reducing #{type} neighborhood std outliers"
neighborhoods = similar_neighborhoods!(type: type)
std_dist_of_neighborhoods = neighborhoods.map(&:dist_std)
avg, std = *calculate_average_and_std(values: std_dist_of_neighborhoods)
similar_neighborhoods!(type: type).select! { |n| (avg - n.dist_std).abs <= std }
std_outlier_reduction(type: type, max_reduction_attempts: max_reduction_attempts, reduction_attempts: reduction_attempts + 1)
end
|
.vertical ⇒ Object
31
32
33
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 31
def vertical
vertical_neighborhoods_by_similar_neighborhood
end
|
Instance Method Details
#attributes ⇒ Object
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 258
def attributes
attributes = CONTROL_POINT_ATTRIBUTES.reduce({}) { |h, k| h.merge!({ k => self.send(k) }) }
measure_attributes = measure.attributes.reduce({}) do |hash, (key, value)|
hash["measure_#{key}"] = value
hash
end
if pair_scope?
center_id = center[:id]
scope_id = [scope.control_points.first.n1, scope.control_points.first.n2]
scope_name = 'pair'
else
center_id = center.id
scope_id = nil
scope_name = 'neighborhood'
end
attributes.merge!(measure_attributes)
attributes.merge!(id: id, center: center_id, scope_id: scope_id, scope_name: scope_name, type: type, control_points: control_points.map{|c| c[:id]})
attributes
end
|
#calculate ⇒ Object
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 235
def calculate
if pair_scope?
elements = scope.control_points.select(&:not_generated?)
@control_points = if measure_position?
elements.select { |cp| measure.includes?(cp.x1, cp.y1) }
else
elements.select { |cp| measure.includes?(cp.pdist) }
end
else
@neighborhoods = scope.similar_neighborhoods(type: center.type).select { |n| measure.includes?(n.dist_avg) }
distance_neighborhoods = @neighborhoods.map(&:reference)
@control_points = distance_neighborhoods.map(&:control_points).flatten.uniq(&:raw)
end
@dist_avg, @dist_std = *calculate_average_and_std(values: control_points.map(&:pdist), ignore_empty: true)
@x_avg, @x_std = *calculate_average_and_std(values: control_points.map(&:px), ignore_empty: true)
@y_avg, @y_std = *calculate_average_and_std(values: control_points.map(&:py), ignore_empty: true)
@count = control_points.count
self
end
|
#distances_from_options(type: :horizontal) ⇒ Object
198
199
200
201
202
203
204
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 198
def distances_from_options(type: :horizontal)
if type == :both
options.fetch(:distances, {})
else
options[:distances]&.fetch(type, {}) || {}
end
end
|
#horizontal? ⇒ Boolean
180
181
182
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 180
def horizontal?
pair_scope? ? scope.horizontal? : center.horizontal?
end
|
#id ⇒ Object
148
149
150
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 148
def id
@id
end
|
#id=(id) ⇒ Object
152
153
154
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 152
def id=(id)
@id = id
end
|
#measure_distance? ⇒ Boolean
176
177
178
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 176
def measure_distance?
measure.distance?
end
|
#measure_position? ⇒ Boolean
172
173
174
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 172
def measure_position?
measure.position?
end
|
#neighborhood_scope? ⇒ Boolean
168
169
170
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 168
def neighborhood_scope?
scope.class.name == self.class.name
end
|
#pair_scope? ⇒ Boolean
164
165
166
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 164
def pair_scope?
scope.class.name == 'Panomosity::Pair'
end
|
#reference ⇒ Object
156
157
158
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 156
def reference
@reference
end
|
#reference=(reference) ⇒ Object
160
161
162
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 160
def reference=(reference)
@reference = reference
end
|
#set_distance_defaults ⇒ Object
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 206
def set_distance_defaults
return unless measure_position?
measure.update_distances(distances_from_options(type: :both))
if scope.horizontal?
measure.update_distances(x2: (scope.first_image.h * 0.1).round)
measure.update_distances(distances_from_options(type: :horizontal))
else
measure.update_distances(x1: (scope.first_image.w * 0.1).round)
measure.update_distances(distances_from_options(type: :vertical))
end
measure.distances[:x1] ||= DEFAULT_DISTANCE
measure.distances[:x2] ||= DEFAULT_DISTANCE
end
|
#set_measure_defaults ⇒ Object
223
224
225
226
227
228
229
230
231
232
233
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 223
def set_measure_defaults
center_values = if measure_position?
{ x1: center.x1, x2: center.y1 }
elsif pair_scope?
{ x1: center.pdist }
else
{ x1: center.dist_avg }
end
measure.update(center: center_values)
end
|
#type ⇒ Object
188
189
190
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 188
def type
horizontal? ? :horizontal : :vertical
end
|
#update_measure(params) ⇒ Object
192
193
194
195
196
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 192
def update_measure(params)
measure.update(params)
set_distance_defaults
set_measure_defaults
end
|
#vertical? ⇒ Boolean
184
185
186
|
# File 'lib/panomosity/generalized_neighborhood.rb', line 184
def vertical?
pair_scope? ? scope.vertical? : center.vertical?
end
|