2

There is a directory with jpg files and one jpg file that should be compared with the files in the directory and in this way find 2 graphically identical files. It's about the simplest way. Maybe it is possible to compare the differences in R, G, B (variability), and not the R, G, B values themselves, since they may differ slightly with different degrees of jpeg compression.

Spektre
  • 49,595
  • 11
  • 110
  • 380
Inum
  • 53
  • 1
  • 7

1 Answers1

0

for comparing 2 images:

  1. Load the two jpgs into memory located bitmaps

    see opening image file on c++ , PNG , JPEG for simple C++ Builder example just port to pascal the class names and usage should be the same in Delphi.

  2. Compute abs differences

    use Graphics::TBitmap::ScanLine[y] for fast pixel access, union or BYTE pointed for individual color channel access and compute abs average difference and max abs difference individually for each color channel.

    for more info see TBitmap and ScanLine[y] usage and color channel access example

    However as SilverWarior pointed out using RGB space is nto good for this so compare in luminance (just convert the RGB to luminance)

  3. Threshold the result

    simply if any of max and avg differences is bigger than some threshold the two images are not identical.

To create a list of files either use winapi FindFirst,FindNext,FindClose to obtain the directory list or use the file list from win3.11 VCL components set its directory and obtain the files in form of list...

And then just auto compare the images ...

Here small C++ builder example for comparing 2 images:

//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#include <jpeg.hpp>
#pragma hdrstop
#include "win_main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TMain *Main;
Graphics::TBitmap *bmp0,*bmp1;
//---------------------------------------------------------------------------
int picture_load(Graphics::TBitmap *bmp,AnsiString name)
    {
    if (bmp==NULL) return 0;
    if (!FileExists(name)) return 0;
    bmp->HandleType=bmDIB;
    bmp->PixelFormat=pf32bit;
    AnsiString ext=ExtractFileExt(name).LowerCase();
    for(;;)
        {
        if (ext==".bmp")
            {
            bmp->LoadFromFile(name);
            break;
            }
        if (ext==".jpg")
            {
            TJPEGImage *jpg=new TJPEGImage;
            if (jpg==NULL) return 0;
            jpg->LoadFromFile(name);
            bmp->Assign(jpg);
            delete jpg;
            break;
            }
        return 0;
        }
    bmp->HandleType=bmDIB;
    bmp->PixelFormat=pf32bit;
    return 1;
    }
//---------------------------------------------------------------------------
int picture_compare(Graphics::TBitmap *bmp0,Graphics::TBitmap *bmp1)
    {
    if ((bmp0==NULL)&&(bmp1==NULL)) return 1;
    if (bmp0==NULL) return 0;
    if (bmp1==NULL) return 0;
    if (bmp0->Width !=bmp1->Width ) return 0;
    if (bmp0->Height!=bmp1->Height) return 0;
    int x,y,a;
    double c0,c1,dc,de,maxdif=0.0,avgdif=0.0;
    BYTE *p0,*p1;
    for (y=0;y<bmp0->Height;y++)
        {
        p0=(BYTE*)bmp0->ScanLine[y];
        p1=(BYTE*)bmp1->ScanLine[y];
        for (a=0,x=0;x<bmp0->Width;x++)
            {
            c0 =p0[a]; c1 =p1[a]; a++; c0*=0.0722; c1*=0.0722;  // B
            c0+=p0[a]; c1+=p1[a]; a++; c0*=0.7152; c1*=0.7152;  // G
            c0+=p0[a]; c1+=p1[a]; a++; c0*=0.2126; c1*=0.2126;  // R
                                  a++;                          // A
            dc=fabs(c0-c1);if (maxdif<dc) maxdif=dc; avgdif+=dc;
            }
        }
    avgdif/=bmp0->Width;
    avgdif/=bmp0->Height;
    if (avgdif>10) return 0;
    if (maxdif>50) return 0;
    return 1;
    }
//---------------------------------------------------------------------------
__fastcall TMain::TMain(TComponent* Owner) : TForm(Owner)
    {
    bmp0=new Graphics::TBitmap;
    bmp1=new Graphics::TBitmap;

    picture_load(bmp0,"in0.jpg");
    picture_load(bmp1,"in1.jpg");
    Caption=picture_compare(bmp0,bmp1);

    int xs,ys;
    xs=bmp0->Width+bmp1->Width;
    ys=bmp0->Height;
    if (ys<bmp1->Height) ys=bmp1->Height;
    ClientWidth=xs;
    ClientHeight=ys;
    }
//---------------------------------------------------------------------------
void __fastcall TMain::FormDestroy(TObject *Sender)
    {
    if (bmp0) delete bmp0; bmp0=NULL;
    if (bmp1) delete bmp1; bmp1=NULL;
    }
//---------------------------------------------------------------------------
void __fastcall TMain::FormPaint(TObject *Sender)
    {
    Canvas->Draw(0,0,bmp0);
    Canvas->Draw(bmp0->Width,0,bmp1);
    }
//---------------------------------------------------------------------------

You should play with the thresholds (I chose form very small input sample) to meet your needs and also beware this is comparing as grayscale images so you should add also some color comparison too (integrate some areas into avg color and compare that)

The function picture_compare returns true for "identical" images... beware it expects pf32bit pixelformat for both images !!! different format will change the pixel access and might also change the RGB order which will lead to wrong weights during conversion to luminance/grayscale. The pixelformat is set during picture_load so do not forget to set it if you use different loading method...

Also for comparing the color you might do a histogram for each color channel separately and compare that ...

I used double to prevent (32 bit) integer overflow of avgdif but take in mind for high resolution even double is not safe.

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • 2
    Comparing color values between two compressed JPEG images is actually the worst approach you could take. Why? If you go and read of how JPEG compression work you will learn that JPEG compression does most of its compression by compressing color space which is also called chrominance but keeps light information also called luminance pretty much intact. Therefore the best approach for comparing of two JPEG images would be to compare luminance data from both images. – SilverWarior Jan 28 '23 at 11:13
  • @SilverWarior yes you're right just tested it and the result is not good for naive RGB difference. Using weighted grayscale comparison looks OK – Spektre Jan 29 '23 at 07:53