determine the boundaries of intricate shapes in an image with a white background using JavaScript

How can I efficiently determine the boundaries of an image, specifically focusing on the non-white pixels using JavaScript algorithms?

For instance, how could I generate lists containing the x and y points corresponding to the boundary pixels of an object like this:

https://i.sstatic.net/ntSUp.png

It's important to note that the interior section should be included while any completely white areas within (like holes) should be excluded.

Therefore, the desired outcome would be two lists representing the x and y coordinates for constructing an object similar to this:

https://i.sstatic.net/h7DZy.png

Below is my current approach, which successfully handles concave objects but struggles with more complex shapes featuring convex sides.

Success with Concave Object

Challenges with Complex Object

You can observe in the provided examples that the algorithm fails to accurately capture the inside of the more intricate, convex image.

The Question Persists

Hence, the question remains: what effective method can be employed to create a mask or outline of the image (excluding holes) that effectively covers the external regions of any complex/convex object where the background is white and the object components are colored? Thank you.

Answer №1

Utilizing a flood-fill algorithm, this method covers the outer regions with white and the inner areas with black.
It's important to note that this implementation is basic, as there are numerous optimizations that could enhance its efficiency (such as calculating the bounding rectangle and only filling inside it or utilizing 32-bit arrays for pixel assignment during filling).
Additionally, the filling always commences at the upper left corner; if the object currently occupies that pixel, an alternative pixel can be selected for the starting point.

For brevity, touch handlers and some other elements have been omitted from the example. The updateMask function is responsible for generating the mask.

function createCube(color, x, y){
    const geo = new THREE.BoxBufferGeometry(1, 1, 1);
    const mat = new THREE.MeshPhysicalMaterial({ color: color, opacity: 1 });
    const mesh = new THREE.Mesh(geo, mat);
    mesh.position.x = x;
    mesh.position.y = y;
    return mesh;
}

const c_main = document.getElementById("main");
const c_mask = document.getElementById("mask");
const ctx_mask = c_mask.getContext("2d");
ctx_mask.fillStyle = "#000";
const cw = c_main.width, ch = c_main.height;

const TWO_PI = Math.PI * 2;
const damp = 75, radius = 10, animspeed = 0.001;
const center = new THREE.Vector3(0, 0, 0);
let x1 = 0;
let phi = Math.PI / 2;

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(35, cw / ch, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ canvas: c_main, alpha: true, antialias: false });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(cw, ch);
const camLight = new THREE.PointLight(0xdfdfdf, 1.8, 300, 2);
scene.add(new THREE.HemisphereLight(0x999999, 0x555555, 1));
scene.add(new THREE.AmbientLight(0x404040));
scene.add(camLight);
const cubes = [];
cubes.push(createCube(0x2378d3, 0, 0));
cubes.push(createCube(0xc36843, -0.75, 0.75));
cubes.push(createCube(0x43f873, -0.25, 1.5));
cubes.push(createCube(0x253621, 1, 0.35));
scene.add(...cubes);

function initialize() {
    c_main.addEventListener("mousedown", mouseDown, false);
    updateCamera();
    animate();
}

function updateMask(){
    //First, fill the canvas with black
    ctx_mask.globalCompositeOperation = "source-over";
    ctx_mask.fillRect(0,0, cw, ch);
    //Then using the composite operation "destination-in" the canvas is made transparent EXCEPT where the new image is drawn.
    ctx_mask.globalCompositeOperation = "destination-in";
    ctx_mask.drawImage(c_main, 0, 0);

    //Now, use a flood fill algorithm of your choice to fill the outer transparent field with white.
    const idata = ctx_mask.getImageData(0,0, cw, ch);
    const array = idata.data;
    floodFill(array, 0, 0, cw, ch);
    ctx_mask.putImageData(idata, 0, 0);

    //The only transparency left are in the "holes", we make these black by using the composite operation "destination-over" to paint black behind everything.
    ctx_mask.globalCompositeOperation = "destination-over";
    ctx_mask.fillRect(0,0, cw, ch);
}  

// More code here...

initialize();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.js"></script>
<canvas id="main" width="300" height="200"></canvas>
<canvas id="mask" width="300" height="200"></canvas>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for optimizing snabbdom rendering speed

I am currently working on a node.js project where I render html on the back end using snabbdom. However, I have noticed that when the server receives a high volume of requests, it starts to slow down significantly. My hypothesis is that this is due to no ...

Using CSS to design a table-like structure with rows that span multiple columns

I am trying to generate a table dynamically using CSS and a JSON array. For example: In the code snippet provided, I have assigned a class of 'spannedrow' to span certain cells in the table, although the class is not defined yet. This is just ...

Which should you use: "states" in javascript or php?

