Ich hab ein keines Verständnissproblem mit der Tic-Toc Funktion von Matlab.
Ich bin gerade dabei für eine Bildverarbeitungsaufgabe einen eigenen Objekterkennungsalgorythmus zu programmieren. (Mir ist klar dass es da natürlich eine eigene FUnktin gibt ...)
Die Zeitmessungen mit Tic-Toc habe ich nicht (wie im Code gezeigt) gleichzeit verwendet sondern immer einzeln.
Wenn ich den Inhalt in der if-Funktion auskommentiere und die Messung 1 ausgeben lasse, bekomme ich einen Messwert von 0,026 Sekunden. (Das ist scheinbar die Zeit die Matlab benötigt um für Jeden Punkt im Bild (bw) den Pixelwert mit der if-Funkion zu überprüfen). (In der If- FUnktion wird jedoch keine Operation durchgeführt)
Wenn ich nun den If-Schleifeninhalt wieder einblende und die Messung 2 beobachte, erhalte ich 10 Messwerte (Da die if-Funktion 10mal erfüllt wird) mit 0,001 sekunden. Somit wären das in Summe rund 0,01sekunden.
Für mich wäre es nun logisch wenn die Messung 1 mit eingeblendeter if-Struktur 0,036 sekunden benötigen würde.
Jedoch dauert dass dann unglaubliche 2,15 sekunden.
Den Denkfehler kann ich dir nicht erklären, dazu müsste ich wissen was konturverfolgung3 macht. Schau dir doch mal "profile" an, damit siehst du in welcher Zeile der Code wieviel Zeit benötigt.
Manchmal ist Matlabs JIT sehr schlau und optimiert die inneren Schleifenaufrufe weg, wenn es erkennt, dass die Werte nirgendwo benutzt werden. Deshalb ist eine Laufzeitmessung mit einer (fast) leeren Schleife nicht unbedingt nachvollziehbar.
Hier, und bei den anderen Variablen wahrscheinlich auch, wird der Output in jeder Iteration vergrößert. Dies ist als "fehlende Pre-allocation" bekannt und es ollten entsprechende MLint-Warnungen im Editor erscheinen - sind da welche?
Wenn ein Array iterativ vergrößert wird, bis es n Elemente enthält, muss Matlab nicht n*8 Bytes allocieren (ein DOUBLE hat 8 Byte), sondern SUM(1:n)*8. Bei n==10 sollte das allerdings nicht zu 2.15 Sekunden Laufzeit führen, denn auch SUM(1:10) ist nur 55. Aber SUM(1:1000) ist schon 500500.
Im Endeffekt ist also dmjr's Empfehlung des Profilers wohl am besten. Allerdings schaltet der Profiler leider die JIT ab. Es kann deshalb sein, dass eine sehr effizient ausgeführte Schleife im Profiler plötzlich lahm aussieht.
Gruß, Jan
Geppsl
Gast
Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
Verfasst am: 26.11.2012, 19:43
Titel:
Danke für die schnellen Antworten.
Ich bin heute leider ein bisschen Zeitlich eingespannt aber konnte mal einen kurzen Blick auf den Profiler werfen. Ist ziemlich nützlich. Morgen werde ich mir den Code in Ruhe nochmal anschauen können um die Schwachstelle zu suchen.
Bezüglich der Sache mit dem interativen Vergrößern:
Ich hab die Warnung eh auch schon von Matlab bemerkt. Jedoch wüsste ich nicht wie man es anders programmieren könnte.
Ich hab gelesen, dass es schneller wäre zuerst eine Varibale mit Nullen zu initiallisieren und anschließend die Werte zu überschreiben. Wie wird dass jedoch gehandhabt wenn ich nicht weiß, wie offt meine Schleife durchlaufen wird? (Ist nämlich von der Objektanzahl im Bild abhängig)
Wenn man eine akzeptabele Obergrenze kennt, ist es im Allgemeinen billiger dies zu verwenden und die ungenutzten Elemente hinterher zu verwerfen. Das Allozieren von 1000 Elementen ist billiger als 45 Elemente iterative zu vergrößern.
Gruß, Jan
Gepps
Gast
Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
Verfasst am: 29.11.2012, 00:06
Titel:
Hallo Leute
Ich bin langsam ziemlich am verzweifeln.
Ich bin nun noch auf eine Möglichkeit gekommen den Code deutlich zu vereinfachen. (Ich erspare mir nun einige Hilfsvariablen und unnötige if-Abfragen)
Weiters hab ich alle vorkommenden interaitven Variablen-Vergrößerungen durch eine Vorinitialisierung ersetzt.
for zeile=1:zeilen
for spalte=1:spalten
if(bw(zeile,spalte)==1)% Wenn der Wert 1 ist... if(bw2(zeile,spalte)==0) tic [Konturzeile, Konturspalte, Areazeile, Areaspalte, objektanzahl, bw2]=konturverfolgung3(bw, bw2, R, zeile, spalte, objektanzahl);
% Ergebnis Speichern
Konturzeilen{objektanzahl}=Konturzeile;
Konturspalten{objektanzahl}=Konturspalte;
Areazeilen{objektanzahl}=Areazeile;
Areaspalten{objektanzahl}=Areaspalte;
toc end end end end
%% Flächenschwerpunkt
S=zeros(2,10);
for k=1:objektanzahl
S(1,k)=sum(Konturspalten{k})/numel(Konturspalten{k});
S(2,k)=sum(Konturzeilen{k})/numel(Konturzeilen{k});
end
Wie oft ist "if (bw(zeile,spalte)==1)" überhaupt wahr?
Ansonsten ist der Haken an dem Code dass die Funktion konturverfolgung3 bw2 zurückgibt, dadurch lässt sich vorab nicht bestimmen für welche Werte die Schleife durchlaufen wird (was Optimierungspotential bieten würde).
Geppsl
Gast
Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
Verfasst am: 30.11.2012, 00:30
Titel:
Hallo dmjr
Die erste If- Abfrage wird bei jedem Pixel erfüllt auf dem der Pixelwert 1 ist (Ich schätze 100 - 200 mal)
die zweite if-Abfrage wird pro Objekt nur einmal erfüllt. In meinem Fall sind es 10 Objekte.
Ich hab nun nochmals meinen Code noch weiter reduziert. Anstelle des bw2 Bildes arbeite ich nun nur noch mit dem bw-Bild.
for zeile=1:zeilen
for spalte=1:spalten
if(bw(zeile,spalte)==1)% Wenn der Wert 1 ist... [bw, Konturzeile, Konturspalte, objektanzahl] = konturverfolgung4(bw, R, zeile, spalte, objektanzahl);
% Ergebnis Speichern
Konturzeilen{objektanzahl}=Konturzeile;
Konturspalten{objektanzahl}=Konturspalte;
end end end
Der Code macht nichts anderes als im Bild bw die Pixel abzusuchen bis er auf das erste Pixel stößt indem ein 1er steht (somit ein Objekt detektiert wird). Sobald er das gefunden hat verfolgt meine Unterfunktion Konturverfolgung4 die Kontur und löscht die entsprechenden Pixel aus dem bw. (Ist notwendig, da sonst ein Objekt mehrmals detektiert wird).
Der Code benötigt noch immer über 3 Sekunden.
Ich wüsste nicht wie ich um das Überschreiben von bw herum kommen könnte.
Ich hab mal versucht den Inhalt der If-Abfrage auszukommentieren und ohne Unterfunktion die gefundenen Pixel im BW einfach zu überschreiben.
Das sollte nun viel schneller laufen als 0.2 sec. Verblüffend ist die Geschwindigkeit also nicht wirklich. Dass der gesamte Code viel länger benötigt, liegt wohl daran dass "konturverfolgung4" viel Zeit benötigt. Deshalb ist es sinnvoll, sich bei der Optimierung des Codes auf diese funktion zu konzentrieren.
Regel: Optimier immer nur ein einziges Bottleneck.
Gruß, Jan
Geppsl
Gast
Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
Verfasst am: 30.11.2012, 18:24
Titel:
Hallo Jan
Das austauschen der Schleifen ändert leider auch nichts.
Laut Tic Toc und Profiler benötigt die Konturverfolgung4 rund 0,001s - 0,003s (Je nach Objektgröße). Da die If- Schleife 10 Mal erfüllt wird sind wir da bei ca 0,03 Sekunden. Somit kann es daran nicht liegen.
Für mich hat es den Eindruck als hätte Matlab irgend eine Art von Aktualisierungsproblem (Dadurch dass bw bei jeder if- Erfüllung geändert wird)
Hat jemand vielleicht eine Ahnung wie Matlab dieses Problem mit dem fertigen Befehl "regionprops(bw, {'Centroid'})" löst? .... Es muss ja scheinbar einen schnelleren Ansatz dafür geben das Bild abzusuchen ....
while((Startwert(1) ~= Neuwert(1)) || (Startwert(2) ~= Neuwert(2)) || (n<=3))% Solange der Neuwert nicht der Startwert ist ...
Wert1=bw((Neuwert(1)+R(1,1,vk)),(Neuwert(2)+R(2,1,vk)));
Wert2=bw((Neuwert(1)+R(1,2,vk)),(Neuwert(2)+R(2,2,vk)));
Wert3=bw((Neuwert(1)+R(1,3,vk)),(Neuwert(2)+R(2,3,vk)));
if Wert1==1
Konturzeile(n)=Neuwert(1)+R(1,1,vk); %In Kontur speichern
Konturspalte(n)=Neuwert(2)+R(2,1,vk);
vector=mod(vector-2,8); %Tichtungsvektor um 2 reduzieren
Neuwert=[Konturzeile(n),Konturspalte(n)];
n=n+1;
else if(Wert2==1)
Konturzeile(n)=Neuwert(1)+R(1,2,vk); %In Kontur speichern
Konturspalte(n)=Neuwert(2)+R(2,2,vk);
Neuwert=[Konturzeile(n),Konturspalte(n)];
n=n+1;
else if(Wert3==1)
Konturzeile(n)=Neuwert(1)+R(1,3,vk); %In Kontur speichern
Konturspalte(n)=Neuwert(2)+R(2,3,vk);
Neuwert=[Konturzeile(n),Konturspalte(n)];
n=n+1;
else
vector=mod(vector+2,8); %Tichtungsvektor um 2 reduzieren
end end end
vk=vector+1;
end
%Löschen des letzten Eintrages
Konturspalte(numel(Konturspalte))=[];
Konturzeile(numel(Konturzeile))=[];
n=1; % Laufvariable für die Area-Werte for k= min(Konturzeile) : max(Konturzeile)% Zeilenweise Kontur Prüfen
fuellstart=find(Konturzeile==k); % Suche Konturpunkte mit aktuellen Zeilenwert for i= min(Konturspalte(fuellstart)) : max(Konturspalte(fuellstart))% Zwischenwerte ausfüllen und in Area abspeichern
bw(k,i)=0;
n=n+1;
end end
Du kannst Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen. Du kannst Dateien in diesem Forum posten Du kannst Dateien in diesem Forum herunterladen
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.