![]() |
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
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
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 ![]() 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
![]()
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 10:00 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz