1 /** 2 Image thresholding module. 3 4 Copyright: Copyright Relja Ljubobratovic 2016. 5 6 Authors: Relja Ljubobratovic 7 8 License: $(LINK3 http://www.boost.org/LICENSE_1_0.txt, Boost Software License - Version 1.0). 9 */ 10 module dcv.imgproc.threshold; 11 12 import mir.ndslice; 13 import mir.ndslice.algorithm : each; 14 15 import dcv.core.utils : emptySlice; 16 17 /** 18 Clip slice values by a given threshold value. 19 20 If any slice element has value in range between lower and 21 upper threshold value, its output value is set to upper 22 clipping value, otherwise to 0. If output value type is 23 a floating point, upper clipping value is 1.0, otherwise 24 its the maximal value for that type (e.g. for ubyte its 255, 25 for float and double its 1.0). 26 27 If lower threshold bound is of the same value as higher, then 28 values are clipped from given value to 0. 29 30 Thresholding is supported for 1D, 2D and 3D slices. 31 32 Params: 33 input = Input slice. 34 lowThresh = Lower threshold value. 35 highThresh = Higher threshold value. 36 prealloc = Optional pre-allocated slice buffer for output. 37 38 Note: 39 Input and pre-allocated buffer slice, should be of same structure 40 (i.e. have same strides). If prealloc buffer is not given, and is 41 allocated anew, input slice memory must be contiguous. 42 */ 43 nothrow Slice!(Contiguous, packs, OutputType*) threshold(OutputType, InputType, SliceKind kind, size_t []packs) 44 ( 45 Slice!(kind, packs, InputType*) input, 46 InputType lowThresh, 47 InputType highThresh, 48 Slice!(Contiguous, packs, OutputType*) prealloc = emptySlice!(packs, OutputType) 49 ) 50 in 51 { 52 //TODO: consider leaving upper value, and not setting it to 1. 53 assert(lowThresh <= highThresh); 54 assert(!input.empty); 55 } 56 body 57 { 58 import std.math : approxEqual; 59 import std.traits : isFloatingPoint, isNumeric; 60 61 static assert(isNumeric!OutputType, "Invalid output type - has to be numeric."); 62 63 if (prealloc.shape != input.shape) 64 { 65 prealloc = uninitializedSlice!OutputType(input.shape); 66 } 67 68 assert(input.structure.strides == prealloc.structure.strides, 69 "Input slice structure does not match with resulting buffer."); 70 71 static if (isFloatingPoint!OutputType) 72 OutputType upvalue = 1.0; 73 else 74 OutputType upvalue = OutputType.max; 75 76 auto p = zip!true(prealloc, input); 77 78 if (lowThresh.approxEqual(highThresh)) 79 { 80 p.each!((v) 81 { 82 v.a = cast(OutputType)(v.b <= lowThresh ? 0 : upvalue); 83 }); 84 } 85 else 86 { 87 p.each!((v) 88 { 89 v.a = cast(OutputType)(v.b >= lowThresh && v.b <= highThresh ? upvalue : 0); 90 }); 91 } 92 93 return prealloc; 94 } 95 96 /** 97 Convenience function for thresholding, where lower and upper bound values are the same. 98 99 Calls threshold(slice, thresh, thresh, prealloc) 100 101 Params: 102 input = Input slice. 103 thresh = Threshold value - any value lower than this will be set to 0, and higher to 1. 104 prealloc = Optional pre-allocated slice buffer for output. 105 106 Note: 107 Input and pre-allocated buffer slice, should be of same structure 108 (i.e. have same strides). If prealloc buffer is not given, and is 109 allocated anew, input slice memory must be contiguous. 110 */ 111 nothrow Slice!(Contiguous, packs, OutputType*) threshold(OutputType, InputType, SliceKind kind, size_t []packs) 112 ( 113 Slice!(kind, packs, InputType*) input, 114 InputType thresh, 115 Slice!(Contiguous, packs, OutputType*) prealloc = emptySlice!(packs, OutputType) 116 ) 117 { 118 return threshold!(OutputType, InputType, N)(slice, thresh, thresh, prealloc); 119 } 120