1. David Lin
  2. WebCL-ImageFx

Commits

David Lin  committed 1364b57

fx: invert + grayscale

  • Participants
  • Parent commits e783cba
  • Branches master

Comments (0)

Files changed (8)

File www/index.html

View file
   <script data-main="js/app" src="js/lib/require.js"></script>
 </head>
 <body>
+  <div>
+    <form>
+      <label>Effect: </label>
+      <select id="effect"></select>
+    </form>
+  </div>
+  <div id="parameters-area">
+  </div>
+  <div>
+    <button id="execute">Execute</button>
+  </div>
+  <div>
+    <img id="source" src="img/lena.png"></img>
+  </div>
+  <div>
+    <canvas id="output"></canvas>
+  </div>
 </body>
 </html>

File www/js/app.js

View file
     'zepto': {
       deps: [],
       exports: 'Zepto'
-    },
-    'maria': {
-      deps: [],
-      exports: 'maria'
     }
   }
 });

File www/js/app/fx/grayscale.cl

View file
+const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE |
+                          CLK_ADDRESS_CLAMP_TO_EDGE |
+                          CLK_FILTER_NEAREST;
+
+__kernel void main(__read_only image2d_t src,
+                   __write_only image2d_t dst,
+                   uint width, uint height)
+{
+  uint x = get_global_id(0), y = get_global_id(1);
+  if (x >= width || y >= height)
+    return;
+  float4 color = read_imagef(src, sampler, (int2)(x, y));
+  float lum = dot(color, (float4)(0.299f, 0.587f, 0.114f, 0.0f));
+  float4 result = (float4)(lum, lum, lum, 1.0f);
+  write_imagef(dst, (int2)(x, y), result);
+}

File www/js/app/fx/grayscale.js

View file
+define([
+  'zepto',
+  'text!./grayscale.cl'
+], function($, code){
+  
+  function setupContext()
+  {
+    var platform = WebCL.getPlatformIDs()[0];
+    var props = [WebCL.CL_CONTEXT_PLATFORM, platform];
+    var type = WebCL.CL_DEVICE_TYPE_GPU;
+    return WebCL.createContextFromType(props, type);
+  }
+  
+  function sourceImageElement()
+  {
+    return $("img#source")[0];
+  }
+  
+  function sourceImageData()
+  {
+    var cav = document.createElement('canvas');
+    var img = sourceImageElement();
+    cav.width = img.width;
+    cav.height = img.height;
+    var ctx = cav.getContext('2d');
+    ctx.drawImage(img, 0, 0);
+    return ctx.getImageData(0, 0, img.width, img.height);
+  }
+  
+  function outputCanvasElement()
+  {
+    return $("canvas#output")[0];
+  }
+  
+  function execute()
+  {
+    var ctx = setupContext();
+    var dev = ctx.getContextInfo(WebCL.CL_CONTEXT_DEVICES)[0];
+    var cmd = ctx.createCommandQueue(dev, 0);
+    _execute(ctx, cmd);
+    ctx.releaseCLResources();
+  }
+  
+  function _execute(ctx, cmd)
+  {
+    var src = sourceImageData();
+    var format = { channelOrder: WebCL.CL_RGBA,
+                   channelDataType: WebCL.CL_UNORM_INT8 }
+    var imgIn = ctx.createImage2D(WebCL.CL_MEM_READ_ONLY, format, src.width, src.height, 0);
+    var imgOut = ctx.createImage2D(WebCL.CL_MEM_WRITE_ONLY, format, src.width, src.height, 0);
+    cmd.enqueueWriteImage(imgIn, false, [0,0,0], [src.width, src.height, 1], 0, 0, src.data, []);
+    var program = ctx.createProgramWithSource(code);
+    program.buildProgram(ctx.getContextInfo(WebCL.CL_CONTEXT_DEVICES), "");
+    var kernel = program.createKernel('main');
+    kernel.setKernelArg(0, imgIn);
+    kernel.setKernelArg(1, imgOut);
+    kernel.setKernelArg(2, src.width, WebCL.types.UINT);
+    kernel.setKernelArg(3, src.height, WebCL.types.UINT);
+    var localSize = 16;
+    var globalWidth = Math.ceil(src.width / localSize) * localSize;
+    var globalHeight = Math.ceil(src.height / localSize) * localSize;
+    cmd.enqueueNDRangeKernel(kernel, 2, [0,0], [globalWidth, globalHeight], [localSize, localSize], []);
+    var canvas = outputCanvasElement();
+    canvas.width = src.width;
+    canvas.height = src.height;
+    var canvasCtx = canvas.getContext('2d');
+    var result = canvasCtx.createImageData(src.width, src.height);
+    cmd.enqueueReadImage(imgOut, false, [0,0,0], [result.width, result.height, 1], 0, 0, result.data, []);
+    cmd.finish();
+    canvasCtx.putImageData(result, 0, 0);
+  }
+  
+  function setup()
+  {
+    $("button#execute").off().on("click", execute);
+  }
+  
+  return setup;
+});

File www/js/app/fx/invert.cl

View file
+const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE |
+                          CLK_ADDRESS_CLAMP_TO_EDGE |
+                          CLK_FILTER_NEAREST;
+
+__kernel void main(__read_only image2d_t src,
+                   __write_only image2d_t dst,
+                   uint width, uint height)
+{
+  uint x = get_global_id(0), y = get_global_id(1);
+  if (x >= width || y >= height)
+    return;
+  float4 color = read_imagef(src, sampler, (int2)(x, y));
+  float4 result = (float4)((float3)(1.0f) - color.xyz, 1.0f);
+  write_imagef(dst, (int2)(x, y), result);
+}

File www/js/app/fx/invert.js

View file
+define([
+  'zepto',
+  'text!./invert.cl'
+], function($, code){
+  
+  function setupContext()
+  {
+    var platform = WebCL.getPlatformIDs()[0];
+    var props = [WebCL.CL_CONTEXT_PLATFORM, platform];
+    var type = WebCL.CL_DEVICE_TYPE_GPU;
+    return WebCL.createContextFromType(props, type);
+  }
+  
+  function sourceImageElement()
+  {
+    return $("img#source")[0];
+  }
+  
+  function sourceImageData()
+  {
+    var cav = document.createElement('canvas');
+    var img = sourceImageElement();
+    cav.width = img.width;
+    cav.height = img.height;
+    var ctx = cav.getContext('2d');
+    ctx.drawImage(img, 0, 0);
+    return ctx.getImageData(0, 0, img.width, img.height);
+  }
+  
+  function outputCanvasElement()
+  {
+    return $("canvas#output")[0];
+  }
+  
+  function execute()
+  {
+    var ctx = setupContext();
+    var dev = ctx.getContextInfo(WebCL.CL_CONTEXT_DEVICES)[0];
+    var cmd = ctx.createCommandQueue(dev, 0);
+    _execute(ctx, cmd);
+    ctx.releaseCLResources();
+  }
+  
+  function _execute(ctx, cmd)
+  {
+    var src = sourceImageData();
+    var format = { channelOrder: WebCL.CL_RGBA,
+                   channelDataType: WebCL.CL_UNORM_INT8 }
+    var imgIn = ctx.createImage2D(WebCL.CL_MEM_READ_ONLY, format, src.width, src.height, 0);
+    var imgOut = ctx.createImage2D(WebCL.CL_MEM_WRITE_ONLY, format, src.width, src.height, 0);
+    cmd.enqueueWriteImage(imgIn, false, [0,0,0], [src.width, src.height, 1], 0, 0, src.data, []);
+    var program = ctx.createProgramWithSource(code);
+    program.buildProgram(ctx.getContextInfo(WebCL.CL_CONTEXT_DEVICES), "");
+    var kernel = program.createKernel('main');
+    kernel.setKernelArg(0, imgIn);
+    kernel.setKernelArg(1, imgOut);
+    kernel.setKernelArg(2, src.width, WebCL.types.UINT);
+    kernel.setKernelArg(3, src.height, WebCL.types.UINT);
+    var localSize = 16;
+    var globalWidth = Math.ceil(src.width / localSize) * localSize;
+    var globalHeight = Math.ceil(src.height / localSize) * localSize;
+    cmd.enqueueNDRangeKernel(kernel, 2, [0,0], [globalWidth, globalHeight], [localSize, localSize], []);
+    var canvas = outputCanvasElement();
+    canvas.width = src.width;
+    canvas.height = src.height;
+    var canvasCtx = canvas.getContext('2d');
+    var result = canvasCtx.createImageData(src.width, src.height);
+    cmd.enqueueReadImage(imgOut, false, [0,0,0], [result.width, result.height, 1], 0, 0, result.data, []);
+    cmd.finish();
+    canvasCtx.putImageData(result, 0, 0);
+  }
+  
+  function setup()
+  {
+    $("button#execute").off().on("click", execute);
+  }
+  
+  return setup;
+});

File www/js/app/main.js

View file
 define(function (require) {
   var zepto = require('zepto');
   zepto(function($){
-    // Load Template
-    var html = require('text!./templates/invert.html');
-    $(document.body).html(html);
+    // Setup FX Selection
+    $("select#effect").on("change", function(e){
+      var value = e.target.value;
+      require(["./fx/"+value], function(fx){ fx(); });
+    }).append((function(){
+      var options = ['invert', 'grayscale'];
+      for (var i in options) {
+        var node = document.createElement('option');
+        node.value = options[i];
+        node.text = options[i];
+        options[i] = node;
+      }
+      return options;
+    })()).trigger('change');
     // Setup Drag-and-Drop
     $(document).on("dragenter", function(e){
       e.stopPropagation();
       if (files.length != 1) { return; }
       var file = files[0];
       if (!file.type.match(/image.*/)) { return; }
-      var images = $("#source-image");
+      var images = $("img#source");
       images.attr('file', file);
       var reader = new FileReader();
       reader.onload = function(e){ images.attr('src', e.target.result); }

File www/js/app/templates/invert.html

View file
 <body>
   <p>Hello World</p>
   <div>
+    <button id="execute">Run</button>
   </div>
-  <div id="source-area">
-    <img id="source-image" src="img/lena.png"></img>
+  <div>
+    <img id="source" src="img/lena.png"></img>
   </div>
-  <div id="output-area">
-    <canvas id="output-canvas">
+  <div>
+    <canvas id="output">
     </canvas>
   </div>
 </body>