After spending some time working with FLEX and its "states" declaration, I find myself in need of guidance as I transition into Facebook development. Specifically, I am unsure how to navigate between pages created with html without the use of php. Can some ...

Unable to apply an icon using a style component, yet the same style functions correctly in a ".css" file

I am currently using a styled component, and for some reason, I can't see my icon in the HTML. However, the same setup is working perfectly fine in the .css file. // CSS .name { width: 70%; height: 40px; margin-top: 20px; background-im ...

Whenever I hit refresh on my Three.js based page, Firefox fails to clear the memory properly

I've spent the last hour coding a web page in Three.js while using Firefox as my browser. Strangely, every time I hit refresh in Firefox, the memory usage keeps increasing. Does Firefox not have a garbage collector? When I check the memory tools, I no ...

JQuery toggle class transition failing to function

I have attempted to incorporate CSS transitions to toggle classes, but unfortunately, they are not functioning as expected. No change occurs. Here is a reference to the code in question: https://jsfiddle.net/n1rz7jqp/ JQUERY: $('.right-side-men ...

What is the process for adjusting the scale value in pixels?

Is there a way to adjust the object's scale based on pixel value using three.js? object.scale.set(0.05,0.05,0.05); I am aiming to set the size at 0.05 pixels. ...

Integrate Javascript Chart into Your Rails Application

As a newcomer to Rails, I am attempting to incorporate a JavaScript chart from Highcharts.com into my Rails application. However, I have encountered an issue where the view container remains empty. I have downloaded the package and added it to vendor/asse ...

I am unsure about how to properly implement the reduce function

I am struggling with implementing the reduce function in my code. I have data output from a map function that consists of two documents. For example, one document contains: key "_id":"AD" "values" { "numtweets" : 1, "hastags" : ...

Two ng-click events are triggered within a nested ng-click

I am facing an issue with using the ng-click within a nested list under another list that also has a ng-click event. Here is my code snippet: <ul> <li ng-repeat="facet in node.Facets" ng-click="updateNav(facet.Action)" ng-cloak & ...

JavaScript runs a function multiple times at various intervals

While tackling the well-known Ransom Note task, especially from a platform like HackerRank, I delved into experimenting with the execution time of a JavaScript function. My focus shifted slightly from the original task as I explored how the function perfor ...

"Maximizing the efficiency of passing state in React: expert tips

I am currently working on developing a social media platform similar to Facebook. A crucial feature of this project is the feed, which displays a list of posts retrieved from the database and rendered dynamically. In Feed.js const [posts, setPosts] = useS ...

What possible reasons could explain why certain AngularJS code only functions properly when the Internet Explorer console is actively open

Encountering a peculiar issue with an AngularJS controller (2 way data binding issue using IE 11 with AngularJS). Strangely, the problem seems to resolve itself when I have the debugging tools open in IE 11. Any insights on why this could be happening and ...

Is it possible to center the image and resize it even when the window is resized?

My goal is to position an image in the center of the screen by performing some calculations. I've tried using: var wh = jQuery(window).innerHeight(); var ww = jQuery(window).innerWidth(); var fh = jQuery('.drop').innerHeight(); var fw = jQ ...

Simulating a service call in an AngularJS controller

Here is the code for my Controller: (function () { 'use strict'; angular.module('myApp').controller('myCtrl', function ($scope, myService) { // Start -----> Service call: Get Initial Data myService ...

Unforeseen outcomes arise when toggling expansion in JavaScript

I have a pop-out div at the top of my page that expands and closes on toggle. Also, when I toggle the pop-out div, it changes the top position of another div (a side pop-out menu). The issue is that the side pop-out menu should only appear when clicking ...

Trouble encountered with JSX in my custom React Library after transitioning to Preact

I've created a straightforward React library that I implement with my own state management, utilizing just a Higher Order Component: import React from 'react'; const connect = (state, chunk) => Comp => props =>{ const newProps ...

Navigate through the rows and columns of an HTML table by utilizing Javascript with webdriver, specifically for Protractor in a non-angular environment

I need help with iterating through rows and columns using Selenium Webdriver. I am currently using Protractor for a non-angular web page. I have some Java code that works with the WebElement class to get the number of links, but now I need to transition th ...

Is it possible to have the background scroll downward while keeping some content centered in place at all times?

Attempting to achieve the following effect in JavaScript, HTML, and Sass: When scrolling down the page, the layers (ground, sky, space, etc.) move downward The content (a rocket flying in the sky) stays centered on the screen and will move horizontally l ...

Guide on How to Retrieve the Following YouTube Video using a PHP Array

I have a PHP/HTML script that currently loads a random YouTube video from an array every time the page is refreshed. However, I am looking to add functionality for next and previous buttons to allow users to cycle through the videos in the array. The goal ...