++ed by:
1 non-PAUSE user
Author image Ben Bullock


Image::Similar - find out how similar two images are


    use Image::Similar 'load_image';
    use Imager;
    use FindBin '$Bin';
    my $x = Imager->new ();
    # Get image data from file
    $x->read (file => "$Bin/x.png");
    # Load image into Image::Similar
    my $xi = load_image ($x);
    my $y = Imager->new ();
    # Get image data from file
    $y->read (file => "$Bin/y.jpg");
    # Load image into Image::Similar
    my $yi = load_image ($y);
    print "The difference is ", $xi->diff ($yi), ".\n";

(This example is included as synopsis.pl in the distribution.)


This documents Image::Similar version 0.07 corresponding to git commit b26adc57d72672372aa48cd62a27696160b74ba1 released on Sat Jul 15 15:57:13 2017 +0900.


This is an experimental module for comparing images. It uses a simplified form of the algorithm described in "An image signature for any kind of image" to calculate image signatures and distances between images.

The algorithm consists of converting the image into greyscale, chopping it into a grid, and then computing a signature based on relative lightness and darkness of the blocks of the grid.

The module does not contain its own image-reading facility, so images must be loaded to the module via one of the following supported Perl modules:

Imager (recommended)

All image types are supported. If you have no preference, I suggest using Imager, since it is a very well-behaved module. The conversion to greyscale is done using Imager's own routines.


All image types are supported. RGB images are combined to greyscale using constants taken from the source code of Imager.


All image types are supported. RGB images are combined to greyscale using constants taken from the source code of Imager.


This module is used for some internals of Image::Similar related to testing, thus it was installed when you installed Image::Similar. However, Image::PNG::Libpng is only for PNG images.

Image::Similar supports all PNG image types. It currently only supports bit depths of eight.

RGB images are combined to greyscale using constants taken from the source code of Imager. As of this version, there is no handling of the alpha channel (transparent pixels) and the background value is ignored.

Use "load_image" to load the image.



This loads image data from various modules into an Image::Similar object. The return value is the Image::Similar object.

Using Imager:

    use Imager;
    my $img = Imager->new ();
    $img->read (file => 'my.jpg');
    my $is = load_image ($img);

Using Image::PNG::Libpng:

    use Image::PNG::Libpng ':all';
    my $img = read_png_file ('my.png');
    my $is = load_image ($img);

The return value is an Image::Similar object.

Using GD:

    use Image::Similar 'load_image';
    use GD;
    my $gd = GD::Image->newFromPng ("t/images/chess/chess-100.png");
    my $is = load_image ($gd);

Using Image::Imlib2:

    use Image::Similar 'load_image';
    use Image::Imlib2;
    my $imlib2 = Image::Imlib2->load ("t/images/chess/chess-100.png");
    my $is = load_image ($imlib2);



    my $is = Image::Similar->new (height => 10, width => 10);

Unless you want to change internals, use "load_image" instead of this.

The returned image currently contains a field $is->{image} which you need to use the "set_pixel" method on to set the pixels.


    my $diff = $is1->diff ($is2);

This returns a floating-point number which is the difference between images $is1 and $is2. This is meant to be approximately the same value as given by "vector_euclidean_length()" in Image::Libpuzzle, but no validation has been carried out. Both $is1 and $is2 are Image::Similar objects created using "load_image".


    my $sig = $is->signature ();

