amol saxena
amol saxena

Reputation: 307

Comparing images in which some parts are variable, but should not matter

I am concerned about to find dissimilarities between images as shown in the samples underneath with the black oval shape.

My problem is that some part of image is also variable, but I do not want to consider this part when finding dissimilarities. To overcome this problem I want to make "transparent" that area which is now marked with red color: the variable part Date/Time and the Date/Time edit field should be excluded from comparison as can be seen from image below:

enter image description here

One way is: I can use a “transparent” color to mark image areas that should not be compared. To do this, I need to modify the baseline copy of an image in the following manner:

How to do automate above manual work through coding? I want to implement above behavior in C code.

Upvotes: 1

Views: 1399

Answers (3)

Weather Vane
Weather Vane

Reputation: 34585

If you are providing a rectangle to colour in, why not just ignore a rectangular area in the first place? Here is some pseudo code

int compareimages (char *im1, char* im2, int wid, int dep, int x0, int y0, int x1, int y1) {
    int x, y;
    for (y=0; y<dep; y++)
        for (x=0; x<wid; x++)
            if (x<x0 || x>x1 || y<y0 || y>y1)     // if outside rectangle
                if im1[y*wid+x] != im2[y*wid+x]   // compare pixels
                    return 0;
    return 1;
}

UPDATE for several areas to be ignored, which may overlap.

Still not hard: just provide an array of rectangles. It is still going to be easier than going to the trouble of painting out areas when you can check them in the first place.

#include <stdio.h>

#define WID 200
#define DEP 600

typedef struct {
    int left;
    int top;
    int right;
    int bot;
} rect;

char image1[WID*DEP];
char image2[WID*DEP];

int inrect (int x, int y, rect r) {
    if (x<r.left || x>r.right || y<r.top || y>r.bot)
        return 0;
    return 1;
}

int compareimages (char *im1, char* im2, int wid, int dep, rect *rarr, int rects) {
    int x, y, n, ignore;
    for (y=0; y<dep; y++)
        for (x=0; x<wid; x++) {
            ignore = 0;
            for (n=0; n<rects; n++)
                ignore |= inrect (x, y, rarr[n]);
            if (!ignore)
                if (im1[y*wid+x] != im2[y*wid+x])   // compare pixels
                    return 0;
        }
    return 1;
}

int main(void) {
    rect rectarr[2] = { {10, 10, 50, 50}, { 40, 40, 90, 90 }};
    // ... load images ...

    // put pixel in one of the rectangles
    image1[20*WID+20] = 1;
    if (compareimages (image1, image2, WID, DEP, rectarr, 2))
        printf ("Same\n");
    else
        printf ("Different\n");

    // put pixel outside any rectangles
    image1[0] = 1;
    if (compareimages (image1, image2, WID, DEP, rectarr, 2))
        printf ("Same\n");
    else
        printf ("Different\n");
    return 0;
}

Program output:

Same
Different

EDIT added another version of the function, comparing 4 pixel components.

int compareimages (char *im1, char* im2, int wid, int dep, rect *rarr, int rects) {
    int x, y, n, ignore;
    for (y=0; y<dep; y++)
        for (x=0; x<wid; x++) {
            ignore = 0;
            for (n=0; n<rects; n++)
                ignore |= inrect (x, y, rarr[n]);
            if (!ignore) {
                if (im1[y*wid*4+x] != im2[y*wid*4+x])   // compare pixels
                    return 0;
                if (im1[y*wid*4+x+1] != im2[y*wid*4+x+1])
                    return 0;
                if (im1[y*wid*4+x+2] != im2[y*wid*4+x+2])
                    return 0;
                if (im1[y*wid*4+x+3] != im2[y*wid*4+x+3])
                    return 0;
            }
        }
    return 1;
}

Upvotes: 3

Kurt Pfeifle
Kurt Pfeifle

Reputation: 90213

My suggestion is:

  1. First implement the solution as a command line with ImageMagick.
  2. Once this works, port this command line over to ImageMagick's C API.

Here are a few answers about comparing images using ImageMagick compare. They may not apply to your precise question, but thy provide enough theoretical background with practical examples to get you started:

If I understand your question correctly, you do want to compare only some parts of two images, any you want to exclude other parts from the comparison where you already know there are (uninteresting) differences. Right?

Taking these two images as an example:

compare.png

reference.png

BTW, these two images have been born as PDFs, and I could apply the procedure described below to PDF pages too (without a need to convert them to image files first).

You do not necessarily need a transparent mask -- you can use a black (or any color) one too.

Create a green mask of 280x20 pixels size:

convert -size 280x20 xc:green greenmask-280x20.png

Now use composite to place the mask on top of each of the images:

convert                               \
   https://i.sstatic.net/Q1pyC.png \
   greenmask-280x20.png               \
    -geometry +32+35                  \
    -compose over                     \
    -composite                        \
   c.png


convert                               \
   https://i.sstatic.net/JVije.png \
   greenmask-280x20.png               \
    -geometry +32+35                  \
    -compose over                     \
    -composite                        \
   r.png

The -geometry +32+35 parameter maybe requires some explanation: it tells ImageMagick to place the top left corner of the greenmask 32 pixels to the right and 35 pixels to the bottom of the top left corner of the original image.

The resulting images are here:

c.png

r.png

An answer that discusses the different compose methods known to ImageMagick is here:

Now your images are ready for either statistical or visual comparison, provided by ImageMagick's compare command:

compare c.png r.png -compose src delta.png

The delta.png shows all pixels in red which are different, the rest is white:

delta.png

Or, using the most simple compare command, where the reference image serves as a pale background with red delta pixels on top:

compare c.png r.png  delta2.png

delta2.png

Upvotes: 4

user3629249
user3629249

Reputation: 16540

Normally, such an 'image' as is used in the example is NOT a single image.

Rather it is a large number of images overlaying each other.

Most likely, the 'image' is made of:

the background
the outside border (which has 4 parts)
the upper left icon
the upper border clickable button( three of them)

the text field: Date/Time:
the input field: (for the date/time)

the text field: 'Table:'
the input multi line field/ with initial text 'Customers'

etc etc etc

I.E. that is not a single image but rather many images
that overlay each other

a single image would be something like a .bmp or .tif or .jpg file

Upvotes: 0

Related Questions