multiarray 0.20.0 → 0.21.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/multiarray.rb +14 -0
- data/lib/multiarray/complex.rb +8 -8
- data/lib/multiarray/components.rb +236 -0
- data/lib/multiarray/diagonal.rb +1 -1
- data/lib/multiarray/element.rb +4 -4
- data/lib/multiarray/gccfunction.rb +29 -0
- data/lib/multiarray/gccvalue.rb +1 -2
- data/lib/multiarray/inject.rb +4 -4
- data/lib/multiarray/mask.rb +7 -3
- data/lib/multiarray/operations.rb +67 -3
- data/lib/multiarray/pointer.rb +16 -0
- data/lib/multiarray/rgb.rb +27 -11
- data/lib/multiarray/store.rb +3 -1
- data/lib/multiarray/unmask.rb +7 -3
- data/test/tc_multiarray.rb +5 -0
- data/test/tc_sequence.rb +15 -0
- metadata +4 -3
data/Rakefile
CHANGED
data/lib/multiarray.rb
CHANGED
@@ -66,6 +66,18 @@ class Proc
|
|
66
66
|
|
67
67
|
end
|
68
68
|
|
69
|
+
# An overloadable while loop
|
70
|
+
#
|
71
|
+
# @param [Proc] action The loop body
|
72
|
+
#
|
73
|
+
# @return [NilClass] Returns +nil+.
|
74
|
+
#
|
75
|
+
# @private
|
76
|
+
def while( &action )
|
77
|
+
action.call while call.get
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
|
69
81
|
end
|
70
82
|
|
71
83
|
# +Object+ is extended with a few methods
|
@@ -698,6 +710,7 @@ require 'multiarray/lut'
|
|
698
710
|
require 'multiarray/integral'
|
699
711
|
require 'multiarray/mask'
|
700
712
|
require 'multiarray/unmask'
|
713
|
+
require 'multiarray/components'
|
701
714
|
require 'multiarray/operations'
|
702
715
|
require 'multiarray/methods'
|
703
716
|
require 'multiarray/rgb'
|
@@ -793,3 +806,4 @@ module Hornetseye
|
|
793
806
|
module_function :sum
|
794
807
|
|
795
808
|
end
|
809
|
+
|
data/lib/multiarray/complex.rb
CHANGED
@@ -98,7 +98,7 @@ module Hornetseye
|
|
98
98
|
# @return [Object] Returns +value+.
|
99
99
|
#
|
100
100
|
# @private
|
101
|
-
def
|
101
|
+
def assign( value )
|
102
102
|
@real, @imag = value.real, value.imag
|
103
103
|
end
|
104
104
|
|
@@ -862,8 +862,8 @@ module Hornetseye
|
|
862
862
|
if Thread.current[ :function ]
|
863
863
|
real = Thread.current[ :function ].variable self.class.element_type, 'v'
|
864
864
|
imag = Thread.current[ :function ].variable self.class.element_type, 'v'
|
865
|
-
real.
|
866
|
-
imag.
|
865
|
+
real.assign @value.real
|
866
|
+
imag.assign @value.imag
|
867
867
|
self.class.new InternalComplex.new( real, imag )
|
868
868
|
else
|
869
869
|
self.class.new get
|
@@ -877,15 +877,15 @@ module Hornetseye
|
|
877
877
|
# @return [Object] Returns +value+.
|
878
878
|
#
|
879
879
|
# @private
|
880
|
-
def
|
880
|
+
def assign( value )
|
881
881
|
value = value.simplify
|
882
|
-
if @value.real.respond_to? :
|
883
|
-
@value.real.
|
882
|
+
if @value.real.respond_to? :assign
|
883
|
+
@value.real.assign value.get.real
|
884
884
|
else
|
885
885
|
@value.real = value.get.real
|
886
886
|
end
|
887
|
-
if @value.imag.respond_to? :
|
888
|
-
@value.imag.
|
887
|
+
if @value.imag.respond_to? :assign
|
888
|
+
@value.imag.assign value.get.imag
|
889
889
|
else
|
890
890
|
@value.imag = value.get.imag
|
891
891
|
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
# multiarray - Lazy multi-dimensional arrays for Ruby
|
2
|
+
# Copyright (C) 2010, 2011 Jan Wedekind
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
# Namespace of Hornetseye computer vision library
|
18
|
+
module Hornetseye
|
19
|
+
|
20
|
+
# Class for representing connected component analysis
|
21
|
+
class Components < Node
|
22
|
+
|
23
|
+
class << self
|
24
|
+
|
25
|
+
# Check whether objects of this class are finalised computations
|
26
|
+
#
|
27
|
+
# @return [Boolean] Returns +false+.
|
28
|
+
#
|
29
|
+
# @private
|
30
|
+
def finalised?
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
# Constructor
|
37
|
+
#
|
38
|
+
# @param [Node] dest Target array to write component labels to.
|
39
|
+
# @param [Node] source Array to extract components from.
|
40
|
+
# @param [Node] default Value of background pixel.
|
41
|
+
# @param [Node] zero Zero is used to aid compilation.
|
42
|
+
# @param [Node] labels Array to store label correspondences.
|
43
|
+
# @param [Node] rank Array to store number of indirections for each label.
|
44
|
+
# @param [Node] n Pointer to return number of components.
|
45
|
+
def initialize( dest, source, default, zero, labels, rank, n )
|
46
|
+
@dest, @source, @default, @zero, @labels, @rank, @n =
|
47
|
+
dest, source, default, zero, labels, rank, n
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get unique descriptor of this object
|
51
|
+
#
|
52
|
+
# @param [Hash] hash Labels for any variables.
|
53
|
+
#
|
54
|
+
# @return [String] Descriptor of this object,
|
55
|
+
#
|
56
|
+
# @private
|
57
|
+
def descriptor( hash )
|
58
|
+
"Components(#{@dest.descriptor( hash )},#{@source.descriptor( hash )}," +
|
59
|
+
"#{@default.descriptor( hash )},#{@zero.descriptor( hash )}," +
|
60
|
+
"#{@labels.descriptor( hash )},#{@rank.descriptor( hash )}," +
|
61
|
+
"#{@n.descriptor( hash )})"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Get type of result of delayed operation
|
65
|
+
#
|
66
|
+
# @return [Class] Type of result.
|
67
|
+
def array_type
|
68
|
+
retval = @dest.array_type
|
69
|
+
( class << self; self; end ).instance_eval do
|
70
|
+
define_method( :array_type ) { retval }
|
71
|
+
end
|
72
|
+
retval
|
73
|
+
end
|
74
|
+
|
75
|
+
# Reevaluate computation
|
76
|
+
#
|
77
|
+
# @return [Node,Object] Result of computation
|
78
|
+
#
|
79
|
+
# @see #force
|
80
|
+
#
|
81
|
+
# @private
|
82
|
+
def demand
|
83
|
+
knot [], []
|
84
|
+
@dest
|
85
|
+
end
|
86
|
+
|
87
|
+
# Recursive function to perform connected component labelling
|
88
|
+
#
|
89
|
+
# @param [Array<Proc>] args Array with functions for locating neighbouring elements.
|
90
|
+
# @param [Array<Proc>] comp Array with functions for locating neighbouring labels.
|
91
|
+
#
|
92
|
+
# @private
|
93
|
+
def knot( args, comp )
|
94
|
+
n = @n.simplify
|
95
|
+
if dimension > 0
|
96
|
+
subargs1, subargs2, subargs3 = [], [], []
|
97
|
+
subcomp1, subcomp2, subcomp3 = [], [], []
|
98
|
+
args.each do |arg|
|
99
|
+
subargs1.push proc { |i| arg.element( i - 1 ).demand }
|
100
|
+
subargs2.push proc { |i| arg.element( i ).demand }
|
101
|
+
subargs3.push proc { |i| arg.element( i + 1 ).demand }
|
102
|
+
end
|
103
|
+
comp.each do |c|
|
104
|
+
subcomp1.push proc { |i| c.element( i - 1 ) }
|
105
|
+
subcomp2.push proc { |i| c.element( i ) }
|
106
|
+
subcomp3.push proc { |i| c.element( i + 1 ) }
|
107
|
+
end
|
108
|
+
self.class.new( @dest.element( INT.new( 0 ) ),
|
109
|
+
@source.element( INT.new( 0 ) ).demand, @default, @zero,
|
110
|
+
@labels, @rank, n ).
|
111
|
+
knot( ( subargs2 + subargs3 ).collect { |p| p.call INT.new( 0 ) },
|
112
|
+
( subcomp2 + subcomp3 ).collect { |p| p.call INT.new( 0 ) } )
|
113
|
+
INT.new( 1 ).upto INT.new( @source.shape.last ) - 2 do |i|
|
114
|
+
self.class.new( @dest.element( INT.new( i ) ),
|
115
|
+
@source.element( INT.new( i ) ).demand, @default, @zero,
|
116
|
+
@labels, @rank, n ).
|
117
|
+
knot( ( subargs1 + subargs2 + subargs3 ).collect { |p| p.call INT.new( i ) } +
|
118
|
+
[ @source.element( INT.new( i ) - 1 ) ],
|
119
|
+
( subcomp1 + subcomp2 + subcomp3 ).collect { |p| p.call INT.new( i ) } +
|
120
|
+
[ @dest.element( INT.new( i ) - 1 ) ] )
|
121
|
+
end
|
122
|
+
i = @source.shape.last - 1
|
123
|
+
self.class.new( @dest.element( INT.new( i ) ),
|
124
|
+
@source.element( INT.new( i ) ).demand, @default, @zero,
|
125
|
+
@labels, @rank, n ).
|
126
|
+
knot( ( subargs1 + subargs2 ).collect { |p| p.call INT.new( i ) } +
|
127
|
+
[ @source.element( INT.new( i ) - 1 ) ],
|
128
|
+
( subcomp1 + subcomp2 ).collect { |p| p.call INT.new( i ) } +
|
129
|
+
[ @dest.element( INT.new( i ) - 1 ) ] )
|
130
|
+
else
|
131
|
+
@source.ne( @default ).if_else( proc do
|
132
|
+
label = @zero.simplify
|
133
|
+
args.zip( comp ).each do |arg,other|
|
134
|
+
@source.eq( arg ).if do
|
135
|
+
other = other.simplify
|
136
|
+
proc { other.ne( @labels.element( other ).demand ) }.while do
|
137
|
+
other.assign @labels.element( other ).demand
|
138
|
+
end
|
139
|
+
label.eq( @zero ).if_else( proc do
|
140
|
+
label.assign other
|
141
|
+
end, proc do
|
142
|
+
label.ne( other ).if do
|
143
|
+
( @rank.element( label ).demand <= @rank.element( other ).demand ).if_else( proc do
|
144
|
+
@labels[ other ] = label
|
145
|
+
@rank.element( label ).demand.eq( @rank.element( other ).demand ).if do
|
146
|
+
@rank[ label ] = @rank.element( other ).demand + 1
|
147
|
+
end
|
148
|
+
end, proc do
|
149
|
+
@labels[ label ] = other
|
150
|
+
label.assign other
|
151
|
+
end )
|
152
|
+
end
|
153
|
+
end )
|
154
|
+
end
|
155
|
+
end
|
156
|
+
label.eq( @zero ).if do
|
157
|
+
n.assign n + 1
|
158
|
+
@labels[ n ] = n
|
159
|
+
@rank[ n ] = 0
|
160
|
+
label.assign n
|
161
|
+
end
|
162
|
+
@dest.store label
|
163
|
+
end, proc do
|
164
|
+
@dest.store INT.new( 0 )
|
165
|
+
end )
|
166
|
+
end
|
167
|
+
if @n.is_a? Pointer_
|
168
|
+
INT.new( 0 ).upto n do |i|
|
169
|
+
l = UINT.new( i ).simplify
|
170
|
+
proc { l.ne( @labels.element( l ).demand ) }.while do
|
171
|
+
l.assign @labels.element( l ).demand
|
172
|
+
end
|
173
|
+
@labels[ INT.new( i ) ] = l
|
174
|
+
end
|
175
|
+
@n.store n
|
176
|
+
else
|
177
|
+
@n.assign n
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Substitute variables
|
182
|
+
#
|
183
|
+
# Substitute the variables with the values given in the hash.
|
184
|
+
#
|
185
|
+
# @param [Hash] hash Substitutions to apply.
|
186
|
+
#
|
187
|
+
# @return [Node] Term with substitutions applied.
|
188
|
+
#
|
189
|
+
# @private
|
190
|
+
def subst( hash )
|
191
|
+
self.class.new @dest.subst( hash ), @source.subst( hash ), @default.subst( hash ),
|
192
|
+
@zero.subst( hash ), @labels.subst( hash ), @rank.subst( hash ), @n.subst( hash )
|
193
|
+
end
|
194
|
+
|
195
|
+
# Get variables contained in this term
|
196
|
+
#
|
197
|
+
# @return [Set] Returns list of variables.
|
198
|
+
#
|
199
|
+
# @private
|
200
|
+
def variables
|
201
|
+
@dest.variables + @source.variables + @default.variables + @zero.variables +
|
202
|
+
@labels.variables + @rank.variables + @n.variables
|
203
|
+
end
|
204
|
+
|
205
|
+
# Strip of all values
|
206
|
+
#
|
207
|
+
# Split up into variables, values, and a term where all values have been
|
208
|
+
# replaced with variables.
|
209
|
+
#
|
210
|
+
# @return [Array<Array,Node>] Returns an array of variables, an array of
|
211
|
+
# values, and the term based on variables.
|
212
|
+
#
|
213
|
+
# @private
|
214
|
+
def strip
|
215
|
+
stripped = [ @dest, @source, @default, @zero, @labels, @rank, @n ].
|
216
|
+
collect { |value| value.strip }
|
217
|
+
return stripped.inject( [] ) { |vars,elem| vars + elem[ 0 ] },
|
218
|
+
stripped.inject( [] ) { |values,elem| values + elem[ 1 ] },
|
219
|
+
self.class.new( *stripped.collect { |elem| elem[ 2 ] } )
|
220
|
+
end
|
221
|
+
|
222
|
+
# Get variables contained in this term
|
223
|
+
#
|
224
|
+
# @return [Set] Returns list of variables.
|
225
|
+
#
|
226
|
+
# @private
|
227
|
+
def compilable?
|
228
|
+
[ @dest, @source, @default, @zero, @labels, @rank, @n ].all? do |value|
|
229
|
+
value.compilable?
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
data/lib/multiarray/diagonal.rb
CHANGED
@@ -106,7 +106,7 @@ module Hornetseye
|
|
106
106
|
j0.upto( ( @index2.size - 1 ).minor( @index0 + s1 ) ) do |j|
|
107
107
|
i = @index0.get + s1.get - j
|
108
108
|
sub = @value.subst @index1 => INT.new( i ), @index2 => INT.new( j )
|
109
|
-
retval.
|
109
|
+
retval.assign @block.subst( @var1 => retval, @var2 => sub )
|
110
110
|
end
|
111
111
|
retval
|
112
112
|
end
|
data/lib/multiarray/element.rb
CHANGED
@@ -93,7 +93,7 @@ module Hornetseye
|
|
93
93
|
def dup
|
94
94
|
if Thread.current[ :function ]
|
95
95
|
value = Thread.current[ :function ].variable self.class, 'v'
|
96
|
-
value.
|
96
|
+
value.assign get
|
97
97
|
self.class.new value
|
98
98
|
else
|
99
99
|
self.class.new get
|
@@ -155,9 +155,9 @@ module Hornetseye
|
|
155
155
|
# @return [Object] Returns +value+.
|
156
156
|
#
|
157
157
|
# @private
|
158
|
-
def
|
159
|
-
if @value.respond_to? :
|
160
|
-
@value.
|
158
|
+
def assign( value )
|
159
|
+
if @value.respond_to? :assign
|
160
|
+
@value.assign value.simplify.get
|
161
161
|
else
|
162
162
|
@value = value.simplify.get
|
163
163
|
end
|
@@ -196,3 +196,32 @@ module Hornetseye
|
|
196
196
|
end
|
197
197
|
|
198
198
|
end
|
199
|
+
|
200
|
+
class Proc
|
201
|
+
|
202
|
+
# Overloaded while loop for handling compilation
|
203
|
+
#
|
204
|
+
# @param [Proc] action The loop body
|
205
|
+
#
|
206
|
+
# @return [NilClass] Returns +nil+.
|
207
|
+
#
|
208
|
+
# @private
|
209
|
+
def while_with_gcc( &action )
|
210
|
+
function = Thread.current[ :function ]
|
211
|
+
if function
|
212
|
+
function << "#{function.indent}while ( 1 ) {\n"
|
213
|
+
function.indent_offset +1
|
214
|
+
function << "#{function.indent}if ( !( #{call.get}) ) break;\n"
|
215
|
+
action.call
|
216
|
+
function.indent_offset -1
|
217
|
+
function << "#{function.indent}}\n"
|
218
|
+
nil
|
219
|
+
else
|
220
|
+
while_without_gcc &action
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
alias_method_chain :while, :gcc
|
225
|
+
|
226
|
+
end
|
227
|
+
|
data/lib/multiarray/gccvalue.rb
CHANGED
@@ -163,7 +163,7 @@ module Hornetseye
|
|
163
163
|
# @return [Object] Returns +value+.
|
164
164
|
#
|
165
165
|
# @private
|
166
|
-
def
|
166
|
+
def assign( value )
|
167
167
|
@function << "#{@function.indent}#{self} = #{value};\n"
|
168
168
|
value
|
169
169
|
end
|
@@ -370,7 +370,6 @@ module Hornetseye
|
|
370
370
|
self
|
371
371
|
end
|
372
372
|
|
373
|
-
|
374
373
|
define_unary_op :not, '!'
|
375
374
|
define_unary_op :~
|
376
375
|
define_unary_op :-@, :-
|
data/lib/multiarray/inject.rb
CHANGED
@@ -96,7 +96,7 @@ module Hornetseye
|
|
96
96
|
end
|
97
97
|
offset.upto @index.size - 1 do |i|
|
98
98
|
sub = @value.subst @index => INT.new( i )
|
99
|
-
retval.
|
99
|
+
retval.assign @block.subst( @var1 => retval, @var2 => sub )
|
100
100
|
end
|
101
101
|
retval
|
102
102
|
end
|
@@ -109,7 +109,7 @@ module Hornetseye
|
|
109
109
|
#
|
110
110
|
# @private
|
111
111
|
def element( i )
|
112
|
-
|
112
|
+
self.class.new @value.element( i ), @index, @initial, @block, @var1, @var2
|
113
113
|
end
|
114
114
|
|
115
115
|
# Get variables contained in this term
|
@@ -142,7 +142,7 @@ module Hornetseye
|
|
142
142
|
vars3, values3, term3 = @block.strip
|
143
143
|
return vars1 + vars2 + vars3 + meta_vars,
|
144
144
|
values1 + values2 + values3 + meta_values,
|
145
|
-
|
145
|
+
self.class.new( term1, var, term2, term3, @var1, @var2 )
|
146
146
|
end
|
147
147
|
|
148
148
|
# Substitute variables
|
@@ -159,7 +159,7 @@ module Hornetseye
|
|
159
159
|
value = @value.subst( @index => subst_var ).subst hash
|
160
160
|
initial = @initial ? @initial.subst( hash ) : nil
|
161
161
|
block = @block.subst hash
|
162
|
-
|
162
|
+
self.class.new value, subst_var, initial, block, @var1, @var2
|
163
163
|
end
|
164
164
|
|
165
165
|
# Check whether this term is compilable
|
data/lib/multiarray/mask.rb
CHANGED
@@ -81,12 +81,16 @@ module Hornetseye
|
|
81
81
|
Mask.new( @dest, source, m, index ).demand
|
82
82
|
end
|
83
83
|
else
|
84
|
-
@m.
|
84
|
+
@m.if do
|
85
85
|
Store.new( @dest.element( index ), @source ).demand
|
86
|
-
index.
|
86
|
+
index.assign index + 1
|
87
87
|
end
|
88
88
|
end
|
89
|
-
@index.
|
89
|
+
if @index.is_a? Pointer_
|
90
|
+
@index.store index
|
91
|
+
else
|
92
|
+
@index.assign index
|
93
|
+
end
|
90
94
|
@dest
|
91
95
|
else
|
92
96
|
super
|
@@ -213,6 +213,34 @@ module Hornetseye
|
|
213
213
|
end
|
214
214
|
end
|
215
215
|
|
216
|
+
# Generate code for memory allocation
|
217
|
+
#
|
218
|
+
# @return [GCCValue] C value referring to result.
|
219
|
+
#
|
220
|
+
# @private
|
221
|
+
def malloc
|
222
|
+
get.malloc
|
223
|
+
end
|
224
|
+
|
225
|
+
# Conditional operation
|
226
|
+
#
|
227
|
+
# @param [Proc] action Action to perform if condition is +true+.
|
228
|
+
#
|
229
|
+
# @return [Object] The return value should be ignored.
|
230
|
+
def if( &action )
|
231
|
+
simplify.get.if &action
|
232
|
+
end
|
233
|
+
|
234
|
+
# Conditional operation
|
235
|
+
#
|
236
|
+
# @param [Proc] action1 Action to perform if condition is +true+.
|
237
|
+
# @param [Proc] action2 Action to perform if condition is +false+.
|
238
|
+
#
|
239
|
+
# @return [Object] The return value should be ignored.
|
240
|
+
def if_else( action1, action2 )
|
241
|
+
simplify.get.if_else action1, action2
|
242
|
+
end
|
243
|
+
|
216
244
|
# Element-wise comparison of values
|
217
245
|
#
|
218
246
|
# @param [Node] other Array with values to compare with.
|
@@ -390,6 +418,13 @@ module Hornetseye
|
|
390
418
|
min( initial ? initial.min : nil ) .. max( initial ? initial.max : nil )
|
391
419
|
end
|
392
420
|
|
421
|
+
# Check values against boundaries
|
422
|
+
#
|
423
|
+
# @return [Node] Boolean array with result.
|
424
|
+
def between?( a, b )
|
425
|
+
Hornetseye::lazy { ( self >= a ).and self <= b }.force
|
426
|
+
end
|
427
|
+
|
393
428
|
# Normalise values of array
|
394
429
|
#
|
395
430
|
# @param [Range] range Target range of normalisation.
|
@@ -621,12 +656,12 @@ module Hornetseye
|
|
621
656
|
# @return [Node] The histogram.
|
622
657
|
def histogram( *ret_shape )
|
623
658
|
options = ret_shape.last.is_a?( Hash ) ? ret_shape.pop : {}
|
624
|
-
options = { :weight => UINT.
|
659
|
+
options = { :weight => UINT.new( 1 ), :safe => true }.merge options
|
625
660
|
unless options[ :weight ].is_a? Node
|
626
661
|
options[ :weight ] =
|
627
662
|
Node.match( options[ :weight ] ).maxint.new options[ :weight ]
|
628
663
|
end
|
629
|
-
if shape.first != 1 and ret_shape.size == 1
|
664
|
+
if ( shape.first != 1 or dimension == 1 ) and ret_shape.size == 1
|
630
665
|
[ self ].histogram *( ret_shape + [ options ] )
|
631
666
|
else
|
632
667
|
( 0 ... shape.first ).collect { |i| unroll[i] }.
|
@@ -642,7 +677,7 @@ module Hornetseye
|
|
642
677
|
#
|
643
678
|
# @return [Node] The result of the lookup operation.
|
644
679
|
def lut( table, options = {} )
|
645
|
-
if shape.first != 1 and table.dimension == 1
|
680
|
+
if ( shape.first != 1 or dimension == 1 ) and table.dimension == 1
|
646
681
|
[ self ].lut table, options
|
647
682
|
else
|
648
683
|
( 0 ... shape.first ).collect { |i| unroll[i] }.lut table, options
|
@@ -690,6 +725,35 @@ module Hornetseye
|
|
690
725
|
left
|
691
726
|
end
|
692
727
|
|
728
|
+
# Perform connected component labelling
|
729
|
+
#
|
730
|
+
# @option options [Object] :default (typecode.default) Value of background elements.
|
731
|
+
# @option options [Class] :target (UINT) Typecode of labels.
|
732
|
+
#
|
733
|
+
# @return [Node] Array with labels of connected components.
|
734
|
+
def components( options = {} )
|
735
|
+
if shape.any? { |x| x <= 1 }
|
736
|
+
raise "Every dimension must be greater than 1 (shape was #{shape})"
|
737
|
+
end
|
738
|
+
options = { :target => UINT, :default => typecode.default }.merge options
|
739
|
+
target = options[ :target ]
|
740
|
+
default = options[ :default ]
|
741
|
+
default = typecode.new default unless default.is_a? Node
|
742
|
+
left = Hornetseye::MultiArray( target, *shape ).new
|
743
|
+
labels = Sequence.new target, size; labels[0] = 0
|
744
|
+
rank = Sequence.uint size; rank[0] = 0
|
745
|
+
n = Hornetseye::Pointer( INT ).new; n.store INT.new( 0 )
|
746
|
+
block = Components.new left, self, default, target.new( 0 ), labels, rank, n
|
747
|
+
if block.compilable?
|
748
|
+
Hornetseye::GCCFunction.run block
|
749
|
+
else
|
750
|
+
block.demand
|
751
|
+
end
|
752
|
+
labels = labels[ 0 .. n.demand.get ]
|
753
|
+
left.lut labels.lut( labels.histogram( labels.size, :weight => target.new( 1 ) ).
|
754
|
+
minor( 1 ).integral - 1 )
|
755
|
+
end
|
756
|
+
|
693
757
|
# Select values from array using a mask
|
694
758
|
#
|
695
759
|
# @param [Node] m Mask to apply to this array.
|
data/lib/multiarray/pointer.rb
CHANGED
@@ -184,6 +184,22 @@ module Hornetseye
|
|
184
184
|
"#{self.class.to_s}(#{@value.to_s})"
|
185
185
|
end
|
186
186
|
|
187
|
+
# Store a value in this native element
|
188
|
+
#
|
189
|
+
# @param [Object] value New value for native element.
|
190
|
+
#
|
191
|
+
# @return [Object] Returns +value+.
|
192
|
+
#
|
193
|
+
# @private
|
194
|
+
def assign( value )
|
195
|
+
if @value.respond_to? :assign
|
196
|
+
@value.assign value.simplify.get
|
197
|
+
else
|
198
|
+
@value = value.simplify.get
|
199
|
+
end
|
200
|
+
value
|
201
|
+
end
|
202
|
+
|
187
203
|
# Store new value in this pointer
|
188
204
|
#
|
189
205
|
# @param [Object] value New value for this pointer object.
|
data/lib/multiarray/rgb.rb
CHANGED
@@ -125,7 +125,7 @@ module Hornetseye
|
|
125
125
|
# @return [Object] Returns +value+.
|
126
126
|
#
|
127
127
|
# @private
|
128
|
-
def
|
128
|
+
def assign( value )
|
129
129
|
@r, @g, @b = value.r, value.g, value.b
|
130
130
|
end
|
131
131
|
|
@@ -407,9 +407,9 @@ module Hornetseye
|
|
407
407
|
r = Thread.current[ :function ].variable self.class.element_type, 'v'
|
408
408
|
g = Thread.current[ :function ].variable self.class.element_type, 'v'
|
409
409
|
b = Thread.current[ :function ].variable self.class.element_type, 'v'
|
410
|
-
r.
|
411
|
-
g.
|
412
|
-
b.
|
410
|
+
r.assign @value.r
|
411
|
+
g.assign @value.g
|
412
|
+
b.assign @value.b
|
413
413
|
self.class.new RGB.new( r, g, b )
|
414
414
|
else
|
415
415
|
self.class.new get
|
@@ -423,20 +423,20 @@ module Hornetseye
|
|
423
423
|
# @return [Object] Returns +value+.
|
424
424
|
#
|
425
425
|
# @private
|
426
|
-
def
|
426
|
+
def assign( value )
|
427
427
|
value = value.simplify
|
428
|
-
if @value.r.respond_to? :
|
429
|
-
@value.r.
|
428
|
+
if @value.r.respond_to? :assign
|
429
|
+
@value.r.assign value.get.r
|
430
430
|
else
|
431
431
|
@value.r = value.get.r
|
432
432
|
end
|
433
|
-
if @value.g.respond_to? :
|
434
|
-
@value.g.
|
433
|
+
if @value.g.respond_to? :assign
|
434
|
+
@value.g.assign value.get.g
|
435
435
|
else
|
436
436
|
@value.g = value.get.g
|
437
437
|
end
|
438
|
-
if @value.b.respond_to? :
|
439
|
-
@value.b.
|
438
|
+
if @value.b.respond_to? :assign
|
439
|
+
@value.b.assign value.get.b
|
440
440
|
else
|
441
441
|
@value.b = value.get.b
|
442
442
|
end
|
@@ -935,3 +935,19 @@ class Fixnum
|
|
935
935
|
|
936
936
|
end
|
937
937
|
|
938
|
+
module Math
|
939
|
+
|
940
|
+
def sqrt_with_rgb( c )
|
941
|
+
if c.is_a? Hornetseye::RGB
|
942
|
+
Hornetseye::RGB.new sqrt( c.r ), sqrt( c.g ), sqrt( c.b )
|
943
|
+
else
|
944
|
+
sqrt_without_rgb c
|
945
|
+
end
|
946
|
+
end
|
947
|
+
|
948
|
+
alias_method_chain :sqrt, :rgb
|
949
|
+
module_function :sqrt_without_rgb
|
950
|
+
module_function :sqrt
|
951
|
+
|
952
|
+
end
|
953
|
+
|
data/lib/multiarray/store.rb
CHANGED
data/lib/multiarray/unmask.rb
CHANGED
@@ -84,14 +84,18 @@ module Hornetseye
|
|
84
84
|
Unmask.new( dest, @source, m, index, default ).demand
|
85
85
|
end
|
86
86
|
else
|
87
|
-
@m.
|
87
|
+
@m.if_else( proc do
|
88
88
|
Store.new( @dest, @source.element( index ) ).demand
|
89
|
-
index.
|
89
|
+
index.assign index + 1
|
90
90
|
end, proc do
|
91
91
|
Store.new( @dest, @default ).demand
|
92
92
|
end )
|
93
93
|
end
|
94
|
-
@index.
|
94
|
+
if @index.is_a? Pointer_
|
95
|
+
@index.store index
|
96
|
+
else
|
97
|
+
@index.assign index
|
98
|
+
end
|
95
99
|
@dest
|
96
100
|
else
|
97
101
|
super
|
data/test/tc_multiarray.rb
CHANGED
@@ -731,6 +731,11 @@ class TC_MultiArray < Test::Unit::TestCase
|
|
731
731
|
M( I, 3, 2 )[ [ 1, 2, 3 ], [ 4, 5, 6 ] ].integral
|
732
732
|
end
|
733
733
|
|
734
|
+
def test_components
|
735
|
+
assert_equal [ [ 1, 0, 2 ], [ 0, 0, 2 ], [ 2, 2, 2 ] ],
|
736
|
+
M[ [ 1, 0, 1 ], [ 0, 0, 1 ], [ 1, 1, 1 ] ].components.to_a
|
737
|
+
end
|
738
|
+
|
734
739
|
def test_mask
|
735
740
|
[ O, I ].each do |t|
|
736
741
|
assert_equal M( O, 2, 2 )[ [ 1, 2 ], [ 5, 7 ] ],
|
data/test/tc_sequence.rb
CHANGED
@@ -334,6 +334,10 @@ class TC_Sequence < Test::Unit::TestCase
|
|
334
334
|
assert_equal C( 3, 2, 3 ), S[ C( 1, 2, 3 ), C( 3, 2, 1 ) ].max
|
335
335
|
end
|
336
336
|
|
337
|
+
def test_between
|
338
|
+
assert_equal S[ false, true, true, false ], S[ 1, 2, 3, 4 ].between?( 2, 3 )
|
339
|
+
end
|
340
|
+
|
337
341
|
def test_normalise
|
338
342
|
assert_equal [ 0.0, 85.0, 255.0 ], S[ 1, 2, 4 ].normalise.to_a
|
339
343
|
assert_equal [ C( 0.0, 85.0, 255.0 ) ], S[ C( 1, 2, 4 ) ].normalise.to_a
|
@@ -713,6 +717,12 @@ class TC_Sequence < Test::Unit::TestCase
|
|
713
717
|
assert_in_delta x.real, y.real, 1.0e-5
|
714
718
|
assert_in_delta x.imag, y.imag, 1.0e-5
|
715
719
|
end
|
720
|
+
[ Math.sqrt( C( 1, 2, 3 ) ), Math.sqrt( C( 2, 4, 6 ) ) ].
|
721
|
+
zip( Math.sqrt( S[ C( 1, 2, 3 ), C( 2, 4, 6 ) ] ).to_a ).each do |x,y|
|
722
|
+
assert_in_delta x.r, y.r, 1.0e-5
|
723
|
+
assert_in_delta x.g, y.g, 1.0e-5
|
724
|
+
assert_in_delta x.b, y.b, 1.0e-5
|
725
|
+
end
|
716
726
|
end
|
717
727
|
|
718
728
|
def test_exp
|
@@ -928,6 +938,11 @@ class TC_Sequence < Test::Unit::TestCase
|
|
928
938
|
assert_equal S( I, 3 )[ 1, 3, 6 ], S( I, 3 )[ 1, 2, 3 ].integral
|
929
939
|
end
|
930
940
|
|
941
|
+
def test_components
|
942
|
+
assert_equal [ 0, 1, 1, 0, 2 ], S[ 0, 1, 1, 0, 1 ].components.to_a
|
943
|
+
assert_equal [ 0, 1, 1, 0, 2 ], S[ nil, 1, 1, nil, 1 ].components.to_a
|
944
|
+
end
|
945
|
+
|
931
946
|
def test_mask
|
932
947
|
assert_equal S( O, 2 )[ 2, 5 ], S( O, 3 )[ 2, 3, 5 ].
|
933
948
|
mask( S[ true, false, true ] )
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 21
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.21.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jan Wedekind
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-02-27 00:00:00 +00:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -66,6 +66,7 @@ files:
|
|
66
66
|
- lib/multiarray/gcccontext.rb
|
67
67
|
- lib/multiarray/unmask.rb
|
68
68
|
- lib/multiarray/elementwise.rb
|
69
|
+
- lib/multiarray/components.rb
|
69
70
|
- lib/multiarray/diagonal.rb
|
70
71
|
- lib/multiarray/index.rb
|
71
72
|
- lib/multiarray/variable.rb
|