multiarray 0.18.1 → 0.19.0
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.
- 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
|