Canvas pixels to coordinates

筅森魡賤 提交于 2020-01-06 16:49:05

问题


I have a canvas with width = 900, height = 574. I have all the pixels of the canvas. Inside the canvas there are some rectangles, knowing all the pixels of a rectangle what I want is to find the coordinates of the 4 points of a rectangle and then find the width and height of the rectangle.

So what I did is:

  pMinX = (_.min(points)/ 4) % highlightCanvas.width
  pMinY = Math.floor((_.min(points) / 4) / highlightCanvas.width)
  pMaxX = (_.max(points) / 4) % highlightCanvas.width
  pMaxY = Math.floor((_.max(points) / 4) / highlightCanvas.width)

Points is the array of the pixels (4 channels rgba) of the rectangle of which the coordinates I want to find.

pMinY and pMaxY seem to work well while pMinX, pMaX sometimes seem correct while others are wrong. To test, I created a floating div and resize it according to:

  {
    width:  pMaxX - pMinX
    height: pMaxY - pMinY
  }

The height of the div is always correct. But the width there are cases that fails. Any idea why sometimes the calculation fails?


回答1:


Here's annotated code showing how to calculate the bounding box (x, y, width, height) of the salmon colored rectangle in your image.

It works like this:

  • Get the r,g,b,a values for each pixel on the canvas using .getImageData.

  • Set up test(s) that a pixel's rgba must meet to be considered as "inside the desired rectangle" In your example, the salmon rectangle is made up of 2 colors so this test will capture all pixels inside your rectangle:

    // create an array to hold tests that are used to
    // find your desired pixels. The tests should be functions
    // that return true for your desired rgba pixel values
    // (substitue whatever algorithm test that are necessary for your design)
    var tests=[];
    
    
    // add a test into the tests[] array
    tests.push(function(r,g,b,a){
        return(
            (r==251 && g==115 && b==119)||
            (r==249 && g==100 && b==107)
        );
    });
    
  • Determine the minX, minY, maxX & maxY of pixels meeting the tests

  • Calculate the bounding box of the rectangle pixels from the determined minimums and maximums:

    var bounds={
        x:minX,
        y:minY,
        width:maxX-minX,
        height:maxY-minY
    };
    

Important Note: For .getImageData to be allowed, you must satisfy security restrictions. The usual way is to serve the image on the same domain as your webpage. Alternatively, you can set up the server hosting the image to serve that image to any anonymous requestor.

Example code and a Demo:

// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

// load the image
var img=new Image();
// the image must satisfy cross-origin restrictions
// or else we can't use .getImageData
img.crossOrigin='anonymous';
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/findRect.png";
function start(){

  // resize the canvas to the image size 
  // and draw the image onto the canvas
  cw=canvas.width=img.width;
  ch=canvas.height=img.height;
  ctx.drawImage(img,0,0);

  // create an array to hold tests that are used to
  // find your desired pixels. The tests should be functions
  // that return true for your desired rgba pixel values
  // (substitue whatever algorithm test that are necessary for
  //    your design)
  var tests=[];

  // sample test returns true if matching the 2 colors making up the rect
  tests.push(function(r,g,b,a){
    return(
      (r==251 && g==115 && b==119)||
      (r==249 && g==100 && b==107)
    );
  });

  // find the bounds of all pixels meeting the prescribed test(s)
  var bounds=findImageBounds(tests);   

  // testing...draw just the discovered rect to a second canvas
  var c=document.createElement('canvas');
  var cctx=c.getContext('2d');
  document.body.appendChild(c);
  c.width=cw;
  c.height=ch;
  cctx.drawImage(canvas,
                 bounds.x,bounds.y,bounds.w,bounds.h,
                 bounds.x,bounds.y,bounds.w,bounds.h
                );

}

function findImageBounds(tests){

  // get the rgba color values for all pixels on the canvas
  var d=ctx.getImageData(0,0,cw,ch).data;

  // iterate over each pixel
  // find the min/max X,Y of pixels where all tests are true
  var minX=1000000;
  var minY=1000000;
  var maxX=-1000000;
  var maxY=-1000000;
  var hits=0;
  for(var y=0;y<ch;y++){
    for(var x=0;x<cw;x++){
      // n==the position in the rgba array for canvas position x,y
      n=(y*cw+x)*4;
      // the rgba values at this pixel
      r=d[n];
      g=d[n+1];
      b=d[n+2];
      a=d[n+3];
      // run all tests on this pixel
      var testsTrue=true;
      for(var i=0;i<tests.length;i++){
        testsTrue=testsTrue && tests[i](r,g,b,a);
      }
      // if this pixel meets all tests
      // see if it influences our boundary 
      if(testsTrue){
        hits++;
        if(x<minX){minX=x;}
        if(y<minY){minY=y;}
        if(x>minX){maxX=x;}
        if(y>maxY){maxY=y;}
      }
    }}
  // return the x,y,width,height of the bounding box
  // of pixels meeting all the supplied tests
  return({x:minX,y:minY,w:maxX-minX,h:maxY-minY,pixelCount:hits});
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<h4>The original canvas</h4>
<canvas id="canvas" width=300 height=300></canvas>
<h4>Just the rect from the canvas</h4>


来源:https://stackoverflow.com/questions/29792199/canvas-pixels-to-coordinates

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!