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 }