Hallo,
ich verusche mithilfe einer FOR-Schleife in eine Matrix (die später mal ein TIF-Bild sein wird; hier eine Matrix aus Einsen) beliebig viele Ellipsen einzufügen. Durch den Parameter cloud_cover reguliere ich, wieviel Prozent des Bildes inetwa durch Ellipsen ersetzt werden sollen.
Diese Methode funktioniert an und für sich auch sehr gut. Das Problem ist die Rechenzeit. Die Matrix des Satellitenbildes hat die Dimensionen 8000x7000 Pixel. Da jedes Pixel mit der FOR-Schleife 'besucht' wird, um eine Ellipse zu generieren und das ganze auch noch mehrfach abläuft, um auf (in diesem Beispiel) 5% dauert die ganze Sache Stunden.
Die Rechenzeit steigt bei dieser Methode quadratisch mit der Anzahl der Matrixelemente...
Meine Frage lautet daher:
Hat jemand eine Idee, wie man das ganze effizienter gestalten könnte?
Code:
%initilal Parameters
cloud_cover = 5;
dim = 500; %Dimension der NxN-Matrix;
Matrix = ones(dim,dim+200); %Matrix aus Einsen;
%Ellsipsenparameter, a=b -> Kreis
a= 10; %Ellipse semiaxis in y-direction
b= 10; %Ellipse semiaxis in x-direction
for i=1:dim_x
for j=1:dim_y
k = i-x;
l = j-y;
if k^2/a^2+l^2/b^2<1 %squared
Matrix(i,j)=0;
end end end
%sum of matrix elemnts after cloud simulation
sum_after = sum(sum(Matrix));
%percentage of simulated clouds
cloud_fraction = 100-(sum_after/sum_before*100)
Möglichkeit 1, die stupide Brechstange, wenn du die Parallel Computing Toolbox und einen Multicore Rechner hast: Parallelisier das Ganze. Schreib in deinen Code oben hin, wenn du z.B. einen Quadcore hast:
Dan ersetze das äußere for durch ein parfor und probier mal aus.
Möglichkeit 2: Du setzt in jedem Durchlauf außen a und b neu, und in jedem inneren Loop (da wo es ganz kritisch ist), berechnest du a^2 und b^2. Setze a und b außerhalb des whiles, berechne a2 (oder nenns a_squared), für b auch, und spar dir 2mal quadrieren...
Möglichkeit 3: Vektorisieren. Das wird, wenn es klappt, viel rausholen. Hab gerade noch nicht genau genug drüber nachgedacht, tu ich aber noch. Du würdest versuchen, die for-Schleifen ganz weg zu lassen, und logische Indizes zu benutzen. Kanns gerade nich genau erklären, entweder du ahnst in welche Richtung ich will, oder ich muss das nochmal selbst versuchen...
Möglichkeit 4: Mehr vorberechnen. Die Ellipsengleichung wird ja dauernd aufgerufen, alles was sich ändert sind x und y. Du solltest, da a und b konstant sind, dir eine Art "Ellipsen-Maske" vorberechnen. Die wird dann nur darüber gelegt, wo sie gebraucht wird, ganz ohne Loop. Wie einen kleinen Stempel, der auf dein großes Bild immer draufgepresst wird, an zufälligen Locations. Das würde am allerallermeisten bringen. Ist klar was ich meine? Auch da fehlt natürlich jetzt die konkrete Umsetzung von mir.
_________________
Dan ersetze das äußere for durch ein parfor und probier mal aus.
--> ??? Error: The variable Matrix in a parfor cannot be classified.
Zitat:
Möglichkeit 2: Du setzt in jedem Durchlauf außen a und b neu, und in jedem inneren Loop (da wo es ganz kritisch ist), berechnest du a^2 und b^2. Setze a und b außerhalb des whiles, berechne a2 (oder nenns a_squared), für b auch, und spar dir 2mal quadrieren...
--> a und b werde deshalb neu berechnet, weil sie später einmal varriieren sollen für jede ellipse
zu den anderen varianten habe ich so erstmal keine vorstellung.
Mein Code produziert tatsächlich eine andere Ausgabe als Deiner. Um eine equivalente Ausgabe zu erreichen, muss aber einfach nur Vorder- und Hintergrund vertauscht werden!
Code:
% Alt: Matrix = bsxfun(@plus, k .^ 2 / a^2, l .^ 2 / b ^ 2) < 1; % Neu:
Matrix = bsxfun(@plus, k .^ 2 / a^2, l .^ 2 / b ^ 2) >= 1;
Leidr läuft das Programm dann nicht mehr korrekt. Bei meiner Variante wird eine Ellipse erzeugt, geschaut, wieviel Prozent des Bildes dann mit Ellipsen gefüllt sind und das Ganze so oft wiederholt, bis der Grenzwert (hier 5%) überschritten wurde. Bei deiner Variante wird zwar eine Ellipse eingefügt, aber beim nächsten Durchlauf der While-Schleife wieder überschrieben, so, dass der Prozentsatz immer ungefähr gleich bleibt und nicht ansteigt. Wie kann ich das denn beheben?
%Matrix=imread('C:\Users\Robert\Desktop\LT51940242007197MOR00\test_subset.tif', 'TIFF');
dim = 500; %Dimension der NxN-Matrix;
Matrix = ones(dim,dim); %Matrix aus Einsen;
Ja, mein Code produziert nur eine einzelne Ellipse. Ich hielt den Transfer daraus die Summe mehrerer Ellipsen zu erstellen, für leicht. Dafür gibt es viele Möglichkeiten, z.B.:
so lange die Matrix quadratisch ist, funktioniert die Funktion bsxfun wunderbar. Wenn ich jedoch eine nicht quadratische Matrix einlade (in diesem Fall 7321*8251) geht das ganze nicht mehr und das Ergebnis sind 1 Pixel breite streifen, anstelle der gewollten Ellipsen
fällt Dir das Muster in dem Bild auf? Sieht ganz so aus, als habest Du X- und Y-Koordinaten beim logical-indexing vertauscht, woraufhin die Ellipsen in den Spalten verschoben würden. Versuche das ganze doch mal mit einer Ellipse und viel weniger Pixeln, so dass Du Dir die Ausgabe der BSXFCN-Funktion noch im Command-Window betrachten kannst.
das ist scheinbar tatsächlich des Pudels Kern gewesen. (siehe Bild)
Vielen Dank!
Robert
Jan S hat Folgendes geschrieben:
Hallo x4ecro,
fällt Dir das Muster in dem Bild auf? Sieht ganz so aus, als habest Du X- und Y-Koordinaten beim logical-indexing vertauscht, woraufhin die Ellipsen in den Spalten verschoben würden. Versuche das ganze doch mal mit einer Ellipse und viel weniger Pixeln, so dass Du Dir die Ausgabe der BSXFCN-Funktion noch im Command-Window betrachten kannst.
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.