Search code examples
javascriptarraysalgorithmconnected-components

Connected components labeling pixels with javascript?


I have array of pixes. From the beginning I need to remove the black background from the PNG and then somehow group the remaining white pixels together in the array of arrays. Were every subarray coresponds to pixels (shape) blob cordinates. And the question is how to do connected component labeling in javascript? Maybe there is a library that does that?

[[10,34,34,10],[72, 300, 72, 30]]

This is how I remove the black pixels:

   const black2transparent = (img: HTMLImageElement) => {
    const c = document.createElement("canvas");

    const w = img.width;
    const h = img.height;

    c.width = w;
    c.height = h;

    const ctx = c.getContext("2d");

    if (!ctx) {
      return "";
    }

    ctx.drawImage(img, 0, 0, w, h);
    const imageData = ctx.getImageData(0, 0, w, h);

    const pixel = imageData.data;

    const r = 0;
    const g = 1;
    const b = 2;
    const a = 3;

    for (let p = 0; p < pixel.length; p += 4) {
      if (pixel[p + r] === 0 && pixel[p + g] === 0 && pixel[p + b] === 0) {
        pixel[p + a] = 0;
      }
    }


    ctx.putImageData(imageData, 0, 0);

    return c.toDataURL("image/png");
  };

Solution

  • const black2transparent = (img: HTMLImageElement) => {
        const c = document.createElement("canvas");
    
        const w = img.width;
        const h = img.height;
    
        c.width = w;
        c.height = h;
    
        const ctx = c.getContext("2d");
    
        if (!ctx) {
          return "";
        }
    
        ctx.drawImage(img, 0, 0, w, h);
        const imageData = ctx.getImageData(0, 0, w, h);
    
        const pixel = imageData.data;
    
        const r = 0;
        const g = 1;
        const b = 2;
        const a = 3;
    
        let x = 1;
        let y = 0;
        const whiteLines = [];
        let lastWhitePixelStart = null;
    
        for (let p = 0; p < pixel.length; p += 4) {
          if (p > 0 && p % (w * 4) === 0) {
            x = 1;
            lastWhitePixelStart = null;
            y += 1;
          } else {
            x += 1;
          }
    
          if (pixel[p + r] === 0 && pixel[p + g] === 0 && pixel[p + b] === 0) {
            pixel[p + a] = 0;
    
            if (lastWhitePixelStart !== null) {
              whiteLines.push([lastWhitePixelStart, { x, y }]);
              lastWhitePixelStart = null;
            }
          } else {
            if (lastWhitePixelStart === null) {
              lastWhitePixelStart = { x, y };
            }
          }
        }
    
        const blobs: MaskDataType[] = [];
        while (whiteLines.length) {
          let line = whiteLines.shift();
          if (!line) break;
          let categorized = false;
    
          for (let i = 0; i < blobs.length; i += 1) {
            let blob = blobs[i];
    
            if (blob.maxY + 2 < line[0].y) continue;
    
            if (blob.minX > line[1].x || blob.maxX < line[0].x) {
              continue;
            }
    
            blob.maxY = line[0].y;
            blob.minX = Math.min(blob.minX, line[0].x);
            blob.maxX = Math.min(blob.maxX, line[1].x);
            blob.lines.push(line);
            categorized = true;
          }
    
          if (!categorized) {
            blobs.push({
              minY: line[0].y,
              maxY: line[0].y,
              minX: line[0].x,
              maxX: line[1].x,
              lines: [line],
            });
          }
        }
    
        // blob contains array of white pixels coordinates
        setMaskData(blobs);
    
        ctx.putImageData(imageData, 0, 0);
    
        return c.toDataURL("image/png");
      };
    

    Array of pixels are in blobs