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
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
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
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.
D4no0
I think different image size can be handled easily by any fingerprinting algorithms, it gets tricky when the image is partially manipulated.
kip
Very likely a javascript implementation (almost certain).
Yes, deliberately intended to be resolution independent. And format independent. And colourspace independent.







