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 +/