在画布中查找正方形/矩形

4

我真的不知道该去哪里寻找这个答案。我在SO上查找,但那些问题更加复杂,例如检测汽车或游戏中的复杂形状。我只是有一个带有图像的canvas(HTML5元素),其中有许多包含图像的矩形和正方形,并且想要检测每一个形状,"将它们剪切出来",并逐一处理。我卡在了"找到"这些形状然后获取它们的坐标上。这些也不是我正在绘制的图像,而是其他人上传的图像,然后我将它们绘制到画布上。

类似于以下情况:

+------------------+
|  ----  ---  ---- |
|  |  |  | |  |  | |
|  ----  ---  ---- |
|  --------------- |
|  |             | |
|  --------------- |
|                  |
+------------------+

我希望能够删除这4个块中的每一个,以便我可以逐个检查它们,如下所示:

----     ---     ----     ---------------
|  | =>  | | =>  |  | =>  |             |
----     ---     ----     ---------------
3个回答

7

[如何进行矩形自动裁剪的概述]

首先,将画布大小调整为图像大小,并在画布上绘制图像。

然后对于画布图像中的每个矩形:

  • 使用getImageData获取画布图像上每个像素颜色的数组。
  • 从左上角开始扫描颜色。
  • 当您遇到非背景颜色时,就会遇到矩形的边缘。
  • (您必须输入背景颜色或假设左上角像素定义了背景颜色)
  • 沿着顺时针方向行走,直到返回到起始位置。
  • (“步行”意味着沿着边框像素颜色垂直/水平行进)。
  • 您已经得到了矩形的边界区域。
  • (由于反锯齿像素,您需要绑定稍大一些的区域)。
  • 创建一个临时画布并将其大小调整为发现的边界框大小。
  • 使用context.drawImage的剪辑参数将原始画布中的有界矩形复制到临时画布中。
  • 使用canvas.toDataURL将temp画布保存为图像。
  • 使用context.clearRect从画布上清除矩形像素。
  • 重新开始该过程,以查找下一个矩形。

以下是显示自动裁剪到图像的代码和演示:http://jsfiddle.net/m1erickson/33tf2/

enter image description here

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
    #clips{border:1px solid blue; padding:5px;}
    img{margin:3px;}        
</style>
<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var cw,ch;        

    // background definition
    // OPTION: look at the top-left pixel and assume == background
    //         then set these vars automatically
    var isTransparent=false;
    var bkColor={r:255,g:255,b:255};
    var bkFillColor="rgb("+bkColor.r+","+bkColor.g+","+bkColor.b+")";

    // load test image
    var img=new Image();
    img.crossOrigin="anonymous";
    img.onload=start;
    img.src="https://dl.dropboxusercontent.com/u/139992952/multple/temp2a.png";        

    function start(){
        // draw the test image on the canvas
        cw=canvas.width=img.width/2;
        ch=canvas.height=img.width/2;
        ctx.drawImage(img,0,0,cw,ch);
    }


    function clipBox(data){
        var pos=findEdge(data);
        if(!pos.valid){return;}
        var bb=findBoundary(pos,data);
        clipToImage(bb.x,bb.y,bb.width,bb.height);
        if(isTransparent){
            // clear the clipped area
            // plus a few pixels to clear any anti-aliasing
            ctx.clearRect(bb.x-2,bb.y-2,bb.width+4,bb.height+4);
        }else{
            // fill the clipped area with the bkColor
            // plus a few pixels to clear any anti-aliasing
            ctx.fillStyle=bkFillColor;
            ctx.fillRect(bb.x-2,bb.y-2,bb.width+4,bb.height+4);
        }
    }

    function xyIsInImage(data,x,y){
        // find the starting index of the r,g,b,a of pixel x,y
        var start=(y*cw+x)*4;
        if(isTransparent){
            return(data[start+3]>25);
        }else{
            var r=data[start+0];
            var g=data[start+1];
            var b=data[start+2];
            var a=data[start+3];  // pixel alpha (opacity)
            var deltaR=Math.abs(bkColor.r-r);
            var deltaG=Math.abs(bkColor.g-g);
            var deltaB=Math.abs(bkColor.b-b);
            return(!(deltaR<5 && deltaG<5 && deltaB<5 && a>25));
        }
    }

    function findEdge(data){
        for(var y=0;y<ch;y++){
        for(var x=0;x<cw;x++){
            if(xyIsInImage(data,x,y)){
                return({x:x,y:y,valid:true});
            }
        }}
        return({x:-100,y:-100,valid:false});
    }

    function findBoundary(pos,data){
        var x0=x1=pos.x;
        var y0=y1=pos.y;
        while(y1<=ch && xyIsInImage(data,x1,y1)){y1++;}
        var x2=x1;
        var y2=y1-1;
        while(x2<=cw && xyIsInImage(data,x2,y2)){x2++;}
        return({x:x0,y:y0,width:x2-x0,height:y2-y0+1});
    }

    function drawLine(x1,y1,x2,y2){
        ctx.beginPath();
        ctx.moveTo(x1,y1);
        ctx.lineTo(x2,y2);
        ctx.strokeStyle="red";
        ctx.lineWidth=0.50;
        ctx.stroke();
    }

    function clipToImage(x,y,w,h){
        // don't save anti-alias slivers
        if(w<3 || h<3){ return; }
        // save clipped area to an img element
        var tempCanvas=document.createElement("canvas");
        var tempCtx=tempCanvas.getContext("2d");
        tempCanvas.width=w;
        tempCanvas.height=h;
        tempCtx.drawImage(canvas,x,y,w,h,0,0,w,h);
        var image=new Image();
        image.width=w;
        image.height=h;
        image.src=tempCanvas.toDataURL();
        $("#clips").append(image);
    }

    $("#unbox").click(function(){
        var imgData=ctx.getImageData(0,0,cw,ch);
        var data=imgData.data;
        clipBox(data);
    });

}); // end $(function(){});
</script>
</head>
<body>
    <button id="unbox">Clip next sub-image</button><br>
    <canvas id="canvas" width=300 height=150></canvas><br>
    <h4>Below are images clipped from the canvas above.</h4><br>
    <div id="clips"></div>
</body>
</html>

这是一个很棒的代码片段!但不完全是我想要的 :) 根据我的帖子“它有一堆带有图像的矩形和正方形,我想检测每个矩形”。我正在寻找一种检测的方法。这里有一个例子:http://nedroid.com/comics/2010-09-06-guest-comic-jay-fuller.png -- 我想要能够输出这4个正方形的代码。 - Oscar Godson
它们可以是任何大小和轮廓颜色的矩形或正方形。 - Oscar Godson
我添加了一个代码示例,可以找到并剪切在画布上绘制的有边框矩形。干杯! - markE
1
我同意O.P.的观点: 你怎么敢不在第一时间给出正确的答案?(;-)+1) - GameAlchemist

0
将每个绘制形状的详细信息记录到数组中。在某个时候,你或其他人一定会告诉画布插入这些矩形和正方形,所以你应该记录下这些详细信息:
var shapes = []

// Then in some sort of listener
shapes.push({x:shapesX,y:shapesY,w:shapesW,h:shapesH})

通过监听与画布的鼠标交互(如果您是这样绘制到画布的),获取这些形状细节:

  • mousedown - 记录初始X/Y
  • mouseup - 记录用户指针从初始X/Y移动的距离以获得宽度和高度

不,就像我说的那样,上传的图像是jpg/png格式,并且上面画了方块。 - Oscar Godson

0

如果你在画布上只有带边框的矩形,则循环画布像素并检查相同颜色的序列(找到框的角落)。 HTML5 canvas data


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接