Registriert seit: 26. Mai 2005
Ort: Knw.-Remsfeld
119 Beiträge
Delphi XE2 Professional
|
Bildvergleich mit ZeroMeanNormalizedCross-Correlation (ZNCC)
13. Dez 2009, 13:22
Auf der Suche nach einer Möglichkeit, mehrere Bilder miteinander zu vergleichen bin ich auf die Kreuz-Korrelation gestoßen. Mit dem folgenden Algorithmus kann man zwei Canvas beliebiger Größe miteinander vergleichen und bekommt das Ergebnis als Prozentwert der Übereinstimmung zurück. 100% bedeutet demnach perfekte Übereinstimmung.
Alternativ kann der schwächere SSD Algorithmus verwendet werden. Link: SSD
Delphi-Quellcode:
type
PRGBTripleArray = ^TRGBTripleArray;
TRGBTripleArray = array [0..31] of TRGBTriple;
Delphi-Quellcode:
function RGB2TColor( const R, G, B: Byte): Integer;
begin
// convert hexa-decimal values to RGB
Result := R + G shl 8 + B shl 16;
end;
Delphi-Quellcode:
procedure TColor2RGB( const Color: TColor; var R, G, B: Byte);
begin
// convert hexa-decimal values to RGB
R := Color and $FF;
G := (Color shr 8) and $FF;
B := (Color shr 16) and $FF;
end;
Delphi-Quellcode:
// ZeroMeanNormalizedCross-Correlation (ZNCC) (wird MAXIMAL bei guter Übereinstimmung)
function TForm1.ZNCC(Bild1, Bild2: TBitmap):Single;
var
x, y:integer;
P1,P2:array[0..31] of PRGBTripleArray;
a, b, zaehler, nenner1, nenner2, nenner, summe1, summe2, mean1, mean2:single;
ZNCCvalue:Extended;
begin
// ZeroMeanNormalizedCross-Correlation (ZNCC) (wird MAXIMAL bei guter Übereinstimmung)
zaehler:=0.0;
nenner1:=0.0;
nenner2:=0.0;
summe1:=0.0;
summe2:=0.0;
// Bildformat auf 24bit setzen (also ohne Alpha-Kanal)
Bild1.PixelFormat := pf24bit;
Bild2.PixelFormat := pf24bit;
// Summen bilden
for y:=0 to Bild1.Height-1 do
begin
P1[y]:=Bild1.ScanLine[y];
P2[y]:=Bild2.ScanLine[y];
for x:=0 to Bild1.Width-1 do
begin
summe1:=summe1+RGB2TColor(P1[y][x].rgbtRed, P1[y][x].rgbtGreen, P1[y][x].rgbtBlue);
summe2:=summe2+RGB2TColor(P2[y][x].rgbtRed, P2[y][x].rgbtGreen, P2[y][x].rgbtBlue);
end;
end;
mean1:=(1/power((Bild1.Width-1)+(Bild1.Height-1)+1,2))*summe1;
mean2:=(1/power((Bild1.Width-1)+(Bild1.Height-1)+1,2))*summe2;
for x:=0 to Bild1.Width-1 do
begin
for y:=0 to Bild1.Height-1 do
begin
a:=RGB2TColor(P1[y][x].rgbtRed, P1[y][x].rgbtGreen, P1[y][x].rgbtBlue)-mean1;
b:=RGB2TColor(P2[y][x].rgbtRed, P2[y][x].rgbtGreen, P2[y][x].rgbtBlue)-mean2;
zaehler:=zaehler+(a*b);
nenner1:=nenner1+power(a, 2);
nenner2:=nenner2+power(b, 2);
end;
end;
nenner:=sqrt(nenner1*nenner2);
if nenner>0 then
ZNCCvalue:=zaehler/nenner
else
ZNCCvalue:=0.0;
result:=ZNCCvalue*100;
end;
Der Code hat bei mir gut funktioniert. Anbei auch nochmal der Original-Algorithmus.
viel Erfolg,
Christian
Edit: Verwendung von .Pixels auf .ScanLine geändert. Durchlaufgeschwindigkeit bei Vergleich von 500 Dateien mit 32x32px <120ms auf einem Core2Duo mit 2,4Ghz
Christian Nöding
|
|
Zitat
|