Between my own time constraints, as well as indecisiveness regarding what I should build in the first place. I admittedly didn’t accomplish as much as I would have liked this weekend, but here I am humbly presenting my project regardless.
I built a Canny edge detection image filter using MAX graphs. It does kind of work, but at the moment there are two main shortcomings.
1 . Small correctness issues seem to be present as the output doesn’t match the opencv implementation very well.
2 . It’s not actually gpu-optimized. I created a POC using foreach everywhere and didn’t have a chance to get much further than that. Although despite this, performance seems to be quite competitive with opencv already (at least on my nvidia 3080). Maybe next time I ought to shell out for a months subscription to Claude, as even the free website version was actually quite helpful.
On the bright side, MAX graphs are always wonderful to work with, and maybe at least this can be another example of what can be accomplished in terms of hardware-accelerated workloads with Mojo+MAX without actually having any knowledge of the hardware it’s running on.
Those correctness issues look like what you get without weak pixel inclusion to directionally extend the edge-detected lines. That’s a fairly simple operation (shader example here) that can be staged after the non-max suppression.
What I’d really like to do is get a generalized stencil abstraction lifted up so that we can use it for nearby pixel sampling rather than layering everything on foreach, but haven’t had the time to hack on that. Also, I’d love to see if we can use our now-open-sourced Gaussian blur kernel to accelerate the blur stage.
You may not have committed the code to your custom ops in the operations directory, so you may quick want to check those in so that the example will run locally for everyone.
Always great to see the very sweet birthday boy in these.
Thanks for the feedback Brad! It’s supposed to be doing weak pixel inclusion, but clearly not very well. I didn’t realize we had a builtin Gaussian filter now so that’s great!
The kernel code is there, it’s just direct inside of the __init__.mojo file.
Ah, cool, didn’t think to look inside __init__.mojo.
Remembering back on this, I think I needed a special Sobel operator to preserve the directional gradients, instead of the standard Sobel operator. My reference implementation was based on this paper, and as I recall you need the directional information to be able to properly extend the edge lines which we might be throwing away with the normal Sobel.