如何计算涂色区域的面积?

3
我用以下类似的代码在画布上绘制自由笔画。 我需要检查画布有多少被笔画覆盖。 有什么好方法可以检查吗? 我能想到的唯一方法是在鼠标抬起事件时计算具有特定颜色的像素数。 但这很糟糕,因为它很慢... 有什么建议吗?
$(document).ready(function(){
    var draw = false;
    var x_prev = null, y_prev = null;
    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");
    canvas.mousedown(function(e){
        draw = true;
        x_prev = e.pageX - this.offsetLeft;
        y_prev = e.pageY - this.offsetTop;
    });
    window.mouseup(function(){draw=false});
    canvas.mousemove(function(e){
        if(draw){
            context.beginPath();
            context.moveTo(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
            context.lineTo(x_prev, y_prev);
            context.stroke();
            context.closePath();
            x_prev = e.pageX - this.offsetLeft;
            y_prev = e.pageY - this.offsetTop;
        }
    });

线条有多粗?此外,您是否考虑了抗锯齿? - Blender
任意厚度。但是厚度是硬编码的。我不太关心抗锯齿,我只需要一个能给我一个好近似值的东西。这是为了游戏,我不需要高精度。 - akonsu
你打算如何处理线条重叠的情况?你可以使用area += thickness * sqrt((e.pageX - this.offsetLeft - x_prev)^2 + (e.pageY - this.offsetTop - y_prev)^2);,但这并不能解决相交的线条问题。 - Blender
没错,这就是问题所在 :) 我可以算出每条线段的面积,考虑到它的厚度,但如何高效地对所有线段进行计算我不知道... - akonsu
你可能需要做类似于这个问题的解决方案:https://dev59.com/XXVC5IYBdhLWcg3wlyQo。 - Bill
你是否真的尝试过计算透明度超过特定阈值的像素数量来证明它很慢? - Phrogz
2个回答

3

计算机非常。当绘制时,每帧重新计算特定alpha上的像素数对我来说已经足够快了。您可以在此处自行测试:http://jsfiddle.net/ZC8cB/3/

相关代码:

var w = canvas.attr('width'),
    h = canvas.attr('height'),
    area = w * h;

function updateArea() {
  var data = context.getImageData(0, 0, w, h).data;
  for (var ct=0, i=3, len=data.length; i<len; i+=4) if (data[i]>50) ct++;
  $fill.html(ct);
  $pct.html((100 * ct / area).toFixed(2));
}

如果速度真的太慢,您可以选择每次鼠标移动更新一次区域、每隔三次鼠标移动更新一次区域等方式,或者使用定时器。例如,这里有一个稍微修改过的版本,只在每十次鼠标移动时更新:http://jsfiddle.net/ZC8cB/4/ 如果单帧计数速度太慢——因为您的电脑很慢或画布非常大或两者都是——那么您可以在一帧中获取ImageData,并在每个更新帧中计算特定部分的像素。

最终我做的跟这个差不多,只是我在“鼠标松开”事件上扫描画布。 - akonsu

1

将区域量化为线宽大小的正方形,并计算绘制过程中遇到的唯一正方形数量。

var thickness = 4
var height = ..
var width = ..
var drawn = []
var covered = 0;

canvas.mousemove(function(e) {

    var x = e.pageX - this.ofsetLeft;
    var y = e.pageY - this.offsetTop;
    x = parseInt( x / width ) * ( width / thickness )
    y = parseInt( y / height ) * ( height / thickness )
    id = x + y * parseInt(thickness / width)
    if ( !drawn[ id ] ) {
       drawn[ id ] = 1;
       covered++;
    }

}

通过将覆盖的正方形数量除以总正方形数量,可以获得以百分比表示的绘制区域。

var a = covered / ((width / thickness) * (height / thickness))

谢谢您的回答,您能否解释一下这段代码? - akonsu
非常简单,它维护一个网格以跟踪鼠标在绘图时行进了多少个正方形(厚度定义了大小)。已覆盖计数器计算了已涂色正方形的数量。 - Teemu Ikonen
谢谢。这对我来说可能有效,除了当鼠标移动得太快时,事件处理程序无法为轨迹中的所有点调用(这就是我在代码中使用moveTo()和lineTo()的原因)。 - akonsu
在这些情况下,你需要进行一些外推来保持估计更加准确。 - Teemu Ikonen

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