1 module oclcv.median; 2 3 import oclcv.clcore; 4 5 import dplug.core.nogc; 6 import bc.string; 7 8 final class Median2D { 9 public: 10 @nogc nothrow: 11 this(int height, int width, int kernelSize, CLContext ctx){ 12 13 width_ = width; height_= height; kernelSize_ = kernelSize; 14 15 initialize(ctx); 16 } 17 18 ~this(){ 19 destroyFree(prog_); 20 } 21 22 private bool initialize(CLContext ctx){ 23 if(!ctx) 24 return false; 25 context_ = ctx; 26 27 auto compilerParam = RCStringZ.from(nogcFormat!"-D T=\"uchar\" -D T1=\"uchar\" -D cn=1 -D WINDOW_SIZE=%d -D filter_offset=%d" 28 (kernelSize_, kernelSize_ / 2)); 29 // auto compilerParam = RCStringZ.from(nogcFormat!"-D WINDOW_SIZE=%d -D filter_offset=%d"( 30 // kernelSize_, kernelSize_ / 2)); 31 prog_ = mallocNew!CLProgram(CTKernel.KMEDIAN, context_, compilerParam[]); 32 33 34 if(kernelSize_ == 3){ 35 _kernel = prog_.getKernel("medianFilter3"); 36 }else if (kernelSize_ == 5){ 37 _kernel = prog_.getKernel("medianFilter5"); 38 }else if (kernelSize_ == 7){ 39 _kernel = prog_.getKernel("medianFilter7"); 40 } else if (kernelSize_ > 7){ // slow. todo: find better kernels 41 _kernel = prog_.getKernel("MedianFilter2D"); 42 } 43 44 return true; 45 } 46 47 CLBuffer run(CLBuffer d_src_mono){ 48 49 debug _assert(d_src_mono.metaData.dataType == UBYTE, "Input type must be ubyte"); 50 debug _assert(d_src_mono.metaData.numberOfChannels == 1, "Input's channel count must be 1"); 51 52 CLBuffer d_output = mallocNew!CLBuffer(context_, BufferMeta(UBYTE, height_, width_, 1)); 53 54 if(kernelSize_ == 3 || kernelSize_ == 5 || kernelSize_ == 7){ 55 int src_step = cast(int)(width_ * ubyte.sizeof); 56 int dst_step = cast(int)(width_ * ubyte.sizeof); 57 int src_offset = 0; 58 int dst_offset = 0; 59 int dst_rows = height_; 60 int dst_cols = width_; 61 _kernel.setArgs(d_src_mono, src_step, src_offset, d_output, dst_step, dst_offset, dst_rows, dst_cols); 62 }else { 63 _kernel.setArgs(d_src_mono, d_output, width_, height_); 64 } 65 66 _kernel.launch(0, GridDim((width_ + 16 - 1)/16, (height_ + 16 - 1)/16), BlockDim(16,16)); 67 context_.finish(0); 68 69 return d_output; 70 } 71 72 private: 73 int width_, height_; 74 int kernelSize_; 75 CLContext context_; 76 CLProgram prog_; 77 int TILE_SIZE; 78 CLKernel _kernel; 79 } 80 81 final class Median3D { 82 public: 83 @nogc nothrow: 84 this(int height, int width, int kernelSize, CLContext ctx){ 85 86 width_ = width; height_= height; kernelSize_ = kernelSize; 87 88 initialize(ctx); 89 } 90 91 ~this(){ 92 destroyFree(prog_); 93 } 94 95 private bool initialize(CLContext ctx){ 96 if(!ctx) 97 return false; 98 context_ = ctx; 99 100 auto compilerParam = RCStringZ.from(nogcFormat!"-D T=\"uchar3\" -D T1=\"uchar\" -D cn=3 -D KERNEL_SIZE=%d -D WINDOW_SIZE=%d -D filter_offset=%d"( 101 kernelSize_, kernelSize_, kernelSize_ / 2 102 )); 103 prog_ = mallocNew!CLProgram(CTKernel.KMEDIAN, context_, compilerParam[]); 104 105 if(kernelSize_ == 3){ 106 _kernel = prog_.getKernel("medianFilter3"); 107 }else if (kernelSize_ == 5){ 108 _kernel = prog_.getKernel("medianFilter5"); 109 }else if (kernelSize_ == 7){ // has kind of jagged edges, will fix 110 _kernel = prog_.getKernel("medianFilter7"); 111 } else if (kernelSize_ > 7){ // slow. todo: find better kernels 112 _kernel = prog_.getKernel("MedianFilter3D"); 113 } 114 115 return true; 116 } 117 118 CLBuffer run(CLBuffer d_src3d){ 119 120 debug _assert(d_src3d.metaData.dataType == UBYTE, "Input type must be ubyte"); 121 debug _assert(d_src3d.metaData.numberOfChannels == 3, "Input's channel count must be 3"); 122 123 CLBuffer d_output = mallocNew!CLBuffer(context_, BufferMeta(UBYTE, height_, width_, 3)); 124 125 if(kernelSize_ == 3 || kernelSize_ == 5 || kernelSize_ == 7){ 126 int src_step = cast(int)(width_ * 3 * ubyte.sizeof); 127 int dst_step = cast(int)(width_ * 3 * ubyte.sizeof); 128 int src_offset = 0; 129 int dst_offset = 0; 130 int dst_rows = height_; 131 int dst_cols = width_; 132 _kernel.setArgs(d_src3d, src_step, src_offset, d_output, dst_step, dst_offset, dst_rows, dst_cols); 133 }else { 134 _kernel.setArgs(d_src3d, d_output, width_, height_); 135 } 136 137 int tileSize = 16; 138 _kernel.launch(0, GridDim((width_ + tileSize - 1)/tileSize, (height_ + tileSize - 1)/tileSize), BlockDim(tileSize, tileSize)); 139 context_.finish(0); 140 141 return d_output; 142 } 143 144 private: 145 int width_, height_; 146 int kernelSize_; 147 CLContext context_; 148 CLProgram prog_; 149 int TILE_SIZE; 150 CLKernel _kernel; 151 } 152 /+ 153 final class Median3D { 154 public: 155 @nogc nothrow: 156 this(int height, int width, int kernelSize, CLContext ctx){ 157 158 width_ = width; height_= height; kernelSize_ = kernelSize; 159 160 initialize(ctx); 161 } 162 163 ~this(){ 164 destroyFree(prog_); 165 } 166 167 private bool initialize(CLContext ctx){ 168 if(!ctx) 169 return false; 170 context_ = ctx; 171 172 auto compilerParam = RCStringZ.from(nogcFormat!"-D KERNEL_SIZE=%d -D filter_offset=%d"( 173 kernelSize_, kernelSize_ / 2)); 174 prog_ = mallocNew!CLProgram(CTKernel.KMEDIAN, context_, compilerParam[]); 175 176 _kernel = prog_.getKernel("MedianFilter3D"); 177 178 return true; 179 } 180 181 CLBuffer run(CLBuffer d_src3d){ 182 183 debug _assert(d_src3d.metaData.dataType == UBYTE, "Input type must be ubyte"); 184 debug _assert(d_src3d.metaData.numberOfChannels == 3, "Input's channel count must be 3"); 185 186 CLBuffer d_output = mallocNew!CLBuffer(context_, BufferMeta(UBYTE, height_, width_, 3)); 187 188 _kernel.setArgs(d_src3d, d_output, width_, height_); 189 190 int tileSize = 16; 191 _kernel.launch(0, GridDim((width_ + tileSize - 1)/tileSize, (height_ + tileSize - 1)/tileSize), BlockDim(tileSize,tileSize)); 192 context_.finish(0); 193 194 return d_output; 195 } 196 197 private: 198 int width_, height_; 199 int kernelSize_; 200 CLContext context_; 201 CLProgram prog_; 202 int TILE_SIZE; 203 CLKernel _kernel; 204 } 205 +/