JSFiddle - React, Tailwind, and code Playground
by alexb
HTML
<img id="img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAFFElEQVR4nO3dXXbqOBBFYUbTg+vR3Iee7+kHLokT8yPbOlJVae+lR8BgfUs4joGbiAzdZj8BqhmwyBKwyBKwyBKwyBKwyBKwyBKwyBKwyBKwyBKwyBKwyBKwyBKw0nf778cIErCy9stTNF7AStZ7T8CiYzV6imMLWNE7QQpY9K7TpFaF9e/te9CzLpJaD9aWFLye1YUUsID1o46qVoL1ShW2epMCFrAkjypgLQ3LRApYS8OyqgIWsE5yAdYjYG2qrUrAmtXF9zVgbQLWpouHSsDaBKxNF4++gbUJWJusqoC1Liy99nH6jnFUCVgTO8cixXIlYE3vKAhg7QJWj1KoErBylWW5ErBylUWVgJWoRMuVgJWlXKoErCwB63XAOls6VQJW/FpUAQtYh8uoSsAKXtLlSsCKXF5VAlbk8qrSOFjvVQFrV+rlSsCKWXZVAlbACqgSsKLVqApYj4DVUBlVAlacKqkSpxuC1K4KWLuA9bpiqgSsCNVTJWBNr6QqAWtuVVUJWHM7dMx+fQx9aeM2BayfDVY1mBdfxz0tYPULWI9mqRpmi588mROwyBKwyBKwyFVhVQLWxIBFxuqR+vu6hm6NlglYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYZAlYmbrpz9eY/Vw+BKwcbUml4AWsBL1SBSy61BtYYW0BK3rvVQGLTgYs6t9HVcCiw+VVJWBFDljUv9SqNBPWP7fvQbuA1dxW0tNBj7Kr0ghYHz1h62ctqtaGdYgUsB4VUCUXrBOksCWpynKl/rCukFoeVhlV6gnrOqm1YVVSpW6weqla2BawdvVVtSSsYqrUAVZ3VevBqqdKwIoQsHaddgOsRyVVaTSsxjsuU1VVGgfr0B2XCVgvOn20BKzSqgSsWTWqWhWWXhM5d681YNUmdQ9Yoyu/Vt0z/Evn6O2BVU6Vpl2avCqsRVRpDqzTh/zJW+RN8B6wBrWUKk2A9VFVRVirqdJoWC2qgFWiSB//QlWhRk1ko6pysNpVAetg7aTKqdKqy5Vifa6wXMuqErB8raxKRlhrq9JKJ9mfBixLi6tSIFiFhKFKEWHl54UqxYWV1hbL1b1IfxXmt4Wqr2LDSsVr8fMLvwp25j2zLVRtC3l1Q0JbqPpVyAv9ssFC1b4YX8ed3Baw9s2erfywUPW0GLOVFhaqXhVmthLCQtWbIs0WsAoVbLbywELV+2LNVhZYqPpYoNmScsBqVAWsMCU5xpqoKpHaKLMl5YA1S1W6RTHEbElpTjdMgZXx3TbEbEkLLVfth2hHx5id0FiICau0XB268ZgxaV9FqIqqXMO8u6ZXaLnKOwy7q3uHQLSoCgBr+sSnE9Z1zo6ySKJKK8HqxWsIrKc4GlUFgDV9mjPaGvXTvYduHEmVgHVyp/WqnUgqVVoV1kVb8X5sHFhhxrWd1quiqmSD1WXTvqcXBpa62grWvOk5/8jAiq5KxydpzEatr+Lyk+9bRVVfDcDUvrkec78OLHo0bF3cb67TA3YPVT0aDKt7nulE1eVSq1KIb/SjXdmXK9kvm4HUqbKr0qDrsfB0MGCRpeyqBKyYAYtcpVYlYIUNWGQsI6l7wCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJLwCJL/wOLINWpctNgvwAAAABJRU5ErkJggg==" alt="" />
<!-- <img id="img"...
JavaScript
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
const idx = (x, y) => y * img.width + x;
const xy = (i) => ({
x: i % img.width,
y: Math.floor(i / img.width)
});
const imgData = ctx.getImageData(0, 0, img.width, img.height);
const data = new Uint32Array(imgData.data.buffer);
const regions = new Array(data.length).fill(0);
let nextRegionId = 1;
function pushcmp(stack, og, x, y) {
const i = idx(x, y);
if (regions[i] === 0 && data[i] === og) {
stack.push(i);
}
}
for (let i = 0; i < data.length; i++) {
const assignedRegion = regions[i];
if (!assignedRegion) {
const stack = [i];
const regionId = nextRegionId++;
while (stack.length > 0) {
const j = stack.pop();
regions[j] = regionId;
const { x, y } = xy(j);
if (x > 0) pushcmp(stack, data[j], x - 1, y);
if (y > 0) pushcmp(stack, data[j], x, y - 1);
if (x < img.width - 1) pushcmp(stack, data[j], x + 1, y);
if (y < img.height - 1) pushcmp(stack, data[j], x, y + 1);
}
}
}
colors = ['white', 'black', 'red', 'lime', 'yellow', 'blue'];
for (let i = 0; i < data.length; i++) {
const regionId = regions[i];
const { x, y } = xy(i);
ctx.fillStyle = colors[regionId] || 'gray';
ctx.fillRect( x, y, 1, 1 );
}
console.log(`number of discrete objects:`, nextRegionId - 2)