Codeoptimierung
-
Hallo,
ich möchte aus einer LabView Umgebung in ein C Programm ein 2D Array einlesen, daraus Berechnungen anstellen und die Ergebnisse anschließend in ein neues 2D Array schreiben, das dann wieder an LabView übergeben werden soll.
Leider scheint es jedoch mit diesen 2D Arrays Probleme zu geben, denn so eifnach kann man wohl 2D Arrays dort nicht verwenden was wohl mit der Speicherallokation zusammenhängt, ich muß wohl versuchen daher möglichst speichergrößenunabhängige Zugriffe zu ermöglichen -so weit meine Theorie.Nun wurde mir an anderer Stelle gesagt, dass die lösung des Problems vielleicht mit Selbst inkrementierenden Zeigern (also Zeiger++) möglich wäre, leider habe ich keine Ahnung wie ich diese bei einem 2D Array und speziell in meinem Programm anwenden kann und finde dazu auch keine Hilfe, Beispiele, Syntax.
Ich habe zwar einen Anhaltspunkt erhalten, begreife aber nicht wie es damit möglich sein soll auf speziell einen Punkt des Arrays zuzugreifen bzw wie der 2D Zugriff erfolgt da mit in dieser Lösung es so scheinen mag, dass doch nur eine Dimension angesteuert wird.
Was ich jedoch gefunden habe ist, dass neben Zeiger++ auch Zeiger+=4 mnöglich istw enn man eben beispielsweise 4 Elemente weiter wandern möchte, jedoch stellt sich da nun die Frage wie ich das in einem 2D Array umsetzen soll, denn es mag ja einmal vorkommen,dass ich in xRichtung 4, in yRichtung aber nur 2 Elemente weiter wandern möchte.
Ich hoffe mir kann da jemand weiterhelfen, gegebenenfalls die Syntax für diesen 2D zugriff nennen, mir diesen Anhaltspunkt Code erklären und letztlich mir helfen das große Problem zu lösen.
Im folgenden poste ich einmal meinen code und diesen Anhaltspunkt.Brows,Bcols geben die Größe des neuen 2D Arrays "Kontrast" an.
Lcols und Lrows geben an in wie große, ich nenne es mal, Teilarrays das ursprüngliche 2D Array "Bild" zerlegt werden soll, was für die Berechnung wichtig ist aber auch für die Größe des neuen Ausgangsarrays. test ist einfach nur eine Variable die ich zum testen einfacher berechnung ohne Arrays verwendete.Der C-Code lautet:
/*Programm zur Kontrastberechnung und Bildarrayzerlegung Brows=Reihenanzahl des neuen Bildarrays (Kontrastbild) von LabView errechnet und übergeben Bcols=Kolumnenanzahl des neuen Bildarrays (Kontrastbild) von LabView errechnet und übergeben Lrows=Reihenanzahl eines Teilarrays von LabView übergeben Lcols=Kolumnenanzahl eines Teilarrays von Labview übergeben Bild=Das Bildarray des ursprünglichen Bildes welches von LabView übergeben wurde Kontrast=Errechnetes Kontrastbild welches an LabView übergeben werden soll */ /* Call Library source file */ #include "extcode.h" #include <stdio.h> #include <stdlib.h> __declspec(dllexport) long KontrastC(long *Brows, long *Bcols, long *Lcols, long *Lrows, unsigned char *Bild, double *Kontrast,long *test); //Hauptprogramm Kontrastberechnung double* callocvector(int); double* freevector(double*); double** callocmatrix(int, int); double** freematrix(double**,int); long KontrastC(long *Brows, long *Bcols, long *Lcols, long *Lrows, unsigned char *Bild, double *Kontrast,long *test) { /* *test=*Lrows * *Lcols; Kontrast[1][1]=777; return 0; } */ int i=0,j=0,m=0,n=0; double** Mittelwert = callocmatrix(*Brows,*Bcols); //double** Kontrast = callocmatrix(*Brows,*Bcols); // Mittelwertsberechnung for (m=0;m<=*Brows;i++) { for(n=0;n<=*Bcols;n++) { for (i=0;i<=*Lrows;i++) { for(j=0;j<=*Lcols;j++) { //Mittelwert[m][n]=Mittelwert[m][n]+Bild[i+(m * *Lrows)][j+(n * *Lcols)]; //Mittelwert[m][n]=Mittelwert[m][n]+ *( *(Bild+i+(m * *Lrows))+j+(n * *Lcols) ); } } Mittelwert[m][n]=( 1.0/(*Lrows * *Lcols) )* Mittelwert[m][n]; } } //Kontrastberechnung for (m=0;m<=*Brows;i++) { for(n=0;n<=*Bcols;n++) { for (i=0;i<=*Lrows;i++) { for(j=0;j<=*Lcols;j++) { //Kontrast[m][n]=Kontrast[m][n]+( (Bild[i+(m * *Lrows)][j+(n * *Lcols)]-Mittelwert[m][n]) // *(Bild[i+(m * *Lrows)][j+(n * *Lcols)]-Mittelwert[m][n]) ); *(*(Kontrast+m)+n)=*(*(Kontrast+m)+n) + ( *( *(Bild+i+(m * *Lrows))+j+(n * *Lcols) )-Mittelwert[m][n]) *( *(*(Bild+i+(m * *Lrows))+j+(n * *Lcols) )-Mittelwert[m][n] ); } } //Kontrast[m][n]=( 1.0/(*Lrows * *Lcols) )* Kontrast[m][n]; *(*(Kontrast+m)+n)=( 1.0/(*Lrows * *Lcols) )* *(*(Kontrast+m)+n); } } //Freigeben des reservierten Speichers //Kontrast = freematrix(Kontrast,Lrows); Mittelwert = freematrix(Mittelwert,*Lrows); return 0; } //Unterprogramme zur dynamischen Speicherallokation /*-------------------------------------------- "callocvector" allocates the memory for a dynamic vector of length n and initializes it --------------------------------------------*/ double* callocvector(int n) { int j; double* vector = calloc(n,sizeof(double)); for (j=0; j<n; j++) { vector[j] = 0; } return(vector); } /*-------------------------------------------- "freevector" dis-allocates the memory of a dynamic vector of arbitrary length and sets the pointer to NULL --------------------------------------------*/ double* freevector(double* vector) { free(vector); return(NULL); } /*-------------------------------------------- "callocmatrix" allocates the memory for a dynamic matrix of size (m \times n) and initializes it --------------------------------------------*/ double** callocmatrix(int m, int n) { int i; double** matrix = calloc(m,sizeof(double)); for (i=0; i<m; i++) { matrix[i] = callocvector(n); } return(matrix); } /*-------------------------------------------- "freematrix" dis-allocates the memory of a dynamic matrix of size (m \times n) and sets the pointer to NULL --------------------------------------------*/ double** freematrix(double** matrix,int m) { int i; for (i=0; i<m; i++) { free(matrix[i]); free(matrix); } return(NULL); }
Und der Anhaltspunkt
for (m=0;m<=*Brows;i++) { MyBild2 = Bild + m * ????; for(n=0;n<=*Bcols;n++) { MyBild1 = MyBild2 + n * ????; for (i=0;i<=*Lrows;i++) { MyBild = MyBild1 + i * ????; for(j=0;j<=*Lcols;j++) { //Mittelwert[m][n]=Mittelwert[m][n]+Bild[i+(m * *Lrows)][j+(n * *Lcols)]; //Mittelwert[m][n]=Mittelwert[m][n]+ *( *(Bild+i+(m * *Lrows))+j+(n * *Lcols) ); Mittelwert[m][n]=Mittelwert[m][n]+ *(MyBild++); } } Mittelwert[m][n]=( 1.0/(*Lrows * *Lcols) )* Mittelwert[m][n]; } }
-
Hallo Gantenbein,
ich habe mir deinen Code noch nicht komplett angesehen, aber schon mal
zwei Fehler gefunden.Zum einen machst du beim Löschen der Matrix einen Fehler:
double** freematrix(double** matrix,int m) { int i; for (i=0; i<m; i++) { free(matrix[i]); free(matrix); // <-- dies muss außerhalb der Schleife! } return(NULL); }
und zum anderen bei der Berechnung:
for (m=0;m<=*Brows;i++) // <-- das Array geht von 0 bis Brow-1, also ist <= falsch. richtig: m<*Brows { for(n=0;n<=*Bcols;n++) // <-- s.o. { for (i=0;i<=*Lrows;i++) // <-- s.o. { for(j=0;j<=*Lcols;j++) // <-- s.o. ...
und noch einen Fehler habe:
long KontrastC(long *Brows, long *Bcols, long *Lcols, long *Lrows, unsigned char *Bild, double *Kontrast,long *test)
Hier ist Bild als ein unsigned char *, also einem Zeiger auf einem char,
welches auch ein char-Array sein kann. Du verwendest Bild aber als ein
zweidimensionales Array, welches du dann auch übergeben müßtest.
Ich nehme mal an, dass ähnliche Fehler mit Kontrast und eventuell test
auch bestehen.Ok, nach längerem Überlegen, habe ich auch verstanden, was in deinem
Anhaltspunkt gemeint sein könnte.
Hier mal etwas klarer:unsigned char **bild; unsigned char *mybild; for (i=0; i<*Brow; ++i) { mybild = bild + i; // <-- Tip: Zeigerarithmetik! for (j=0; j<*Bcol; ++j) { mybild[j] ... // <-- an dieser Stelle wird bild[i][j] verwendet! } }
Ich hoffe mal, ich konnte dir weiterhelfen.
Gruß mcr
-
Hallo,
bei einigen Fehlern hast du vollkommen recht, gerade dieses <= schleicht sich bei mir immer wieder ein, ich wüßte nur zu gerne wo ich mir das einmal angeeignet habe.Nur bei dieser Übergabe der zweidimensionalen Arrays ist im Grunde genau dies das Problem, das es dort als eindimensionales Array erscheint kommt durch die übergabe von LabView und ich muß zugeben, dass ich das selbst sehr seltsam finde.
Nun habe ich jedoch einen Beispielcode dazu gefunden und zwar:#include "extcode.h" #ifdef _cplusplus estern "C" { #endif /* LabVIEW created typedef */ typedef struct { int32 dimSizes[2]; double elt[1]; } TD1; typedef TD1 **TD1Hdl; _declspec(dllexport) void ARRAY2DHandle(TD1Hdl array); _declspec(dllexport) void ARRAY2DHandle(TD1Hdl array) { int i, j; /* dimSizes[0] is the number of rows */ int numrow = (*array)->dimSizes[0]; /* dimSizes[1] is the number of columns */ int numcol = (*array)->dimSizes[1]; for(i = 0; i < numrow; i++) { for(j = 0; j < numcol; j++) { (*array)->elt[(i * numcol) + j] = (*array)->elt[(i * numcol) + j] * (*array)->elt[(i * numcol) + j]; } } }
Dennoch ist mir ein Rätsel wie das funktionieren woll, wir tatsächlich ein eindimensionales Array übergeben, das in dieser Definition einer neuen Struktur, die irgendwie durch dieses extern C in C einbindbar wird, daraus ein Zweidimensionales gemacht?
Und dann dieses " (*array)->elt[(i * numcol) + j] " das sieht ja doch wieder eher danach aus, dass es ein zugriff auf etwas eindimensionales wäre aber das wäre ja unsinnig also wie erkennt der Compiler, dass das in der klammer eine Dimension sein soll und das +j die andere?
Also dieses Beispiel ist mir nun wirklich auch ganz und gar nicht klar.
-
Also die Idee dahinter ist, dass man ein Bild hat, dieses Bild wird in Teilarrays zerlegt, deren Größe von Lcols bzw. Lrows angegeben wird.
In jedem dieser Teilarrays wird zuallererstz der Mittelwert berechnet, anschließend die Standardabweichung. Wenn man nun die Standardabweichung durch den mittelwert dividiert erhält man daraus den Kontrast. diese Zeile fehlte übrigens bisher noch, wie ich gerade sah, daher habe ich das Programm nochmals mitgeschickt.
Diese Werte werden dann also in einem neuen Array gespeichert, dass eben entsprechend der Teilarraygrößen kleiner ist, floor(numrow/ *Lrows).
Die jeweils vier Schleifen dienen also nun dazu, das gesamte Bils zu durchwandern, was die äußeren Beiden besorgen, die inneren beiden durchlaufen dann eben diese kleinen Teilarrays.
Wenn wir annehmen, dass Lcols 2 wäre und die Indexformel j+(n*Lcols) haben wäre das also j+ (n*2)
n=0 0+0 =0
1+0=1
n=1 0+2=2
1+2=3
usw
Also ich meine, dass das so funktionieren müßte.Ich habe nun übrigens mal die funktionszeile, so geändert, dass gar keine Sterne mehr vorhanden sind.
long KontrastC(long *Brows, long *Bcols, long *Lcols, long *Lrows, TD1Hdl Bild, TD1Hdl Kontrast,long *test)Tatsächlich scheint somit auch alles zu laufen. Nun zeigt sich allerdings ein viel größeres Problem. Urspünglich sollte das aus LV ausgelagert werden um diese Kontrastberechnung zu beschleunigen. Nun da ich die Berechnung in LV und die in C parallel laufen habe ist es jedoch so, dass das ganze Programm wahnsinnig verlangsamt wurde, das geht so weit, dass LV schon gar keine Rückmeldung mehr gibt.
Das ist nun doch sehr frustrierend wie ich sagen muß, ist mein Code nun wirklich so viel schlechter als das was ich in LV machte, dabei hörte ich immer, dass es doch erhebliche Geschwindigkeitsgewinne bringen sollte.
Läuft das nun nur scheinbar und es sind immernoch große Fehler enthalten, ist der code nur unglaublich schlecht aber die LV eigenen DLLs werden es doch kaum anders lösen, wie ist das nun zu erklären udn wie bekomme ich es damit nun wirklich verschnellert und nicht verlangsamt?/*Programm zur Kontrastberechnung und Bildarrayzerlegung Brows=Reihenanzahl des neuen Bildarrays (Kontrastbild) von LabView errechnet und übergeben Bcols=Kolumnenanzahl des neuen Bildarrays (Kontrastbild) von LabView errechnet und übergeben Lrows=Reihenanzahl eines Teilarrays von LabView übergeben Lcols=Kolumnenanzahl eines Teilarrays von Labview übergeben Bild=Das Bildarray des ursprünglichen Bildes welches von LabView übergeben wurde Kontrast=Errechnetes Kontrastbild welches an LabView übergeben werden soll */ /* Call Library source file */ #include "extcode.h" #include <stdio.h> #include <stdlib.h> #include <math.h> #ifdef __cplusplus extern "C" { #endif /* LabVIEW created typedef */ typedef struct { int32 dimSizes[2]; double elt[1]; } TD1; typedef TD1 **TD1Hdl; double* callocvector(int); double* freevector(double*); double** callocmatrix(int, int); double** freematrix(double**,int); _declspec(dllexport) long KontrastC(long *Brows, long *Bcols, long *Lcols, long *Lrows, TD1Hdl Bild, TD1Hdl Kontrast,long *test); #ifdef __cplusplus } // extern "C" #endif //Hauptprogramm Kontrastberechnung long KontrastC(long *Brows, long *Bcols, long *Lcols, long *Lrows, TD1Hdl Bild, TD1Hdl Kontrast,long *test) { double** Mittelwert = callocmatrix(*Brows,*Bcols); int i=0,j=0,m=0,n=0; /* dimSizes[0] is the number of rows */ int numrow = (*Bild)->dimSizes[0]; /* dimSizes[1] is the number of columns */ int numcol = (*Bild)->dimSizes[1]; numrow=floor(numrow / *Lrows); numcol=floor(numcol / *Lcols); //(*Kontrast)->elt[(3*numcol)+2]=(*Bild)->elt[(3*numcol)+2]*1000; durch den // Mittelwertsberechnung for (m=0;m<numrow;i++) { for(n=0;n<numcol;n++) { for (i=0;i<*Lrows;i++) { for(j=0;j<*Lcols;j++) { //Mittelwert[m][n]=Mittelwert[m][n]+Bild[i+(m * *Lrows)][j+(n * *Lcols)]; Mittelwert[m][n]=Mittelwert[m][n]+ (*Bild)->elt[((i+(m * *Lrows))*numcol) + (j+(n * *Lcols))] ; } } Mittelwert[m][n]=( 1.0/(*Lrows * *Lcols) )* Mittelwert[m][n]; (*Kontrast)->elt[(m*numcol)+n]=Mittelwert[m][n]; } } //Kontrastberechnung for (m=0;m<numrow;i++) { for(n=0;n<numcol;n++) { for (i=0;i<*Lrows;i++) { for(j=0;j<*Lcols;j++) { (*Kontrast)->elt[(m*numcol)+n]= (*Kontrast)->elt[(m*numcol)+n] + ( ((*Bild)->elt[((i+(m * *Lrows))*numcol) + (j+(n * *Lcols))]-Mittelwert[m][n]) *( (*Bild)->elt[((i+(m * *Lrows))*numcol) + (j+(n * *Lcols))]-Mittelwert[m][n] ) ); //Kontrast[m][n]=*(*(Kontrast+m)+n) + ( *( *(Bild+i+(m * *Lrows))+j+(n * *Lcols) )-Mittelwert[m][n]) // *( *(*(Bild+i+(m * *Lrows))+j+(n * *Lcols) )-Mittelwert[m][n] ); } } (*Kontrast)->elt[(m*numcol)+n]=( 1.0/(*Lrows * *Lcols) )* (*Kontrast)->elt[(m*numcol)+n]; (*Kontrast)->elt[(m*numcol)+n]=(*Kontrast)->elt[(m*numcol)+n]/Mittelwert[m][n]; //Kontrast[m][n]=( 1.0/(*Lrows * *Lcols) )* *(*(Kontrast+m)+n); } } //Freigeben des reservierten Speichers Mittelwert = freematrix(Mittelwert,*Lrows); return 0; } //Unterprogramme zur dynamischen Speicherallokation /*-------------------------------------------- "callocvector" allocates the memory for a dynamic vector of length n and initializes it --------------------------------------------*/ double* callocvector(int n) { int j; double* vector = calloc(n,sizeof(double)); for (j=0; j<n; j++) { vector[j] = 0; } return(vector); } /*-------------------------------------------- "freevector" dis-allocates the memory of a dynamic vector of arbitrary length and sets the pointer to NULL --------------------------------------------*/ double* freevector(double* vector) { free(vector); return(NULL); } /*-------------------------------------------- "callocmatrix" allocates the memory for a dynamic matrix of size (m \times n) and initializes it --------------------------------------------*/ double** callocmatrix(int m, int n) { int i; double** matrix = calloc(m,sizeof(double)); for (i=0; i<m; i++) { matrix[i] = callocvector(n); } return(matrix); } /*-------------------------------------------- "freematrix" dis-allocates the memory of a dynamic matrix of size (m \times n) and sets the pointer to NULL --------------------------------------------*/ double** freematrix(double** matrix,int m) { int i; for (i=0; i<m; i++) { free(matrix[i]); } free(matrix); return(NULL); }