Image - an image processing library based upon Vix

At the time Imagi.ne was available. But I didn’t buy it. And of course the way these things work, the registrar takes my search results and then takes it for “resale”.

I am considering a paid service as a Pro option. I’ll see how that goes.

All in all, I like your ideas :grinning:

4 Likes

Dang, that is what I need right now, lol. Well, I need that and additional functionality that wouldn’t quite fit, but regardless, it’s exciting and I look forward to seeing Imagine!

I see it as available (using gandi.net), but the price is through the roof for this top level domain name. I hope Nigerians can have a better deal, because more than 700 euros a year is crazy even for western pockets.

I looked at inwx.de, which is actually cheap at 380€/y compared to over 700.

1 Like

Always open to ideas so if you have a need, open an issue! Or discuss here, happy either way.

Essentially I need to do @kwando’s example, so an image, resize it, maybe filter it, then compose it together with a mask. I suppose that could be achieved through multiple calls to Imaginary (sorry, thinking in real time here and trying to disaccociate my thinking from what I’ve already been building).

I also need to produce some vector images (for print files) but that is obviously out of scope of Image.

That should all be possible in a single web request since transforms will be composed and the URL format allows specifying multiple transforms.

I’ve published Image version 0.33.0 with the following breaking changes:

Breaking Changes

  • Image.dhash/1 now returns a 64-bit hash rather than a 512-bit hash. The original algorithm is intended to return a 64-bit hash so this is both a breaking change and bug fix.

  • Fix generation of images from text when autofit: false (the default). In these cases the text image is generated from SVG. The original implementation operated on the basis that the image would be generated with a height and width necessary to contain the text of a given font size. The result is not consistent and is influenced by whether the text has ascenders or desenders. The new implementation creates an SVG container of a size large enough to contain the text at the given font-size and then trims away the background to produce the final result. Thanks to @ilesar for the report. Closes #86. As a result of this fix, existing text-generated images may not now be the same as previous releases.

I apologise especially for the breaking changes in text image generation but the previous approach was delivering unpredictable - and usually inconsistent - results.

6 Likes

Meh, pre-1.0 :upside_down_face:

Thanks for your continued work on this lib!

I tried to use the Image library to do a fuzzy comparison of two images by using Image.hamming_distance but it was too fuzzy for my purposes — a picture of a cat and a picture of a house got a hamming distance of 0 (they were both relatively small, square, grayscale images).

Any suggestions on a way to do a fuzzy comparison that’s a bit less fuzzy? (Maybe something analogous to the ImageMagick command magick compare -metric AE -fuzz 10% cat.png house.png diff.png ?)

@eahanson, image comparisons are tricky things and I’m learning a lot. If I’ve understood correctly, the magic compare -metric AE -fuzz 10% means;

  • -metric AE: means absolute error (ie pixel by pixel comparison)
  • -fuzz 10% means the root mean squared difference between the two images should fall in that range of 10% difference

I use a very similar approach in the test suite so I think implementing this is straight forward. But I’d like to do some validation.

May I ask you to DM me the two images you used (I know they are just examples, but it gives us a baseline) - either attach the images or send links is fine.

I am also going to implement at least PSNR and SSIM sooner rather than later. I’m open to other ideas and suggestions.

I’ve published image version 0.34.0. Special shoutout to @sodapopcan who demonstrated amazing patience while I fuddled though making text images work consistently and correctly.

Example of Image.compare/3

The main feature of this release is a way to compare images and return a similarity score and a difference image. This is similar to the same function in ImageMagick.

iex> image_1 = Image.open!("./test/support/images/Kamchatka-2019-8754.jpg")

image

# Image 2 is the same image, only with a cat overlayed upon it.
iex> cat = Image.open! "./test/support/images/cat.png"
iex> image_2 = Image.compose!(i, cat, x: :middle, y: :center) |> Image.flatten!

image

