Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Snowy – a new image library for Python (prideout.net)
124 points by prideout on Sept 5, 2018 | hide | past | favorite | 26 comments



Massive opinionated opinion ahead: I like libraries that don't invent new types but just build around established ones. I think it's great that it uses numpy arrays and doesn't venture to (essentially) wrap an array of some kind and reinvent the wheel.


Yes, I'm happy with this design decision. The only bummer is that it doesn't allow daisy-chaining, as in:

    img = img.resize(...).blur(....).hflip()


I always regret writing those lines when I come back to them anyway. Any time I try to refactor them I throw something out of order or drop a function.

That said, I don't claim to be a clever man.


I didn't want to reply to not sound too opinionated (ironically) but I agree. Chains feel cool when you write them down but don't always scale and lead to mistakes as Sileni points out.

BTW, as an addition to my original comment, a good example of reinventing types are the litany of C++ libraries that do NOT use the STL but reinvent half of it.


To be fair, some of them predate the STL


What is the alternative besides chaining, devise a new variable name for every operation? I understand that daisy chaining can be error prone, but the alternative is so difficult to maintain in long chains.


If the object is modified in place (as it seems to be in this case), then the “pythonic” approach is:

   img = ...
   img.resize(...)
   img.blur(....)
   img.hflip()


The other commenter pointed out the "inplace" version, but in the event I can't get away with that (or don't want to for some reason), I tend to throw in some numbering scheme on my original variable, and at the end replace the original variable or move to a "result_object" sort of name.

I think this is an edge case that is always going to feel inelegant, so whatever makes it easiest to load into my head wins out.


I have an unchain-on-sight policy, especially for file manipulations.


Given than a numpy array could contain lots of different kinds of data, how do you tell whether you're passing something image-like? Seems like even a thin wrapper could prevent some stupid mistakes.


Something I would miss as a user is interoperability. There should be ways to read from/export to numpy arrays, pytables, PIL, OpenCV, ImageMagick, basically all the mentioned and widespread libraries so far.

(Edit: There is in fact: https://github.prideout.net/snowy/reference.html#load , haven't noticed, very good!)


Understood. Maybe it helps that Snowy does not define an Image object, instead it simply operates on numpy arrays.

See also https://github.prideout.net/snowy/index.html#interop


For Geospatial data there is the geo interface which many libraries support, I wonder if that would make sense for other disciplines as well.


What's the overlap with ImageMagick and its pals? This meant to replace or just be a smaller-tool-for-the-job?


Smaller tool, not a replacement.

ImageMagick is much bigger, more powerful, and more production ready. Snowy is hopefully a bit more Pythonic and easy to play with.


so, who is your target audience? The just getting started developer?


It's a small target audience :)

I think graphics developers like myself would be interested; people who work with distance fields, tileable images, HDR imagery, and height map data.

Maybe a technical artist at an animation studio would be interested, or someone working with map imagery.


Neat. How does it benchmark against PIL and OpenCV for common image processing tasks?


Not as fast as PIL but has reasonable optimizations like performing convolution in two passes, caching filter weights from row to row, and using numba decorations.

It's not quite apples to apples because Snowy offers a variety of filters, does everything in fp64, and is purely written in Python.


"Purely" meaning it does not add any C code; it still very actively uses numpy.


Under Alpha Composition

  icon = snowy.load('snowflake.png')
  icon = snow.resize(snowflake, height=100)
  sunset[:100,200:300] = snowy.compose(sunset[:100,200:300], icon)
  snowy.show(sunset)
Pretty sure you meant to say on line 2 `icon = snowy.resize(icon, height=100)`


Thanks, this is fixed now.


Well done! Some commenters have compared this to ImageMagick. I would equate this to comparing love2d [1] to SDL. If you want a user-friendly API for quick image manipulation, use Snowy. If Snowy doesn't give you the level of control you need, use something like ImageMagick or vips.

I could see myself using this in the future.

[1] https://love2d.org/


Would you mind defining a primary use case for this as opposed to PIL, ImageMagick or OpenCV? For the purposes of saving a description with the website.


High-quality filtering of floating-point image data.


Not OP.

PythonLib: Image is Numpy Matrix




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: