1 /** 2 Module implements various algorithms used often in computer vision. 3 4 $(DL Module contains: 5 $(DD 6 $(LINK2 #norm,norm) 7 $(LINK2 #normalized,normalized) 8 $(LINK2 #scaled,scaled) 9 $(LINK2 #ranged,ranged) 10 ) 11 ) 12 13 Copyright: Copyright Relja Ljubobratovic 2016. 14 15 Authors: Relja Ljubobratovic 16 17 License: $(LINK3 http://www.boost.org/LICENSE_1_0.txt, Boost Software License - Version 1.0). 18 */ 19 20 module dcv.core.algorithm; 21 22 import std.traits : isNumeric, isFloatingPoint; 23 24 import mir.ndslice.slice; 25 import mir.ndslice.algorithm : reduce, each; 26 import mir.math.common; 27 28 /** 29 Scale tensor values. 30 31 Params: 32 tensor = Input tensor. 33 alpha = Multiplier value. 34 beta = Offset value. 35 36 Performs value modification of tensor elements using following formula: 37 ---- 38 ref output = alpha * (input) + beta; 39 ---- 40 41 Returns: 42 Scaled input tensor. 43 44 */ 45 nothrow @nogc auto scaled(Scalar, Tensor)(Tensor tensor, Scalar alpha = 1, Scalar beta = 0) if (isNumeric!Scalar) 46 in 47 { 48 static assert(isSlice!Tensor, "Input tensor has to be of type mir.ndslice.slice.Slice."); 49 } 50 body 51 { 52 tensor.each!((ref v) { v = cast(DeepElementType!Tensor)(alpha * (v) + beta); }); 53 return tensor; 54 } 55 56 nothrow unittest 57 { 58 import std.math : approxEqual; 59 60 auto t = tensor1(); 61 auto ts = t.scaled(10.0f, 2.0f); 62 63 assert(t.iterator == ts.iterator); 64 65 assert(approxEqual(ts[0], 12.0f)); 66 assert(approxEqual(ts[1], 22.0f)); 67 assert(approxEqual(ts[2], 32.0f)); 68 } 69 70 /** 71 In-place tensor scaling to fit given value range. 72 73 Params: 74 tensor = Input tensor. 75 minValue = Minimal value output tensor should contain. 76 maxValue = Maximal value output tensor should contain. 77 78 */ 79 nothrow @nogc auto ranged(Scalar, Tensor)(Tensor tensor, 80 Scalar minValue = 0, Scalar maxValue = 1) if (isNumeric!Scalar) 81 in 82 { 83 static assert(isSlice!Tensor, "Input tensor has to be of type mir.ndslice.slice.Slice."); 84 } 85 body 86 { 87 alias T = DeepElementType!Tensor; 88 89 static if (isFloatingPoint!T) 90 { 91 import mir.math.common : fmin, fmax; 92 auto _max = reduce!fmax(T.min_normal, tensor); 93 auto _min = reduce!fmin(T.max, tensor); 94 } 95 else 96 { 97 import mir.utility : min, max; 98 auto _max = reduce!max(T.min, tensor); 99 auto _min = reduce!min(T.max, tensor); 100 } 101 102 auto rn_val = _max - _min; 103 auto sc_val = maxValue - minValue; 104 105 tensor.each!((ref a) { a = cast(T)(sc_val * ((a - _min) / rn_val) + minValue); }); 106 107 return tensor; 108 } 109 110 unittest 111 { 112 immutable smin = -10.0f; 113 immutable smax = 15.0f; 114 115 auto t1 = tensor1(); 116 auto t2 = tensor2(); 117 auto t3 = tensor3(); 118 119 auto t1r = t1.ranged(smin, smax); 120 auto t2r = t2.ranged(smin, smax); 121 auto t3r = t3.ranged(smin, smax); 122 123 assert(t1.iterator == t1r.iterator); 124 assert(t2.iterator == t2r.iterator); 125 assert(t3.iterator == t3r.iterator); 126 127 } 128 129 nothrow unittest 130 { 131 import std.math : approxEqual; 132 133 import mir.utility; 134 135 immutable smin = -10.0f; 136 immutable smax = 15.0f; 137 138 auto t1 = tensor1(); 139 auto t2 = tensor2(); 140 auto t3 = tensor3(); 141 142 auto t1r = t1.ranged(smin, smax); 143 auto t2r = t2.ranged(smin, smax); 144 auto t3r = t3.ranged(smin, smax); 145 146 assert(approxEqual(reduce!min(float.max, t1r), smin)); 147 assert(approxEqual(reduce!max(float.min_normal, t1r), smax)); 148 149 assert(approxEqual(reduce!min(float.max, t2r), smin)); 150 assert(approxEqual(reduce!max(float.min_normal, t2r), smax)); 151 152 assert(approxEqual(reduce!min(float.max, t3r), smin)); 153 assert(approxEqual(reduce!max(float.min_normal, t3r), smax)); 154 } 155 156 version (unittest) 157 { 158 auto tensor1() 159 { 160 return [1.0f, 2.0f, 3.0f].sliced(3); 161 } 162 163 auto tensor2() 164 { 165 return [1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f].sliced(3, 3); 166 } 167 168 auto tensor3() 169 { 170 return [1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 171 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 172 19.0f, 20.0f, 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f].sliced(3, 3, 3); 173 } 174 }