Get the signature of the image. This is a text string consisting of digits 0-4 which identifies the image. The following example demonstrates getting the signature of two similar images.

    use FindBin '$Bin';
    use Image::Similar 'load_image';
    use Imager;
    for my $n (100, 1000) {
        my $image = "$Bin/../t/images/lenagercke/lena-$n.png";
        my $imager = Imager->new ();
        $imager->read (file => $image);
        my $is = load_image ($imager);
        print $is->signature (), "\n";

(This example is included as show-hash.pl in the distribution.)

Its output looks like this:



    my $diff = $is->sig_diff ($sig);

Get the difference between $sig and the image represented by $is.


    my $is = load_signature ($sig);

Load $is, an Image::Similar object, from $sig.


This section lists the testing and internal methods of the module, for people interested in extending or otherwise improving it. Since these are internal private methods, these are subject to change without notice.


    $is->write_png ('test.png');

This is used in conjunction with "png_compare" in Image::PNG::Libpng (version 0.42 or later) to check that Image::Similar has correctly read in the image, by writing out Image::Similar's internal data as a PNG file.


    use Image::Similar 'load_image';
    use GD;
    my $gd = GD::Image->newFromPng ("t/images/chess/chess-100.png");
    my $is = load_image ($gd);

This is the internal routine used by "load_image" to load GD images.


This is the internal routine used by "load_image" to load Image::Imlib2 images.


    my $is = load_image_imager ($imager, %options);

This is the internal routine used by "load_image" to load Imager images. It is not exported. The options are

    my $is = load_image_imager ($imager, make_grey_png => 'imager.png');

Make the greyscale PNG for comparing to Image::Similar's internal version. See "write_png" for how to extract Image::Similar's internal version.


    my $is = load_image_libpng ($libpng);

This loads an image from the return value of "read_png_file" in Image::PNG::Libpng.

Image::Similar::Image methods

These methods work on the XS object within an Image::Similar, which is called Image::Similar::Image.


    fill_grid ($img);

Calculate the image's signature and store it within $img. All the pixel values should have been set with "set_pixel" before calling this. This method is called automatically by "load_image". "load_signature" overrides it with values from the signature, so this method should only be used when calling "new", filling the pixels by the user, and then making the signature "by hand" rather than via "load_image".


    my $diff = image_diff ($img1, $img2);

This computes the value of "diff" from the signatures within $img1 and $img2.


    $img->set_pixel ($x, $y, $grey);

Set a greyscale pixel within the image. $x and $y need to be integers, and $grey needs to be an integer between 0-255. Typically one would first set the width and height of the image with "new", then get the Image::Similar::Image object from the Image::Similar object, then set its pixels with this method, then compute its signature with "fill_grid".


    my $rows = $img->get_rows ();

Get the greyscale pixels from $img as an array reference $rows containing strings of bytes, one byte per pixel.


    my $sig = $image->signature ();

Return the signature value which is set either by "fill_grid" or directly by "fill_from_sig".


    if ($image->valid_image ()) {
        # do something with image data

This returns a true value only if $image contains valid image data. This is to distinguish between an image which is loaded from a stored signature using "fill_from_sig" and one which is loaded from an actual image.


    my $image = Image::Similar::Image::fill_from_sig ($sig);

Fill $image using signature data.


Search many files for duplicate images

This script makes a list of all files which may be images:

    # Construct a list of all images on the accessible file systems.
    use File::Find;
    use FindBin '$Bin';
    # The list of files under construction.
    my @files;
    main ();
    # This returns a true value if its argument is an image file.
    sub is_image_file
        my ($file) = @_;
        if ($file =~ /\.(jpg|png|gif|jpeg)$/i) {
            return 1;
        return undef;
    sub check_file
        if (is_image_file ($File::Find::name)) {
            push @files, $File::Find::name;
    sub write_files
        open my $out, ">", "$Bin/image-list.txt" or die $!;
        for (@files) {
            print $out "$_\n";
        close $out or die $!;
    sub main
        find ({
            wanted => \& check_file,
        }, "$Bin/..");
        write_files ();

(This example is included as find-all-images.pl in the distribution.)

This script then gets all the signatures of the images and compares them looking for similar images.

    # Make signatures for all the images.
    use utf8;
    use FindBin '$Bin';
    use Image::Similar ':all';
    use Imager;
    main ();
    sub main
        my %sigs;
        open my $in, "<", "$Bin/image-list.txt" or die $!;
        while (<$in>) {
            if (/^\s*$/) {
            my $image = $_; 
            my $imager = Imager->new ();
            my $ok = $imager->read (file => $image); 
            if (! $ok) {
                warn "$image is not ok: ", $imager->errstr ();
            my $is = load_image ($imager);
            my $sig = $is->signature ();
            if (! $sig) {
                die "No signature for $image";
            if ($sigs{$sig}) {
                # Identical match.
                print "$sigs{$sig} looks identical to $image.\n";
            else {
                for my $k (keys %sigs) {
                    my $diff = $is->sig_diff ($k);
                    if ($diff < 0.1) {
                        print "$sigs{$k} looks similar to $image.\n";
                # Don't overwrite $sigs{$sig} if it already has a value.
                $sigs{$sig} = $image;
        close $in or die $!;

(This example is included as make-signatures.pl in the distribution.)


Unimplemented parts of the original algorithm

The following parts of the original algorithm are unimplemented as of this version:


The 5% and 95% image cropping methods described in the paper are not used.

Soft pixels

The soft pixel method is not used.

Histogram of image

There is no balancing of the greyscale of the image using a histogram, it only uses the raw pixel values.


Other CPAN modules


This uses a similar algorithm to Image::Similar, but it requires installing a third-party library called libpuzzle, as well as the gd library.


This uses ImgSeek to find similar pictures in a library. It can load images via Imager, Image::Imlib2, or GD.


An image signature for any kind of image

An image signature for any kind of image by H. Chi Wong, Marshall Bern, and David Goldberg, published in Proceedings: 2002 International Conference on Image Processing, Volume 1, date 22-25 September 2002.


Finding Similar Images

An article from Randal Schwartz from 2003. Contains Perl source code for finding similar images.

Questions about image similarity at Stackoverflow

Contains information about more libraries.


A Perl script for finding duplicate and similar images by Rob Kudla / Jonathan H N Chin.



This is the fallback image loading module used if no other option is installed.

"looks_like_number" in Scalar::Util

This is used to validate the parameters of "new".

"carp" in Carp

This is used to warn the user about input values.


Ben Bullock, <bkb@cpan.org>


This package and associated files are copyright (C) 2016-2017 Ben Bullock.

You can use, copy, modify and redistribute this package and associated files under the Perl Artistic Licence or the GNU General Public Licence.