If you’ve seen a really fast wasm solution I’d love to replace the fill portion with it though.
> If a wasm algorithm can run in under 16ms for arbitrarily large images that would be amazing
that would indeed be amazing, because nothing that might change every pixel can run in any fixed period of time for arbitrarily large images; it's necessarily linear time in the worst case, if not worse
i think you are trolling
Precomputing fill areas is a really good idea for the situation you're in!
Edit: actually it was 7 years https://github.com/irskep/literallycanvas-pro-tools/blob/mas...
it also has 10 other method and function calls in it, one of which allocates a new 4-element array
also it's maintaining a stack of pixels to paint instead of looping over a scan line
each iteration of the loop paints one pixel
i don't think canvas memory access patterns are the root of the performance problem
i'm not saying it's bad code, just that it doesn't justify your conclusion
no flood-fill algorithm can run in less than 16ms, or less than any finite time, for arbitrarily large images; they necessarily require at least linear work and, even with arbitrary parallelism (itself impossible in a finite universe), logarithmic time
you need to bound the image size if you are going to bound the execution time
so this is not a good faith request; it is, rather, a deliberately impossible task, like spinning straw into gold, finding an acre of land between the salt water and the beach, making a cambric shirt with no seams or needlework, or reaping a crop with a sickle of leather
unfortunately my previous comment pointing this out has been flagged and is therefore generally no longer visible; i consider this sort of response to a purely logical argument of impossibility to be astoundingly mean-spirited and contemptible
i agree that it's easy to better its performance substantially, but i wouldn't go so far as to say 'perform terribly', except in the sense that it's far from optimal. there are applications where it would be adequate
The code allocates data structures at least eight times per pixel, and tests pixels at least four times. It will perform badly in all languages and so cannot be used as a reliable indication of JS/Canvas performance.
there might even be a case where the single-loop sort is the right thing to use, despite its abominable performance, because it's simpler than bubble sort or insertion sort
for (i = 1; i < n; i++)
if (a[i-1] > a[i]) t = a[i], a[i] = a[i-1], a[i-1] = t, i = 1;You'd first threshold the image by checking if a pixel is 'close enough' to the clicked pixel. This will create a B&W image. Then you call the CCL on this binary image to produce a labelled image: each pixel will contain the id of its component (i.e. which enclosed space it belongs to). Once you have this, it's just a matter of replacing colors on the canvas for pixels with the same id as the clicked pixels.
Obviously, that's just the 'theory' part. If you can find a good library that includes one then you'll have to integrate it. Otherwise, you'll have to re-implement that in Javascript, which is easier said than done and may also not reach the desired performance.
I don't work in web development but accelerating CCL algorithms do happen to be my area of expertise. While their execution time depends on the image content, you can expect them to be in the tens of milliseconds for a 4K image, at least for the 'modern' one you can find in OpenCV, and on current consumer-level CPUs, without multi-threading.
Of course, implementing these newer algorithms isn't straightforward. That's why you should instead use something like OpenCV if you have the option to.
Moreover, if CCL doesn't fit what you're looking for then you can also check out watershed algorithms ( https://en.wikipedia.org/wiki/Watershed_%28image_processing%... ). Because they don't work on binary image, they might be a better way to describe what you call 'enclosed space'.
There are faster fill algorithms than the above, described on Wikipedia, that don't need you to visit the whole image [1]. In particular, span-based filling.
I don't know what OP's original code is but maybe OP was calling a Canvas API method for every pixel (super bad).
the question of memory access time is quite deep
in shane's example of flood-filling a 2048 × 2048 image in 16ms, the image is 16 mebibytes; if you have less ram than that, so that you have to page, you are not going to be able to do it. but my hand-me-down cellphone has 256 times that much ram so i guess you're using a pentium pro 200 or something, in which case you aren't going to be able to run a browser that supports canvas
assuming you're using a machine from the current millennium, and therefore has enough ram to run a browser that supports canvas, you won't need to do any paging, but you do need to think about dram bandwidth. probably the required bandwidth to dram is 2 gigabytes per second (one read and one write), while typical current ddr4 systems provide on the order of 30 or 40 gigabytes per second. that assumes you can keep the memory access reasonably sequential (if your l2 cache is less than those 16 mebibytes). this is usually the case with a simple line-by-line flood-fill algorithm, like the one used by gw-basic 40 years ago, but there are pathological images where it is not; consider a 1-pixel-black/1-pixel-white square spiral that fills the full 4 mebipixels
but images like that cause problems for shane's existing algorithm too because they will make shane's web worker spin for a long time
maybe other optimization approaches would yield a flood-fill algorithm that just runs fast enough in js; wasm can surely do it
like i feel like you can probably loop over the pixels in a scan line until you encounter an obstacle at several tens of megapixels per second
as the dumbest possible test of js perf, this code (admittedly not accessing an imagedata object) gets about 250 million iterations per second on my 2.6 gigahertz palmtop in firefox