Alvin K.
Alvin K.

Reputation: 4379

Area estimation with tiling

This is something a kid can try with markers and graph paper. Area estimation with tiles and it led me to this question: https://math.stackexchange.com/questions/978834/area-estimation-with-tiling

I wrote a simple code in <canvas> which looks at the top-left pixel of a tile, if the color is not red, it turns the tile blue.

Question: How to improve the AI so that it discards only tiles that contains less then 50% red color? Do I need an average (color density) function to determine this?

Here's my fiddle code, with black borders. The actual area is 3750 units. Naturally if I reduce the tile size, it gets closer to the actual area (read: calculus - too advance for a kid).

var sourceHeight = 90;
var sourceWidth = 300;
var pixelation = 10;
var tile_count = 0;

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.moveTo(50, 75);
ctx.lineTo(200, 75);
ctx.lineTo(100, 25);
ctx.lineTo(50, 75);
ctx.fill();
ctx.fillStyle = 'lightgreen';
ctx.rect(0, 0, sourceWidth, sourceHeight);
ctx.fill();

var imgData = ctx.getImageData(0, 15, sourceWidth, sourceHeight);
var data = imgData.data;
for (var y = 0; y < sourceHeight; y += pixelation) {
    for (var x = 0; x < sourceWidth; x += pixelation) {
        var red = data[((sourceWidth * y) + x) * 4];
        var green = data[((sourceWidth * y) + x) * 4 + 1];
        var blue = data[((sourceWidth * y) + x) * 4 + 2];

        if (red > 200) {
            red = 255;
            blue = 0;
            green = 0;
            tile_count += 1;
        } else {
            red = 135;
            green = 206;
            blue = 235;
        }

        for (var n = 0; n < pixelation; n++) {
            for (var m = 0; m < pixelation; m++) {
                if (x + m < sourceWidth) {
                    data[((sourceWidth * (y + n)) + (x + m)) * 4] = red;
                    data[((sourceWidth * (y + n)) + (x + m)) * 4 + 1] = green;
                    data[((sourceWidth * (y + n)) + (x + m)) * 4 + 2] = blue;
                }
            }
        }
    }
}
ctx.putImageData(imgData, 0, 115);

ctx.fillStyle = "black";
ctx.font = "14px Georgia";
ctx.fillText("Tile Size: " + pixelation, 200, 140);
ctx.fillText("Total Tiles: " + tile_count, 200, 155);
<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;"></canvas>

Upvotes: 0

Views: 62

Answers (1)

MvG
MvG

Reputation: 60868

I'd simply count the number of red pixels in the tile vs. the number of non-red ones:

        var redcnt = 0, nonredcnt = 0, red, green, blue;
        for (var n = 0; n < pixelation; n++) {
            for (var m = 0; m < pixelation; m++) {
                if (x + m < sourceWidth) {
                    red = data[((sourceWidth * (y + n)) + (x + m)) * 4];
                    if (red > 200)
                        ++redcnt;
                    else
                        ++nonredcnt
                 }
            }
        }
        if (redcnt >= nonredcnt) {

var sourceHeight = 90;
var sourceWidth = 300;
var pixelation = 10;
var tile_count = 0;

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.moveTo(50, 75);
ctx.lineTo(200, 75);
ctx.lineTo(100, 25);
ctx.lineTo(50, 75);
ctx.fill();
ctx.fillStyle = 'lightgreen';
ctx.rect(0, 0, sourceWidth, sourceHeight);
ctx.fill();

var imgData = ctx.getImageData(0, 15, sourceWidth, sourceHeight);
var data = imgData.data;
for (var y = 0; y < sourceHeight; y += pixelation) {
    for (var x = 0; x < sourceWidth; x += pixelation) {
        var redcnt = 0, nonredcnt = 0, red, green, blue;
        for (var n = 0; n < pixelation; n++) {
            for (var m = 0; m < pixelation; m++) {
                if (x + m < sourceWidth) {
                    red = data[((sourceWidth * (y + n)) + (x + m)) * 4];
                    if (red > 200)
                        ++redcnt;
                    else
                        ++nonredcnt
                 }
            }
        }
        if (redcnt >= nonredcnt) {
            red = 255;
            blue = 0;
            green = 0;
            tile_count += 1;
        } else {
            red = 135;
            green = 206;
            blue = 235;
        }

        for (var n = 0; n < pixelation; n++) {
            for (var m = 0; m < pixelation; m++) {
                if (x + m < sourceWidth) {
                    data[((sourceWidth * (y + n)) + (x + m)) * 4] = red;
                    data[((sourceWidth * (y + n)) + (x + m)) * 4 + 1] = green;
                    data[((sourceWidth * (y + n)) + (x + m)) * 4 + 2] = blue;
                }
            }
        }
    }
}
ctx.putImageData(imgData, 0, 115);

ctx.fillStyle = "black";
ctx.font = "14px Georgia";
ctx.fillText("Tile Size: " + pixelation, 200, 140);
ctx.fillText("Total Tiles: " + tile_count, 200, 155);
<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;"></canvas>

Upvotes: 1

Related Questions