1 module oclcv.color;
2 
3 import oclcv.clcore;
4 
5 import dplug.core.nogc;
6 
7 alias CCONV = int;
8 enum : CCONV {
9     HSV2RGB,
10     RGB2HSV,
11     YUV2RGB,
12     RGB2YUV
13 }
14 
15 final class RGB2GRAY {
16 public:
17     @nogc nothrow:
18 
19     this(int height, int width, CLContext ctx){
20         width_ = width; height_= height;
21         initialize(ctx);
22     }
23 
24     ~this(){
25         destroyFree(prog_);
26     }
27 
28     bool initialize(CLContext ctx){
29         if(!ctx)
30             return false;
31         context_ = ctx;
32         
33         prog_ = mallocNew!CLProgram(CTKernel.KGRAY, context_);
34         rgb2gray_kernel = prog_.getKernel("rgb2gray");
35         
36         return true;
37     }
38 
39     CLBuffer run(CLBuffer d_src_rgb){
40         debug _assert(d_src_rgb.metaData.dataType == UBYTE, "Input type must be ubyte"); 
41         debug _assert(d_src_rgb.metaData.numberOfChannels == 3, "Input's channel count must be 3");
42 
43         CLBuffer d_gray = mallocNew!CLBuffer(context_, BufferMeta(UBYTE, height_, width_, 1));
44         
45         struct _int2 {int x, y;}
46         auto sz = _int2(width_, height_);
47         rgb2gray_kernel.setArgs(d_src_rgb, d_gray, sz);
48         
49         convert();
50 
51         return d_gray;
52     }
53 
54     void convert(){
55         rgb2gray_kernel.launch(0, GridDim((width_ + 16 - 1)/16, (height_ + 16 - 1)/16),
56                                                                     BlockDim(16,16));
57         context_.finish(0);
58     }
59 
60 private:
61     int width_, height_;
62     CLContext context_;
63     CLProgram prog_;
64 
65     CLKernel rgb2gray_kernel;
66 }
67 
68 final class YUVConv {
69 public:
70 @nogc nothrow:
71     this(int height, int width, CCONV conversion, CLContext ctx){
72         width_ = width; height_= height; _conversion = conversion;
73         initialize(ctx);
74     }
75 
76     ~this(){
77         destroyFree(prog_);
78     }
79 
80     bool initialize(CLContext ctx){
81         if(!ctx)
82             return false;
83         context_ = ctx;
84         
85         prog_ = mallocNew!CLProgram(CTKernel.KYUV, context_);
86         
87         if(_conversion == YUV2RGB)
88             conv_kernel = prog_.getKernel("yuv2rgb");
89         else if (_conversion == RGB2YUV)
90             conv_kernel = prog_.getKernel("rgb2yuv");
91         else {
92             debug _assert(0, "unsupported conversion from/to YUV!");
93         }
94         
95         return true;
96     }
97 
98     CLBuffer run(CLBuffer d_src){
99         debug _assert(d_src.metaData.dataType == UBYTE, "Input type must be ubyte"); 
100         debug _assert(d_src.metaData.numberOfChannels == 3, "Input's channel count must be 3");
101 
102         CLBuffer d_dst = mallocNew!CLBuffer(context_, BufferMeta(UBYTE, height_, width_, 3));
103 
104         struct _int2 {int x, y;}
105         auto sz = _int2(width_, height_);
106         conv_kernel.setArgs(d_src, d_dst, sz);
107         
108         convert();
109 
110         return d_dst;
111     }
112 
113     void convert(){
114         conv_kernel.launch(0, GridDim((width_ + 16 - 1)/16, (height_ + 16 - 1)/16),
115                                                                     BlockDim(16,16));
116         context_.finish(0);
117     }
118 
119 private:
120     int width_, height_;
121     CCONV _conversion;
122 
123     CLContext context_;
124     CLProgram prog_;
125 
126     CLKernel conv_kernel;
127 }
128 
129 final class HSVConv {
130 public:
131 @nogc nothrow:
132     this(int height, int width, CCONV conversion, CLContext ctx){
133         width_ = width; height_= height; _conversion = conversion;
134         initialize(ctx);
135     }
136 
137     ~this(){
138         destroyFree(prog_);
139     }
140 
141     bool initialize(CLContext ctx){
142         if(!ctx)
143             return false;
144         context_ = ctx;
145         
146         prog_ = mallocNew!CLProgram(CTKernel.KHSV, context_);
147         
148         if(_conversion == RGB2HSV)
149             conv_kernel = prog_.getKernel("rgb2hsv");
150         else if (_conversion == HSV2RGB)
151             conv_kernel = prog_.getKernel("hsv2rgb");
152         else {
153             debug _assert(0, "unsupported conversion from/to HSV!");
154         }
155         
156         return true;
157     }
158 
159     CLBuffer run(CLBuffer d_src){
160         debug _assert(d_src.metaData.dataType == UBYTE, "Input type must be ubyte"); 
161         debug _assert(d_src.metaData.numberOfChannels == 3, "Input's channel count must be 3");
162 
163         CLBuffer d_dst = mallocNew!CLBuffer(context_, BufferMeta(UBYTE, height_, width_, 3));
164 
165         struct _int2 {int x, y;}
166         auto sz = _int2(width_, height_);
167         conv_kernel.setArgs(d_src, d_dst, sz);
168         
169         convert();
170 
171         return d_dst;
172     }
173 
174     void convert(){
175         conv_kernel.launch(0, GridDim((width_ + 16 - 1)/16, (height_ + 16 - 1)/16),
176                                                                     BlockDim(16,16));
177         context_.finish(0);
178     }
179 
180 private:
181     int width_, height_;
182     CCONV _conversion;
183     CLContext context_;
184     CLProgram prog_;
185 
186     CLKernel conv_kernel;
187 }
188 
189 final class INRANGE3 {
190 public:
191 @nogc nothrow:
192     this(int height, int width, CLContext ctx){
193         width_ = width; height_= height;
194         initialize(ctx);
195     }
196 
197     ~this(){
198         destroyFree(prog_);
199     }
200 
201     bool initialize(CLContext ctx){
202         if(!ctx)
203             return false;
204         context_ = ctx;
205         
206         prog_ = mallocNew!CLProgram(CTKernel.KINRANGE3, context_);
207         inRange_kernel = prog_.getKernel("inRange3");
208 
209         return true;
210     }
211 
212     CLBuffer run(CLBuffer d_src_3c, ubyte lo0, ubyte hi0, ubyte lo1, ubyte hi1, ubyte lo2, ubyte hi2,
213             bool inverse = false){
214         debug _assert(d_src_3c.metaData.dataType == UBYTE, "Input type must be ubyte"); 
215         debug _assert(d_src_3c.metaData.numberOfChannels == 3, "Input's channel count must be 3");
216 
217         CLBuffer d_bool = mallocNew!CLBuffer(context_, BufferMeta(UBYTE, height_, width_, 1));
218 
219         struct _int2 {int x, y;}
220         auto sz = _int2(width_, height_);
221         inRange_kernel.setArgs(d_src_3c, d_bool, sz, lo0, hi0, lo1, hi1, lo2, hi2, (inverse)?1:0);
222         
223         _threshold();
224 
225         return d_bool;
226     }
227 
228     void _threshold(){
229         inRange_kernel.launch(0, GridDim((width_ + 16 - 1)/16, (height_ + 16 - 1)/16),
230                                                                     BlockDim(16,16));
231         context_.finish(0);
232     }
233 
234 private:
235     int width_, height_;
236     CLContext context_;
237     CLProgram prog_;
238 
239     CLKernel inRange_kernel;
240 }