C-Funktion mit Pointern in Delphi nachbilden
Hi!
Die folgende C-Funktion möchte ich äquivalent in Delphi abbilden:
Code:
CvMat ist eine Matrix-Struktur (siehe unten), dessen Elemente mit der Funktion einzeln belegt werden sollen. i ist die Zeile, j die Spalte und val der einzutragende Wert.
CV_INLINE void cvmSet( CvMat* mat, int i, int j, double val )
{ ((double*)(mat->data.ptr + (size_t)mat->step*i))[j] = (double)val; } Hier mein Versuch:
Code:
Die CvMat-Struktur habe ich durch die Hilfe von NicoDE in diesem Topic ja schon umgesetzt bekommen. Vielen Dank nochmal dafür!
procedure cvmSet(var mat: P_CvMat; i: Integer; j: Integer; val: Double);
var PTmpDouble: PDouble; begin PTmpDouble := PDouble(PChar(mat.data.ptr) + mat.step * i); Inc(PTmpDouble, j); PTmpDouble^ := val; end;
Code:
Das Step steht für die Breite einer Martixzeile in Bytes. ptr zeigt auf den Inhalt.
type
P_CvMat = ^CvMat; CvMat = record type_ : Integer; step : Integer; (* for internal use only *) refcount : PInteger; data : record case Integer of 0: (ptr : PByte); 1: (s : PSmallInt); 2: (i : PInteger); 3: (fl : PSingle); 4: (db : PDouble) end; case Integer of 0: (rows : Integer); 1: (height: Integer; case Integer of 0: (cols : Integer); 1: (width : Integer)) end; Mein Problem besteht nun darin, dass ich die Elemente einer 3x3-Matrix mit Werten belege und dann wieder auslese, wobei sich die Werte komplett verändert haben. Irgendeine Idee? Gruß, oXmoX |
Re: C-Funktion mit Pointern in Delphi nachbilden
Spontanübersetzung (ohne Delphi, Syntaxfehler möglich)
Delphi-Quellcode:
mat->data.ptr ist ein Zeiger auf Elemente der Größe 1, dadurch wird für die Addition Faktor 1 verwendet (also ignoriert :)).
procedure cvmSet(mat: P_CvMat; i, j: Integer; val: Double); {inline;}
type PDoubleArray = ^TDoubleArray; TDoubleArray = array [Word] of Double; begin PDoubleArray(Cardinal(mat.data.ptr) + Cardinal(mat.step) * i)[j] := val; end; -> in Delphi können Pointer so nicht addiert werden, deswegen der Cast auf Cardinal (size_t)mat->step*i step wird auf einen vorzeichenlosen Typen gecastet (hart, old-style) und mit i multipliziert (warum i nicht gecastet wird weiß nicht ;)) -> das gleiche auch in Delphi Language ((double* )(...))[j] das ganze wird auf einen Zeiger auf Doubles gecastet und mit dem Array-Operator auf dem j-te Element zugegriffen -> in Delphi kann der Array-Operator so nicht verwendet werden (es gibt keinen ;)); deswegen wird ein Hilfstyp definiert und verwendet Gruß Nico ps: kommt also auf etwa das gleiche raus wie bei dir (bsi auf 'var' und die Zwischenschritte) - bleibt die Frage nach dem Problem... |
Re: C-Funktion mit Pointern in Delphi nachbilden
Hmmm hab deinen Code grad getestet und er liefert die selben Zahlen wie meiner ...auch wenn's bei dir natürlich geschickter aussieht :wink:
|
Re: C-Funktion mit Pointern in Delphi nachbilden
Tcha, die Struktur funktioniert aber soweit (oder fehlen noch Fixes für die Alignments der Original-C-Struktur...)?
|
Re: C-Funktion mit Pointern in Delphi nachbilden
Zitat:
Ich bin bisher noch nicht dazu gekommen, deinen record zu testen. Das wollte ich eigentlich hiermit tun. |
Re: C-Funktion mit Pointern in Delphi nachbilden
Zitat:
Delphi-Quellcode:
TFoo = record
Bar: Byte; //___: Byte; <- Alignment Alc: Word; end;
Delphi-Quellcode:
TFoo = packed record
Bar: Byte; Alc: Word; end; Zitat:
Von hier aus schwer zu sagen, ob ein logischer Fehler vorliegt, oder Strukturen nicht korrekt deklariert sind -> debuggen könnte helfen (je nach Möglichkeit) |
Re: C-Funktion mit Pointern in Delphi nachbilden
Liste der Anhänge anzeigen (Anzahl: 1)
Ok, ich komme nicht weiter :(
Darum hier nochmal mein Code in größerer Ausführlichkeit:
Code:
Die in der Unit verwendete dll gibt es im Anhang. Sie ist Teil der Open-Source-Bibliothek OpenCV (Beta 4). Sollte das mit der dll alleine nicht funktionieren (aufgrund fehlender Abhängigkeiten etc.), dann lässt sich wohl eine komplette Installation der OpenCV Bibliothek nicht vermeiden (kommt aber mit einer einfachen Setup-Datei). Sollte jemand diesen Aufwand tatsächlich treiben: DANKE dafür.
unit CxCore;
interface const CV_32FC1 = 4; CV_64FC1 = 5; CV_MAT_TYPE_MASK = 31; type PDoubleArray = ^TDoubleArray; TDoubleArray = array [Word] of Double; PSingleArray = ^TSingleArray; TSingleArray = array [Word] of Single; P_CvMat = ^CvMat; CvMat = record type_: Integer; step: Integer; //for internal use only refcount: PInteger; data: record case Integer of 0: (ptr: PByte); 1: (s: PSmallInt); 2: (i: PInteger); 3: (fl: PSingle); 4: (db: PDouble) end; case Integer of 0: (rows: Integer); 1: (height: Integer; case Integer of 0: (cols: Integer); 1: (width: Integer)) end; function cvCreateMat(rows: Integer; cols: Integer; type_: Integer): P_CvMat; cdecl; function cvmGet(const mat: P_CvMat; row: Integer; col: Integer): Double; cdecl; procedure cvmSet(mat: P_CvMat; row: Integer; col: Integer; value: Double); cdecl; function CV_MAT_TYPE(flags: Cardinal): Cardinal; implementation function cvCreateMat(rows: Integer; cols: Integer; type_: Integer): P_CvMat; external 'cxcore096.dll'; function cvmGet(const mat: P_CvMat; row: Integer; col: Integer): Double; // external 'cxcore096.dll'; var type_: Integer; begin type_ := CV_MAT_TYPE(mat.type_); assert((row < mat.rows) and (col < mat.cols)); if(type_ = CV_32FC1) then Result := PSingleArray(Cardinal(mat.data.ptr) + Cardinal(mat.step) * row)[col] else begin assert(type_ = CV_64FC1); Result := PDoubleArray(Cardinal(mat.data.ptr) + Cardinal(mat.step) * row)[col]; end; end; procedure cvmSet(mat: P_CvMat; row: Integer; col: Integer; value: Double); // external 'cxcore096.dll'; var type_: Integer; begin type_ := CV_MAT_TYPE(mat.type_); assert((row < mat.rows) and (col < mat.cols)); if(type_ = CV_32FC1) then PSingleArray(Cardinal(mat.data.ptr) + Cardinal(mat.step) * row)[col] := value else begin assert(type_ = CV_64FC1); PDoubleArray(Cardinal(mat.data.ptr) + Cardinal(mat.step) * row)[col] := value; end; end; // #define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK) function CV_MAT_TYPE(flags: Cardinal): Cardinal; begin Result := flags and CV_MAT_TYPE_MASK; end; end. Die Werte für die Konstanten und die Getter und Setter-Funktion habe ich übrigens aus diesem C-Header-File übernommen. Jetzt die Test-Unit:
Code:
Bei mir funktioniert der Test nur mit den 32-Bit-Matrizen, nicht aber mit den 64-Bit-Matrizen ...kommen dann beim Auslesen falsche Werte heraus.
unit TestMatrix;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, CxCore; type TForm1 = class(TForm) ButtonTest64: TButton; ButtonTest32: TButton; procedure ButtonTest64Click(Sender: TObject); procedure ButtonTest32Click(Sender: TObject); private procedure TestMat(Mat: P_CvMat); end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.ButtonTest64Click(Sender: TObject); var Mat: P_CvMat; begin Mat := cvCreateMat(3, 3, CV_64FC1); Self.TestMat(Mat); end; procedure TForm1.ButtonTest32Click(Sender: TObject); var Mat: P_CvMat; begin Mat := cvCreateMat(3, 3, CV_32FC1); Self.TestMat(Mat); end; procedure TForm1.TestMat(Mat: P_CvMat); var Row, Col: Integer; Val: Integer; begin // Matrixwerte belegen Val := 0; for Row := 0 to 2 do for Col := 0 to 2 do begin cvmSet(Mat, Row, Col, Val); Inc(Val); end; // Matrixwerte auslesen for Row := 0 to 2 do for Col := 0 to 2 do begin ShowMessage(FloatToStr(cvmGet(Mat, Row, Col))); end; end; end. Also ...wo ist der Fehler? |
Re: C-Funktion mit Pointern in Delphi nachbilden
Alles klar! Hab meinen Fehler grad gefunden. Das angegebene C-Header-File ist offensichtlich veraltet, so dass die Konstanten nicht mehr stimmen:
Code:
ist jetzt
const
CV_32FC1 = 4; CV_64FC1 = 5;
Code:
...und schon funktioniert alles reibungslos.
const
CV_32FC1 = 5; CV_64FC1 = 6; Der variable Record von NicoDE scheint also auch in Ordnung zu sein. :-D |
Re: C-Funktion mit Pointern in Delphi nachbilden
Soviel zum Thema "Fehler die keiner braucht" :D
Viel Erfolg mit der weiteren Übersetzung... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:17 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz