tmariaz

tmariaz

Image comparison with existing list of images

I am uploading an image to the server. Before it gets uploaded I wanted to check whether I have already uploaded the same image before.

All the uploaded images can be accessed via the url https://myserver/image/{image_id}. As a current user I can get the list of images from the repo.

Now I can select the new image and it stores temporarily in the server. I wanted to compare new_image_url with the list of images stored in the server.

def compare_image(temp_img_url)
   # code to get the list of images from repo
   Enum.each(images, fn m ->
     user_image = “https://myserver/image/#{m.id}”
     {:ok, duplicate_image} = compare_images_from_url(temp_img_url, user_image)
   end)
end

def compare_images_from_url(tmp, current) do
    response = HTTPoison.get!(image_url, [], hackney: [recv_timeout: 15_000, timeout: 150_000])

    case response.status_code do      
         # logics to compare the images 
         # .....
         # return true if there is a duplicate
    end
end

There is a possibility that a user can have 1000s of images. But it is not ideal to compare every single image to find that. Which sounds costly.

What is the best way to do this?

Most Liked

kip

kip

ex_cldr Core Team

The general strategy for “image is basically the same” is to use a perceptual hash. Image.dshash/1 will generate such a hash which can stored in the database if you need, for each image. Or just use the hash to compare with the hash of other images.

A perceptual hash overcomes the issues of same image but different resolution, or different image format, or different image colorspace. But still the “same” image.

Something like:

def kinda_the_same?(image_1, image_2) do
  Image.dhash(image_1) == Image.dhash(image_2)
end
kip

kip

ex_cldr Core Team

Yes, you are right. Basically the image is resized, converted to BW, convolved to sharpen the edges and that’s basically the “image hash”. You can see the code here.

Im not 100% happy with the implementation but as best I can test it works as expected (please open issues if you find otherwise). I’ve fixed the implementation to return the expected 64-bit hash (not the previous 512-bit hash which was wasting space).

kip

kip

ex_cldr Core Team

Probably slower because it involves image resizing, edge detection, contrast enhancement. But its not testing for identical. Identical is not very meaningful for image comparison since different compression algorithms and settings mean the image doesn’t round trip after decoding.

You can use mean square error as a way to establish “similarity” between two images. I use this in the test suite to overcome some the challenges - there can be different results across different library builds, system architectures and so on.

Basically the code for image similarity is:

    similarity =
      calculated_image
      |> Math.subtract!(validate_image)
      |> Math.pow!(2)
      |> Vix.Vips.Operation.avg!()

Note the operations are matrix operations since an image is basically just a matrix.

Last Post!

Lucassifoni

Lucassifoni

I had been quite happy adding multiple heuristics to a client app working mainly on images a few years ago.
I stored :

  • SHA hash
  • File name
  • Perceptual hash (I’d have to find the library)
  • Luminance fingerprint (basically a 8x8 or 16x16 grayscale version of the image)
  • Mime type
  • File size
  • Image width
  • Image height

That allowed me to have quite effective deductions on those questions :

  • Are two images the same ?
  • Are two images minor derivations of the same original (a bit resized, a bit cropped, a bit of this and that and renamed or converted..)

For confusing answers to those questions I had a “potential duplicates” list that someone could check. Maintaining and cleaning that list was useful for the business purposes though, not just to limit storage use.

The answer to “are those two images the same” mainly depend on your specific use case. Maybe identical files are a good enough answer, maybe you’d prefer something more like “do the two image files contain the same picture as seen by an user ?”.

Good luck ! This is a fun topic :slight_smile:

Where Next?

Popular in Questions Top

RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

Other popular topics Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49084 226
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New

We're in Beta

About us Mission Statement