multiarray 0.18.1 → 0.19.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 +66 -0
- data/lib/multiarray/multiarray.rb +33 -1
- data/lib/multiarray/operations.rb +89 -3
- data/test/tc_multiarray.rb +16 -0
- data/test/tc_sequence.rb +22 -0
- metadata +41 -41
data/Rakefile
CHANGED
data/lib/multiarray.rb
CHANGED
@@ -585,6 +585,72 @@ end
|
|
585
585
|
# The +Array+ class is extended with a few methods
|
586
586
|
class Array
|
587
587
|
|
588
|
+
class << self
|
589
|
+
|
590
|
+
# Compute Gauss blur filter
|
591
|
+
#
|
592
|
+
# Compute a filter for approximating a Gaussian blur. The size of the
|
593
|
+
# filter is determined by the given error bound.
|
594
|
+
#
|
595
|
+
# @param [Float] sigma Spread of blur filter.
|
596
|
+
# @param [Float] max_error Upper bound for filter error.
|
597
|
+
#
|
598
|
+
# @return [Array] An array with the filter elements.
|
599
|
+
def gauss_blur_filter( sigma, max_error = 1.0 / 0x100 )
|
600
|
+
def erf( x, sigma )
|
601
|
+
0.5 * Math.erf( x / ( Math.sqrt( 2.0 ) * sigma.abs ) )
|
602
|
+
end
|
603
|
+
raise 'Sigma must be greater than zero.' if sigma <= 0
|
604
|
+
# Integral of Gauss-bell from -0.5 to +0.5.
|
605
|
+
integral = erf( +0.5, sigma ) - erf( -0.5, sigma )
|
606
|
+
retVal = [ integral ]
|
607
|
+
while 1.0 - integral > max_error
|
608
|
+
# Integral of Gauss-bell from -size2 to +size2.
|
609
|
+
size2 = 0.5 * ( retVal.size + 2 )
|
610
|
+
nIntegral = erf( +size2, sigma ) - erf( -size2, sigma )
|
611
|
+
value = 0.5 * ( nIntegral - integral )
|
612
|
+
retVal.unshift( value )
|
613
|
+
retVal.push( value )
|
614
|
+
integral = nIntegral
|
615
|
+
end
|
616
|
+
# Normalise result.
|
617
|
+
retVal.collect { |element| element / integral }
|
618
|
+
end
|
619
|
+
|
620
|
+
# Compute Gauss gradient filter
|
621
|
+
#
|
622
|
+
# Compute a filter for approximating a Gaussian gradient. The size of the
|
623
|
+
# filter is determined by the given error bound.
|
624
|
+
#
|
625
|
+
# @param [Float] sigma Spread of blur filter.
|
626
|
+
# @param [Float] max_error Upper bound for filter error.
|
627
|
+
#
|
628
|
+
# @return [Array] An array with the filter elements.
|
629
|
+
def gauss_gradient_filter( sigma, max_error = 1.0 / 0x100 )
|
630
|
+
def gauss( x, sigma )
|
631
|
+
1.0 / ( Math.sqrt( 2.0 * Math::PI ) * sigma.abs ) *
|
632
|
+
Math.exp( -x**2 / ( 2.0 * sigma**2 ) )
|
633
|
+
end
|
634
|
+
raise 'Sigma must be greater than zero.' if sigma <= 0
|
635
|
+
# Integral of Gauss-gradient from -0.5 to +0.5.
|
636
|
+
retVal = [ gauss( +0.5, sigma ) - gauss( -0.5, sigma ) ]
|
637
|
+
# Absolute integral of Gauss-gradient from 0.5 to infinity.
|
638
|
+
integral = gauss( 0.5, sigma )
|
639
|
+
sumX = 0
|
640
|
+
while 2.0 * integral > max_error
|
641
|
+
size2 = 0.5 * ( retVal.size + 2 )
|
642
|
+
nIntegral = gauss( size2, sigma )
|
643
|
+
value = integral - nIntegral
|
644
|
+
retVal.unshift( -value )
|
645
|
+
retVal.push( +value )
|
646
|
+
sumX += value * ( retVal.size - 1 )
|
647
|
+
integral = nIntegral
|
648
|
+
end
|
649
|
+
retVal.collect { |element| element / sumX }
|
650
|
+
end
|
651
|
+
|
652
|
+
end
|
653
|
+
|
588
654
|
# Element-wise operation based on element and its index
|
589
655
|
#
|
590
656
|
# Same as +Array#collect+ but with index.
|
@@ -74,7 +74,7 @@ module Hornetseye
|
|
74
74
|
# shape of the array is determined. Finally the elements are coopied to the
|
75
75
|
# resulting array.
|
76
76
|
#
|
77
|
-
# @param [Array<Object>] *args
|
77
|
+
# @param [Array<Object>] *args The array elements.
|
78
78
|
#
|
79
79
|
# @return [Node] Uniform multi-dimensional array.
|
80
80
|
def []( *args )
|
@@ -82,6 +82,38 @@ module Hornetseye
|
|
82
82
|
target[ *args ]
|
83
83
|
end
|
84
84
|
|
85
|
+
# Compute Laplacian of Gaussian filter
|
86
|
+
#
|
87
|
+
# @param [Float] sigma Spread of filter.
|
88
|
+
# @param [Integer] size Size of filter (*e.g.* 9 for 9x9 filter)
|
89
|
+
#
|
90
|
+
# @return[Node] The filter.
|
91
|
+
def laplacian_of_gaussian( sigma = 1.4, size = 9 )
|
92
|
+
def erf( x, sigma )
|
93
|
+
0.5 * Math.erf( x / ( Math.sqrt( 2.0 ) * sigma.abs ) )
|
94
|
+
end
|
95
|
+
def gauss_gradient( x, sigma )
|
96
|
+
-x / ( Math.sqrt( 2.0 * Math::PI * sigma.abs**5 ) ) *
|
97
|
+
Math.exp( -x**2 / ( 2.0 * sigma**2 ) )
|
98
|
+
end
|
99
|
+
retval = new DFLOAT, size, size
|
100
|
+
sum = 0
|
101
|
+
for y in 0 .. size - 1
|
102
|
+
y0 = y - 0.5 * size
|
103
|
+
y1 = y0 + 1
|
104
|
+
y_grad_diff = gauss_gradient( y1, sigma ) - gauss_gradient( y0, sigma )
|
105
|
+
y_erf_diff = erf( y1, sigma ) - erf( y0, sigma )
|
106
|
+
for x in 0..size-1
|
107
|
+
x0 = x - 0.5 * size
|
108
|
+
x1 = x0 + 1
|
109
|
+
x_grad_diff = gauss_gradient( x1, sigma ) - gauss_gradient( x0, sigma )
|
110
|
+
x_erf_diff = erf( x1, sigma ) - erf( x0, sigma )
|
111
|
+
retval[ y, x ] = y_grad_diff * x_erf_diff + y_erf_diff * x_grad_diff
|
112
|
+
end
|
113
|
+
end
|
114
|
+
retval
|
115
|
+
end
|
116
|
+
|
85
117
|
end
|
86
118
|
|
87
119
|
end
|
@@ -329,6 +329,14 @@ module Hornetseye
|
|
329
329
|
end
|
330
330
|
end
|
331
331
|
|
332
|
+
def each( &action )
|
333
|
+
if dimension > 0
|
334
|
+
shape.last.times { |i| element( INT.new( i ) ).each &action }
|
335
|
+
else
|
336
|
+
action.call demand.get
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
332
340
|
# Equality operator
|
333
341
|
#
|
334
342
|
# @return [Boolean] Returns result of comparison.
|
@@ -402,7 +410,7 @@ module Hornetseye
|
|
402
410
|
if current.last != current.first
|
403
411
|
factor =
|
404
412
|
( range.last - range.first ).to_f / ( current.last - current.first )
|
405
|
-
|
413
|
+
collect { |x| x * factor + ( range.first - current.first * factor ) }
|
406
414
|
else
|
407
415
|
self + ( range.first - current.first )
|
408
416
|
end
|
@@ -418,7 +426,7 @@ module Hornetseye
|
|
418
426
|
raise "Clipping does not support ranges with end value " +
|
419
427
|
"excluded (such as #{range})"
|
420
428
|
end
|
421
|
-
major( range.begin ).minor range.end
|
429
|
+
collect { |x| x.major( range.begin ).minor range.end }
|
422
430
|
end
|
423
431
|
|
424
432
|
# Fill array with a value
|
@@ -511,6 +519,48 @@ module Hornetseye
|
|
511
519
|
array.product( filter ).diagonal { |s,x| s + x }
|
512
520
|
end
|
513
521
|
|
522
|
+
# Create spread array similar to product array
|
523
|
+
#
|
524
|
+
# Used internally to implement erosion and dilation.
|
525
|
+
#
|
526
|
+
# @param [Integer] n Size of spread.
|
527
|
+
#
|
528
|
+
# @return [Node] Result of operation.
|
529
|
+
#
|
530
|
+
# @see #erode
|
531
|
+
# @see #dilate
|
532
|
+
#
|
533
|
+
# @private
|
534
|
+
def spread( n = 3 )
|
535
|
+
if dimension > 0
|
536
|
+
Hornetseye::lazy( n, shape.last ) { |i,j| self[j].spread n }
|
537
|
+
else
|
538
|
+
self
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
542
|
+
# Erosion
|
543
|
+
#
|
544
|
+
# The erosion operation works on boolean as well as scalar values.
|
545
|
+
#
|
546
|
+
# @param [Integer] n Size of erosion operator.
|
547
|
+
#
|
548
|
+
# @return [Node] Result of operation.
|
549
|
+
def erode( n = 3 )
|
550
|
+
spread( n ).diagonal { |m,x| m.minor x }
|
551
|
+
end
|
552
|
+
|
553
|
+
# Dilation
|
554
|
+
#
|
555
|
+
# The dilation operation works on boolean as well as scalar values.
|
556
|
+
#
|
557
|
+
# @param [Integer] n Size of dilation operator.
|
558
|
+
#
|
559
|
+
# @return [Node] Result of operation.
|
560
|
+
def dilate( n = 3 )
|
561
|
+
spread( n ).diagonal { |m,x| m.major x }
|
562
|
+
end
|
563
|
+
|
514
564
|
# Sobel operator
|
515
565
|
#
|
516
566
|
# @param [Integer] direction Orientation of Sobel filter.
|
@@ -524,6 +574,42 @@ module Hornetseye
|
|
524
574
|
end.force
|
525
575
|
end
|
526
576
|
|
577
|
+
# Gaussian blur
|
578
|
+
#
|
579
|
+
# @param [Float] sigma Spread of Gauss bell.
|
580
|
+
# @param [Float] max_error Error of approximated filter.
|
581
|
+
#
|
582
|
+
# @return [Node] Result of filter operation.
|
583
|
+
def gauss_blur( sigma, max_error = 1.0 / 0x100 )
|
584
|
+
filter_type = DFLOAT.align typecode
|
585
|
+
filter = Sequence[ *Array.gauss_blur_filter( sigma, max_error / dimension ) ].
|
586
|
+
to_type filter_type
|
587
|
+
( dimension - 1 ).downto( 0 ).inject self do |retval,i|
|
588
|
+
retval.convolve filter
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
# Gauss gradient
|
593
|
+
#
|
594
|
+
# @param [Float] sigma Spread of Gauss gradient.
|
595
|
+
# @param [Integer] direction Orientation of Gauss gradient.
|
596
|
+
# @param [Float] max_error Error of approximated filter.
|
597
|
+
#
|
598
|
+
# @return [Node] Result of filter operation.
|
599
|
+
def gauss_gradient( sigma, direction, max_error = 1.0 / 0x100 )
|
600
|
+
filter_type = DFLOAT.align typecode
|
601
|
+
gradient =
|
602
|
+
Sequence[ *Array.gauss_gradient_filter( sigma, max_error / dimension ) ].
|
603
|
+
to_type filter_type
|
604
|
+
blur =
|
605
|
+
Sequence[ *Array.gauss_blur_filter( sigma, max_error / dimension ) ].
|
606
|
+
to_type filter_type
|
607
|
+
( dimension - 1 ).downto( 0 ).inject self do |retval,i|
|
608
|
+
filter = i == direction ? gradient : blur
|
609
|
+
retval.convolve filter
|
610
|
+
end.force
|
611
|
+
end
|
612
|
+
|
527
613
|
# Compute histogram of this array
|
528
614
|
#
|
529
615
|
# @overload histogram( *ret_shape, options = {} )
|
@@ -586,7 +672,7 @@ module Hornetseye
|
|
586
672
|
inject { |a,b| a.and b }
|
587
673
|
end.conditional Lut.new( *( field + [ self ] ) ), options[ :default ]
|
588
674
|
else
|
589
|
-
field.lut self
|
675
|
+
field.lut self, :safe => false
|
590
676
|
end
|
591
677
|
end
|
592
678
|
|
data/test/tc_multiarray.rb
CHANGED
@@ -371,6 +371,12 @@ class TC_MultiArray < Test::Unit::TestCase
|
|
371
371
|
assert_equal M[ [ 6 ] ], M[ [ C( 1, 2, 3 ) ] ].collect { |x| x.r + x.g + x.b }
|
372
372
|
end
|
373
373
|
|
374
|
+
def test_each
|
375
|
+
a = []
|
376
|
+
M[ [ 1, 2, 3 ], [ 4, 5, 6 ] ].each { |x| a << x }
|
377
|
+
assert_equal [ 1, 2, 3, 4, 5, 6 ], a
|
378
|
+
end
|
379
|
+
|
374
380
|
def test_sum
|
375
381
|
m = M[ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
|
376
382
|
assert_equal 21, sum { |i,j| m[ i, j ] }
|
@@ -432,6 +438,16 @@ class TC_MultiArray < Test::Unit::TestCase
|
|
432
438
|
assert_raise( RuntimeError ) { S[ 1, 2, 3 ].convolve f }
|
433
439
|
end
|
434
440
|
|
441
|
+
def test_erode
|
442
|
+
assert_equal [ [ 0, 0, 0 ], [ 0, -1, -1 ], [ 0, -1, -1 ] ],
|
443
|
+
M[ [ 1, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, -1 ] ].erode.to_a
|
444
|
+
end
|
445
|
+
|
446
|
+
def test_dilate
|
447
|
+
assert_equal [ [ 1, 1, 0 ], [ 1, 1, 0 ], [ 0, 0, 0 ] ],
|
448
|
+
M[ [ 1, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, -1 ] ].dilate.to_a
|
449
|
+
end
|
450
|
+
|
435
451
|
def test_sobel
|
436
452
|
m = M[ [ 0, 0, 0, 0 ], [ 0, 1, 0, 0 ], [ 0, 0, 0, 0 ] ]
|
437
453
|
assert_equal [ [ -1, 0, 1, 0 ], [ -2, 0, 2, 0 ], [ -1, 0, 1, 0 ] ],
|
data/test/tc_sequence.rb
CHANGED
@@ -300,6 +300,12 @@ class TC_Sequence < Test::Unit::TestCase
|
|
300
300
|
assert_equal S[ 6 ], S[ C( 1, 2, 3 ) ].collect { |x| x.r + x.g + x.b }
|
301
301
|
end
|
302
302
|
|
303
|
+
def test_each
|
304
|
+
a = []
|
305
|
+
S[ 1, 2, 3 ].each { |x| a << x }
|
306
|
+
assert_equal [ 1, 2, 3 ], a
|
307
|
+
end
|
308
|
+
|
303
309
|
def test_sum
|
304
310
|
[ S( O, 3 ), S( I, 3 ) ].each do |t|
|
305
311
|
assert_equal 6, t[ 1, 2, 3 ].sum
|
@@ -366,6 +372,22 @@ class TC_Sequence < Test::Unit::TestCase
|
|
366
372
|
convolve( S[ C( 1, 0, 0 ), C( 0, 1, 0 ), C( 0, 0, 1 ) ] )
|
367
373
|
end
|
368
374
|
|
375
|
+
def test_erode
|
376
|
+
[ O, I ].each do |t|
|
377
|
+
assert_equal [ 1, 1, 1, 2, 2, 2 ], S( t, 6 )[ 1, 1, 2, 3, 2, 2 ].erode.to_a
|
378
|
+
end
|
379
|
+
assert_equal S[ false, false, true, false, false ],
|
380
|
+
S[ false, true, true, true, false ].erode
|
381
|
+
end
|
382
|
+
|
383
|
+
def test_dilate
|
384
|
+
[ O, I ].each do |t|
|
385
|
+
assert_equal [ 1, 2, 3, 3, 3, 2 ], S( t, 6 )[ 1, 1, 2, 3, 2, 2 ].dilate.to_a
|
386
|
+
end
|
387
|
+
assert_equal S[ false, true, true, true, false ],
|
388
|
+
S[ false, false, true, false, false ].dilate
|
389
|
+
end
|
390
|
+
|
369
391
|
def test_sobel
|
370
392
|
assert_equal [ 0, -1, 0, 1, 0 ], S[ 0, 0, 1, 0, 0 ].sobel( 0 ).to_a
|
371
393
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 19
|
8
|
+
- 0
|
9
|
+
version: 0.19.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-01-
|
17
|
+
date: 2011-01-25 00:00:00 +00:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -57,52 +57,52 @@ files:
|
|
57
57
|
- README.md
|
58
58
|
- COPYING
|
59
59
|
- .document
|
60
|
-
- lib/multiarray/object.rb
|
61
|
-
- lib/multiarray/operations.rb
|
62
|
-
- lib/multiarray/variable.rb
|
63
|
-
- lib/multiarray/gcctype.rb
|
64
60
|
- lib/multiarray/bool.rb
|
65
|
-
- lib/multiarray/element.rb
|
66
|
-
- lib/multiarray/gcccache.rb
|
67
|
-
- lib/multiarray/int.rb
|
68
|
-
- lib/multiarray/gccfunction.rb
|
69
|
-
- lib/multiarray/shortcuts.rb
|
70
|
-
- lib/multiarray/float.rb
|
71
|
-
- lib/multiarray/diagonal.rb
|
72
|
-
- lib/multiarray/inject.rb
|
73
|
-
- lib/multiarray/list.rb
|
74
|
-
- lib/multiarray/pointer.rb
|
75
|
-
- lib/multiarray/lambda.rb
|
76
|
-
- lib/multiarray/sequence.rb
|
77
|
-
- lib/multiarray/methods.rb
|
78
|
-
- lib/multiarray/integral.rb
|
79
61
|
- lib/multiarray/multiarray.rb
|
80
|
-
- lib/multiarray/unmask.rb
|
81
62
|
- lib/multiarray/node.rb
|
82
|
-
- lib/multiarray/
|
83
|
-
- lib/multiarray/mask.rb
|
84
|
-
- lib/multiarray/malloc.rb
|
85
|
-
- lib/multiarray/index.rb
|
63
|
+
- lib/multiarray/gccvalue.rb
|
86
64
|
- lib/multiarray/rgb.rb
|
65
|
+
- lib/multiarray/object.rb
|
87
66
|
- lib/multiarray/gcccontext.rb
|
88
|
-
- lib/multiarray/
|
89
|
-
- lib/multiarray/store.rb
|
67
|
+
- lib/multiarray/unmask.rb
|
90
68
|
- lib/multiarray/elementwise.rb
|
69
|
+
- lib/multiarray/diagonal.rb
|
70
|
+
- lib/multiarray/index.rb
|
71
|
+
- lib/multiarray/variable.rb
|
72
|
+
- lib/multiarray/lambda.rb
|
73
|
+
- lib/multiarray/integral.rb
|
74
|
+
- lib/multiarray/pointer.rb
|
75
|
+
- lib/multiarray/element.rb
|
76
|
+
- lib/multiarray/composite.rb
|
91
77
|
- lib/multiarray/lookup.rb
|
92
|
-
- lib/multiarray/
|
78
|
+
- lib/multiarray/sequence.rb
|
79
|
+
- lib/multiarray/gcctype.rb
|
80
|
+
- lib/multiarray/shortcuts.rb
|
93
81
|
- lib/multiarray/complex.rb
|
94
|
-
- lib/multiarray/
|
82
|
+
- lib/multiarray/mask.rb
|
83
|
+
- lib/multiarray/malloc.rb
|
95
84
|
- lib/multiarray/lut.rb
|
85
|
+
- lib/multiarray/int.rb
|
86
|
+
- lib/multiarray/gcccache.rb
|
87
|
+
- lib/multiarray/inject.rb
|
88
|
+
- lib/multiarray/list.rb
|
89
|
+
- lib/multiarray/gccfunction.rb
|
90
|
+
- lib/multiarray/histogram.rb
|
91
|
+
- lib/multiarray/float.rb
|
92
|
+
- lib/multiarray/random.rb
|
93
|
+
- lib/multiarray/operations.rb
|
94
|
+
- lib/multiarray/store.rb
|
95
|
+
- lib/multiarray/methods.rb
|
96
96
|
- lib/multiarray.rb
|
97
97
|
- test/ts_multiarray.rb
|
98
|
+
- test/tc_int.rb
|
99
|
+
- test/tc_object.rb
|
98
100
|
- test/tc_float.rb
|
99
|
-
- test/
|
100
|
-
- test/tc_rgb.rb
|
101
|
+
- test/tc_lazy.rb
|
101
102
|
- test/tc_multiarray.rb
|
102
103
|
- test/tc_bool.rb
|
103
|
-
- test/
|
104
|
-
- test/
|
105
|
-
- test/tc_lazy.rb
|
104
|
+
- test/tc_rgb.rb
|
105
|
+
- test/tc_sequence.rb
|
106
106
|
has_rdoc: yard
|
107
107
|
homepage: http://wedesoft.github.com/multiarray/
|
108
108
|
licenses: []
|
@@ -136,11 +136,11 @@ signing_key:
|
|
136
136
|
specification_version: 3
|
137
137
|
summary: Multi-dimensional and uniform Ruby arrays
|
138
138
|
test_files:
|
139
|
+
- test/tc_int.rb
|
140
|
+
- test/tc_object.rb
|
139
141
|
- test/tc_float.rb
|
140
|
-
- test/
|
141
|
-
- test/tc_rgb.rb
|
142
|
+
- test/tc_lazy.rb
|
142
143
|
- test/tc_multiarray.rb
|
143
144
|
- test/tc_bool.rb
|
144
|
-
- test/
|
145
|
-
- test/
|
146
|
-
- test/tc_lazy.rb
|
145
|
+
- test/tc_rgb.rb
|
146
|
+
- test/tc_sequence.rb
|