# Now we can compare the image with the defaults of 
# `metric: :ae, difference_color: :red, saturation: 1.0, brightness: 1.0, difference_boost: 1.5`
iex> {:ok, metric, difference_image} = Image.compare(image_1, image_2)
{:ok, 0.13152029520295203,
 %Vix.Vips.Image{ref: #Reference<0.1501890617.2351562776.180408>}}

image

# Note how the pixels that were different between the two images are masked in red overlaid on the original image. Its possible to adjust the brightness and saturation of the base image and to boost them for the difference pixels.  Here's an example:
iex> {:ok, metric, difference_image} = Image.compare image_1, image_2, brightness: 0.5, saturation: 0.2, difference_boost: 2.0
{:ok, 0.13152029520295203,
 %Vix.Vips.Image{ref: #Reference<0.1501890617.2351562776.180435>}}

image
Note how the difference pixels stand out more strongly. You can also see there is a color gradient to the difference pixels. The shading indicates how much different (mathematical difference, not perceptual difference) the pixels are.

10 Likes

I’ve published image version 0.35.0 which focuses primarily on contrast management of an image. Here’s the changelog:

Breaking change

  • Removes Image.autolevel/1 which is replaced by Image.equalize(image, :each).

  • Removes Image.normalize/1 which is replaced by Image.equalize(image, :luminance).

Enhancements

  • Adds Image.equalize/2 which expands an image to fill the tone range. Equalization can be performed on all bands, on each band or only on the luminance band. This function replaces Image.normalize/1 and Image.autolevel/1.

  • Adds Image.contrast/2 to apply simple contrast adjustments to an image. The contrast parameter is provided as a float >= 0.0 with contrast less than 1.0 meaning reduce contrast and greater than 1.0 meaning increase contrast.

  • Adds Image.apply_tone_curve/2 which applies a tone curve to an image. This is typically used to affect overall image contrast.

  • Adds Image.local_contrast/2 which applies a Constrast Limited Adaptive histogram equalization (CLAHE) to improve local contrast in images.

  • Adds Image.sharpen/2 to apply sharpening to an image.

  • Adds Image.modulate/2 to adjust an image using brightness, saturation, hue rotation and lightness in a single call.

  • Adds Image.band_format/1 to return the band format of an image in Nx notation.

  • Adds Image.with_band_format/3 to cast an image to a new band format, execute a function on the cast image and then re-cast the image back to its original band format if the function returns successfully.

  • Adds Image.range/1 that returns the possible range of values for a pixel as a tuple in the form {min_value, max_value}.

  • Adds Image.reduce_noise/2 and Image.reduce_noise!/2 that applies a median filter to reduce salt and pepper noise in an image.

10 Likes

Another Sunday, another release, image version 0.36.0. It’s a relatively small release but given all the contrast-related enhancements last week, one of the key features missing has been histograms.

Enhancements

  • Adds Image.Histogram.as_svg/2 and Image.Histogram.as_image/2 to return the histogram of an image as either an SVG format suitable to adding to an HTML page or as an t:Vix.Vips.Image.t/0. The histogram is separated into red, green, blue and luminance bands.

Example

iex> i = Image.open! "./test/support/images/Kamchatka-2019-8754.jpg"

iex> Image.Histogram.as_image!(i, height: 1024, width: 2048)

15 Likes

Hello,
I have request from a client, to attach custom text from user input on a licence plate frame and preview it by user on app.
I do not have anything working, since I do not want to accept the project if I do not if this is possible with elixir and liveview.

Use case: User enters custom text with selected font and that should be applied as a preview on a licence plate frame.
Here is an example of a plate which text should be customized.

Please I need some guidance if this is even possible to do and what are trade offs I should be aware before making the offer to the client. Thanks!

Based upon your description there shouldn’t be any issues. I will put a quick proof-of-concept together. A few questions:

  • Is the location of the text configuration?
  • What are the valid locations for the text (do you have an example of a completed plate?)
  • Are you also aiming to configure the colour of the plate background, plate numbers, etc?
  • Do you have a hi-res version of the plate template?

Happy to continue here, but suspect this is better as a discussion on the GitHub repo.

1 Like

I mocked up a simple demonstration that should get you a fair way along the the path to what you are after.

Example

This example needs image version 0.36.1 which I published today (the only change is to add support for negative offsets for :x and :y.

iex> license_plate_frame = Image.open! "/Users/kip/Desktop/License_plate_frame.png"
%Vix.Vips.Image{ref: #Reference<0.642921347.487981081.40502>}

iex> text = Image.Text.text!("Kennzeichenhalter.ch", font_size: 60, font: "Helvetica Neue")
%Vix.Vips.Image{ref: #Reference<0.642921347.487981081.40530>}

text

iex> Image.compose!(license_plate_frame, text, x: :middle, y: -60)

Other thoughts

  • Hopefully you can get an SVG of the frame template. This would allow you to do the whole thing in SVG and only render an image at the end.
  • The example doesn’t include the horizontal rules in your example. These can be added without too much trouble
    • Create the rule as an SVG-based image
    • The length of each rule would be something like “total length of text space - width of text image - (2 * space between text and rule) / 2”
    • The font has to be a font known to the system on which is operates. Basically a font in the list returned by fc-list on your system.
3 Likes

@kip Thanks a lot for the example. I got some flu, so I will play around with this library in couple of days. The client will send me SVG hopefully in a few days
For the start only the text which will be collected trough user input on text field, should be displayed on the bottom, like your example. It can be either trough liveview for live preview or it can be generated on server side like traditional app and render an image. When I start experimenting I will get more questions, so I will be free to post here or on github.
Thanks a lot again!

For your UI requirements, I would try to craft everything in SVG and have the browser render it. You distribute the compute requirements, you get auto scaling etc etc. Then only use image if you need to render an image server-side.

4 Likes

cool, thanks. When I have something meaningful, I will share code or some live demo. Thanks again!