如何在FabricJS中编写卷积过滤器以进行边缘检测 [英] How to write a convolution filter for Edge detection in FabricJS

查看:78
本文介绍了如何在FabricJS中编写卷积过滤器以进行边缘检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Fabricjs中编写卷积过滤器以进行边缘检测,但是矩阵不起作用.

这是矩阵(从

 //加载图像var image = new Image();image.crossOrigin ='anonymous';image.onload =开始;image.src ="https://dl.dropboxusercontent.com/u/139992952/multple/sun.png";函数start(){//应用Sobel边缘检测//返回过滤后的画布的ImageDatavar grayscale = Filters.filterImage(Filters.grayscale,image);var vertical = Filters.convoluteFloat32(灰度,[-1,0,1,-2,0,2,-1,0,1]);var horizo​​ntal = Filters.convoluteFloat32(灰度,[-1,-2,-1,0、0、0,1,2,1]);var final_image = Filters.createImageData(vertical.width,vertical.height);对于(var i = 0; i< final_image.data.length; i + = 4){//将垂直渐变设为红色var v = Math.abs(vertical.data [i]);final_image.data [i] = v;//使水平渐变变为绿色var h = Math.abs(horizo​​ntal.data [i]);final_image.data [i + 1] = h;//并混合一些蓝色以达到美观final_image.data [i + 2] =(v + h)/4;final_image.data [i + 3] = 255;//不透明的Alpha}//将过滤后的imageData放在内存画布上var memCanvas = document.createElement('canvas');memCanvas.width = image.width;memCanvas.height = image.height;memCanvas.getContext('2d').putImageData(final_image,0,0);//将内存画布用作Fabric.Image的图像源var canvas = new fabric.Canvas('canvas');var imgElement = document.getElementById('my-image');var imgInstance = new fabric.Image(memCanvas,{left:10,top:10});canvas.add(imgInstance);}  

  body {background-color:ivory;}canvas {border:1px纯红色;margin:0自动;}  

 <脚本src ="https://dl.dropboxusercontent.com/u/139992952/multple/filters.js"><;/script>< script src ="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>< h4>原始图像</h4>< img src ='https://dl.dropboxusercontent.com/u/139992952/multple/sun.png'>< h4>应用了Sobel滤镜的FabricJS图像</h4>< canvas id ="canvas" width = 300 height = 200></canvas>  

这是演示中使用的 Filters.js 脚本:

 //出处:http://www.html5rocks.com/en/tutorials/canvas/imagefilters/过滤器= {};Filters.getPixels = function(img){var c,ctx;如果(img.getContext){c = img;尝试{ctx = c.getContext('2d');} catch(e){}}如果(!ctx){c = this.getCanvas(img.width,img.height);ctx = c.getContext('2d');ctx.drawImage(img,0,0);}返回ctx.getImageData(0,0,c.width,c.height);};Filters.getCanvas = function(w,h){var c = document.createElement('canvas');c.width = w;c.height = h;返回c;};Filters.filterImage = function(filter,image,var_args){var args = [this.getPixels(image)];for(var i = 2; i< arguments.length; i ++){args.push(arguments [i]);}返回filter.apply(null,args);};Filters.grayscale = function(pixels,args){var d = pixel.data;对于(var i = 0; i  =阈值)255:0;d [i] = d [i + 1] = d [i + 2] = v}返回像素;};Filters.tmpCanvas = document.createElement('canvas');Filters.tmpCtx = Filters.tmpCanvas.getContext('2d');Filters.createImageData = function(w,h){返回this.tmpCtx.createImageData(w,h);};Filters.convolute =函数(像素,权重,不透明){var side = Math.round(Math.sqrt(weights.length));var halfSide = Math.floor(side/2);var src = pixel.data;var sw = pixel.width;var sh = pixel.height;var w = sw;var h = sh;var输出= Filters.createImageData(w,h);var dst = output.data;var alphaFac =不透明?1:0;对于(var y = 0; y< h; y ++){对于(var x = 0; x< w; x ++){var sy = y;var sx = x;var dstOff =(y * w + x)* 4;var r = 0,g = 0,b = 0,a = 0;for(var cy = 0; cy< side; cy ++){for(var cx = 0; cx< side; cx ++){var scy = Math.min(sh-1,Math.max(0,sy + cy-halfSide));var scx = Math.min(sw-1,Math.max(0,sx + cx-halfSide));var srcOff =(scy * sw + scx)* 4;var wt = weights [cy * side + cx];r + = src [srcOff] * wt;g + = src [srcOff + 1] * wt;b + = src [srcOff + 2] * wt;a + = src [srcOff + 3] * wt;}}dst [dstOff] = r;dst [dstOff + 1] = g;dst [dstOff + 2] = b;dst [dstOff + 3] = a + alphaFac *(255-a);}}返回输出;};如果(!window.Float32Array)Float32Array =数组;Filters.convoluteFloat32 =函数(像素,权重,不透明){var side = Math.round(Math.sqrt(weights.length));var halfSide = Math.floor(side/2);var src = pixel.data;var sw = pixel.width;var sh = pixel.height;var w = sw;var h = sh;var输出= {宽度:w,高度:h,数据:新的Float32Array(w * h * 4)};var dst = output.data;var alphaFac =不透明?1:0;对于(var y = 0; y< h; y ++){对于(var x = 0; x< w; x ++){var sy = y;var sx = x;var dstOff =(y * w + x)* 4;var r = 0,g = 0,b = 0,a = 0;for(var cy = 0; cy< side; cy ++){for(var cx = 0; cx< side; cx ++){var scy = Math.min(sh-1,Math.max(0,sy + cy-halfSide));var scx = Math.min(sw-1,Math.max(0,sx + cx-halfSide));var srcOff =(scy * sw + scx)* 4;var wt = weights [cy * side + cx];r + = src [srcOff] * wt;g + = src [srcOff + 1] * wt;b + = src [srcOff + 2] * wt;a + = src [srcOff + 3] * wt;}}dst [dstOff] = r;dst [dstOff + 1] = g;dst [dstOff + 2] = b;dst [dstOff + 3] = a + alphaFac *(255-a);}}返回输出;};//函数runFilter(id,filter,arg1,arg2,arg3){var c = document.getElementById(id);var s = c.previousSibling.style;var b = c.parentNode.getElementsByTagName('button')[0];如果(b.originalText == null){b.originalText = b.textContent;}如果(s.display =='none'){s.display ='inline';c.style.display ='none';b.textContent = b.originalText;} 别的 {var idata = Filters.filterImage(filter,img,arg1,arg2,arg3);c.width = idata.width;c.height = idata.height;var ctx = c.getContext('2d');ctx.putImageData(idata,0,0);s.display ='none';c.style.display ='inline';b.textContent ='恢复原始图像';}}//sobel = function(){runFilter('sobel',function(px){px = Filters.grayscale(px);var vertical = Filters.convoluteFloat32(px,[-1,-2,-1,0、0、0,1,2,1]);var horizo​​ntal = Filters.convoluteFloat32(px,[-1,0,1,-2,0,2,-1,0,1]);var id = Filters.createImageData(vertical.width,vertical.height);对于(var i = 0; i< id.data.length; i + = 4){var v = Math.abs(vertical.data [i]);id.data [i] = v;var h = Math.abs(horizo​​ntal.data [i]);id.data [i + 1] = hid.data [i + 2] =(v + h)/4;id.data [i + 3] = 255;}返回ID;});} 

I want to write a convolution filter for edge detection in Fabricjs , but the matrix doesn't work.

Here's the Matrix (Idea taken from http://homepages.inf.ed.ac.uk/rbf/HIPR2/sobel.htm): new fabric.Image.filters.Convolute({ // edge detect matrix: [[ -1, 0, 1, -2, 0, 2, -1, 0, 1 ], [1, 2, 1, 0 ,0 ,0, -1, -2, 1 ]] })

heres the Fiddle

NOTE:- You need to click on the image to get the check boxes for image processing.

解决方案

Since a native html5 canvas element can be an image for Fabric.Image, you can find an Edge detection solution for native canvas and then use that native canvas on a Fabric.Image like this image:myNativeCanvas.

[Addition: added a demo]

Here's example code and a demo showing how to:

  • Use a native canvas to apply Sobel Edge Detection to an image and
  • Use that native canvas as the image source for a Fabric.Image

// load an image 
var image=new Image();
image.crossOrigin='anonymous';
image.onload=start;
image.src="https://dl.dropboxusercontent.com/u/139992952/multple/sun.png";
function start(){

  // apply Sobel Edge Detection
  // return ImageData of the filtered canvas
  var grayscale = Filters.filterImage(Filters.grayscale, image);
  var vertical = Filters.convoluteFloat32(grayscale,
                                          [ -1, 0, 1,
                                           -2, 0, 2,
                                           -1, 0, 1 ]);
  var horizontal = Filters.convoluteFloat32(grayscale,
                                            [ -1, -2, -1,
                                             0,  0,  0,
                                             1,  2,  1 ]);
  var final_image = Filters.createImageData(vertical.width, vertical.height);
  for (var i=0; i<final_image.data.length; i+=4){
    // make the vertical gradient red
    var v = Math.abs(vertical.data[i]);
    final_image.data[i] = v;
    // make the horizontal gradient green
    var h = Math.abs(horizontal.data[i]);
    final_image.data[i+1] = h;
    // and mix in some blue for aesthetics
    final_image.data[i+2] = (v+h)/4;
    final_image.data[i+3] = 255; // opaque alpha
  }

  // put the filtered imageData on an in-memory canvas
  var memCanvas = document.createElement('canvas');
  memCanvas.width=image.width;
  memCanvas.height=image.height;
  memCanvas.getContext('2d').putImageData(final_image,0,0);

  // use the in-memory canvas as an image source for a Fabric.Image
  var canvas = new fabric.Canvas('canvas');
  var imgElement = document.getElementById('my-image');
  var imgInstance = new fabric.Image(memCanvas,{left:10,top:10});
  canvas.add(imgInstance);
}

body{ background-color: ivory; }
canvas{border:1px solid red; margin:0 auto; }

<script src="https://dl.dropboxusercontent.com/u/139992952/multple/filters.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<h4>Original Image</h4>
<img src='https://dl.dropboxusercontent.com/u/139992952/multple/sun.png'>
<h4>FabricJS image with Sobel filter applied</h4>
<canvas id="canvas" width=300 height=200></canvas>

And here is the Filters.js script used in the demo:

// Attribution: http://www.html5rocks.com/en/tutorials/canvas/imagefilters/
Filters = {};
Filters.getPixels = function(img) {
  var c,ctx;
  if (img.getContext) {
    c = img;
    try { ctx = c.getContext('2d'); } catch(e) {}
  }
  if (!ctx) {
    c = this.getCanvas(img.width, img.height);
    ctx = c.getContext('2d');
    ctx.drawImage(img, 0, 0);
  }
  return ctx.getImageData(0,0,c.width,c.height);
};

Filters.getCanvas = function(w,h) {
  var c = document.createElement('canvas');
  c.width = w;
  c.height = h;
  return c;
};

Filters.filterImage = function(filter, image, var_args) {
  var args = [this.getPixels(image)];
  for (var i=2; i<arguments.length; i++) {
    args.push(arguments[i]);
  }
  return filter.apply(null, args);
};

Filters.grayscale = function(pixels, args) {
  var d = pixels.data;
  for (var i=0; i<d.length; i+=4) {
    var r = d[i];
    var g = d[i+1];
    var b = d[i+2];
    // CIE luminance for the RGB
    var v = 0.2126*r + 0.7152*g + 0.0722*b;
    d[i] = d[i+1] = d[i+2] = v
  }
  return pixels;
};

Filters.brightness = function(pixels, adjustment) {
  var d = pixels.data;
  for (var i=0; i<d.length; i+=4) {
    d[i] += adjustment;
    d[i+1] += adjustment;
    d[i+2] += adjustment;
  }
  return pixels;
};

Filters.threshold = function(pixels, threshold) {
  var d = pixels.data;
  for (var i=0; i<d.length; i+=4) {
    var r = d[i];
    var g = d[i+1];
    var b = d[i+2];
    var v = (0.2126*r + 0.7152*g + 0.0722*b >= threshold) ? 255 : 0;
    d[i] = d[i+1] = d[i+2] = v
  }
  return pixels;
};

Filters.tmpCanvas = document.createElement('canvas');
Filters.tmpCtx = Filters.tmpCanvas.getContext('2d');

Filters.createImageData = function(w,h) {
  return this.tmpCtx.createImageData(w,h);
};

Filters.convolute = function(pixels, weights, opaque) {
  var side = Math.round(Math.sqrt(weights.length));
  var halfSide = Math.floor(side/2);

  var src = pixels.data;
  var sw = pixels.width;
  var sh = pixels.height;

  var w = sw;
  var h = sh;
  var output = Filters.createImageData(w, h);
  var dst = output.data;

  var alphaFac = opaque ? 1 : 0;

  for (var y=0; y<h; y++) {
    for (var x=0; x<w; x++) {
      var sy = y;
      var sx = x;
      var dstOff = (y*w+x)*4;
      var r=0, g=0, b=0, a=0;
      for (var cy=0; cy<side; cy++) {
        for (var cx=0; cx<side; cx++) {
          var scy = Math.min(sh-1, Math.max(0, sy + cy - halfSide));
          var scx = Math.min(sw-1, Math.max(0, sx + cx - halfSide));
          var srcOff = (scy*sw+scx)*4;
          var wt = weights[cy*side+cx];
          r += src[srcOff] * wt;
          g += src[srcOff+1] * wt;
          b += src[srcOff+2] * wt;
          a += src[srcOff+3] * wt;
        }
      }
      dst[dstOff] = r;
      dst[dstOff+1] = g;
      dst[dstOff+2] = b;
      dst[dstOff+3] = a + alphaFac*(255-a);
    }
  }
  return output;
};

if (!window.Float32Array)
  Float32Array = Array;

Filters.convoluteFloat32 = function(pixels, weights, opaque) {
  var side = Math.round(Math.sqrt(weights.length));
  var halfSide = Math.floor(side/2);

  var src = pixels.data;
  var sw = pixels.width;
  var sh = pixels.height;

  var w = sw;
  var h = sh;
  var output = {
    width: w, height: h, data: new Float32Array(w*h*4)
  };
  var dst = output.data;

  var alphaFac = opaque ? 1 : 0;

  for (var y=0; y<h; y++) {
    for (var x=0; x<w; x++) {
      var sy = y;
      var sx = x;
      var dstOff = (y*w+x)*4;
      var r=0, g=0, b=0, a=0;
      for (var cy=0; cy<side; cy++) {
        for (var cx=0; cx<side; cx++) {
          var scy = Math.min(sh-1, Math.max(0, sy + cy - halfSide));
          var scx = Math.min(sw-1, Math.max(0, sx + cx - halfSide));
          var srcOff = (scy*sw+scx)*4;
          var wt = weights[cy*side+cx];
          r += src[srcOff] * wt;
          g += src[srcOff+1] * wt;
          b += src[srcOff+2] * wt;
          a += src[srcOff+3] * wt;
        }
      }
      dst[dstOff] = r;
      dst[dstOff+1] = g;
      dst[dstOff+2] = b;
      dst[dstOff+3] = a + alphaFac*(255-a);
    }
  }
  return output;
};
//
function runFilter(id, filter, arg1, arg2, arg3) {
  var c = document.getElementById(id);
  var s = c.previousSibling.style;
  var b = c.parentNode.getElementsByTagName('button')[0];
  if (b.originalText == null) {
    b.originalText = b.textContent;
  }
  if (s.display == 'none') {
    s.display = 'inline';
    c.style.display = 'none';
    b.textContent = b.originalText;
  } else {
    var idata = Filters.filterImage(filter, img, arg1, arg2, arg3);
    c.width = idata.width;
    c.height = idata.height;
    var ctx = c.getContext('2d');
    ctx.putImageData(idata, 0, 0);
    s.display = 'none';
    c.style.display = 'inline';
    b.textContent = 'Restore original image';
  }
}
//
sobel = function() {
  runFilter('sobel', function(px){
    px = Filters.grayscale(px);
    var vertical = Filters.convoluteFloat32(px,
      [-1,-2,-1,
        0, 0, 0,
        1, 2, 1]);
    var horizontal = Filters.convoluteFloat32(px,
      [-1,0,1,
       -2,0,2,
       -1,0,1]);
    var id = Filters.createImageData(vertical.width, vertical.height);
    for (var i=0; i<id.data.length; i+=4) {
      var v = Math.abs(vertical.data[i]);
      id.data[i] = v;
      var h = Math.abs(horizontal.data[i]);
      id.data[i+1] = h
      id.data[i+2] = (v+h)/4;
      id.data[i+3] = 255;
    }
    return id;
  });
}

这篇关于如何在FabricJS中编写卷积过滤器以进行边缘检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