2015-05-02 4 views
9

Wie zyklische Elemente durch jeden Index von Patches einer Matrix, ohne explizit durch jeden Patch zu iterieren?Circular shift von Patches in Matrix in MATLAB

Example

Die iterative Weise, die ich denken kann dieses Radfahren auszuführen ist mit circshift Funktion des MATLAB. Ich könnte durch jeden MxN-Patch in meiner Matrix iterieren und eine kreisförmige Verschiebung der Elemente dieses Patches ausführen.

(HINWEIS: circshift nimmt ein Array und verschiebt den ersten (oder k-ten) Index nach hinten, verschiebt alles nach vorne, um Platz zu machen. Mit einer Matrix, nur Vektorisieren, verschieben und umformen, zurücknehmen Vorteil der MATLAB-Spalte-major lineare Indexierung)

Das wäre toll, wenn ich durch jedes MxN-Fenster meiner größeren (j * M xk * N für ganze Zahlen j, k) Matrix durchlaufen würde. Ich möchte jedoch in der Lage sein, for-Schleifen zu vermeiden und den vektorisierten Code von MATLAB dazu zu nutzen, dies auf einen Schlag zu tun.

Eine vollständige Iteration durch ein Beispiel (2x2 Patches in irgendeiner Matrix B) wäre:

B =   --> B =   --> B =   --> B = 
[ 5 6 7 8 ] --> [ 5 6 7 8 ] --> [ 6 5 8 7 ] --> [ 6 5 8 7 ] 
[ 5 6 7 8 ] --> [ 6 5 8 7 ] --> [ 6 5 8 7 ] --> [ 5 6 7 8 ] 
[ 5 6 7 8 ] --> [ 5 6 7 8 ] --> [ 6 5 8 7 ] --> [ 6 5 8 7 ] 
[ 5 6 7 8 ] --> [ 6 5 8 7 ] --> [ 6 5 8 7 ] --> [ 5 6 7 8 ] 

Irgendwelche Ideen, wie man diese Schichtarbeit machen, ohne durch jeden Patch explizit laufen? Ich habe das Gefühl, dass lineare Indexierung hier der Schlüssel ist, aber ich bin mir nicht sicher warum. Ich interessiere mich auch nicht für die Reihenfolge der Rotation, solange jedes Patch-Element in jedem Patch-Index endet.

Vielen Dank im Voraus!

EDIT: Hier ist eine Kopie-und-Einfügen-fähige Spielzeug-Implementierung mit for-Schleifen zu demonstrieren, was ich suche. Die einzigen für Schleife, die in einer Antwort enthalten sein sollen, ist der k -iterator (steuert, wie viele Schichten letztlich gemacht werden müssen)

A = repmat(1:4, 4, 1); % Input matrix 

% k represents the total number of shifts to be made 
for k = 1:4 

    % Iterate through each patch 
    for i = 1:2:size(A,1) 
     for j = 1:2:size(A,2) 
      tmp = A(i:i+1,j:j+1); % Isolate specific patch 

      % Circularly shift the vectorized patch, reshape it to a matrix 
      % and insert it back into the original matrix 
      A(i:i+1,j:j+1) = reshape(circshift(tmp(:),1), 2, 2); 
     end 
    end 
    display(A) % Display each completely shifted iteration 
end 
+0

Es ist eine interessante Frage. Sie können grundsätzlich berücksichtigen, dass alles, was Sie wollen, getan werden kann. Aber zumindest bin ich nicht motiviert, darüber nachzudenken, wie Ihr Input und Output gestaltet werden sollte. Bitte posten Sie Ihre exakten Eingaben, die zum Kopieren und Einfügen bereit sind, und die Ausgabe, die Sie für diese Eingabe erhalten möchten (auch bereit zum Kopieren und Einfügen). Es gibt viele Dinge zu klären. z.B. Magst du Zellenarrays als Ausgabe? oder 3D-Matrizen? – thewaywewalk

+0

@thewaywewalk Ich habe ein Spielzeugbeispiel für Copy/Paste hinzugefügt, das hoffentlich zeigen soll, wonach ich suche. Die Ausgabe sollte eine Matrix mit den gleichen Dimensionen wie die Eingabe sein. Ich möchte Zellenarrays vermeiden, wenn sie nicht einfach zurückkonvertiert werden können. Ich habe darüber nachgedacht, auch Zellen-Arrays zu verwenden, weil sie nützlich sind, um eine Matrix in Blöcke zu zerlegen, aber selbst damit hilft es nicht, die Verschiebung so weit zu machen, wie ich es beurteilen kann. – marcman

Antwort

2

Ein einfacher Weg, dies zu tun, um die blockproc Funktion aus dem Bild zu verwenden, wäre Verarbeitungs-Toolbox blockproc unterteilt ein Bild (oder allgemein: einer Matrix) in Blöcke einer definierten Größe und wendet eine Funktion auf jeden dieser Blöcke:

B = blockproc(A,blockSize,fun); 

blockproc, können wir die Matrix A in 2 x 2 patches dividieren und gelten die kreisförmige Verschiebung zu jedem dieser Patches. Beachten Sie, dass blockproc einen block_struct Datentyp erstellt und fun(block_struct) aufruft. Um die Daten zu erhalten, verwenden Sie einfach das Feld data der Struktur. Dies führt zu

B = blockproc(A, [2,2], @(x)reshape(circshift(x.data(:),1),2,2)); 

Oder mit dem Beispiel-Code zur Verfügung gestellt:

A = repmat(1:4, 4, 1); 
for k=1:4 
    A = blockproc(A, [2,2], @(x)reshape(circshift(x.data(:),1),2,2)); 
    display(A); 
end 

, die die gewünschte Ausgabe

[ 1 2 3 4 ]  [ 2 1 4 3 ]  [ 2 1 4 3 ]  [ 1 2 3 4 ] 
[ 1 2 3 4 ] -> [ 1 2 3 4 ] -> [ 2 1 4 3 ] -> [ 2 1 4 3 ] -> ... 
[ 1 2 3 4 ]  [ 2 1 4 3 ]  [ 2 1 4 3 ]  [ 1 2 3 4 ] 
[ 1 2 3 4 ]  [ 1 2 3 4 ]  [ 2 1 4 3 ]  [ 2 1 4 3 ] 

Sie können, wie zu handhaben Fällen, in denen die Matrix definieren können auch erzeugt nicht in 2 x 2 Blöcke unterteilt werden, z wenn es die Dimension 5 x 7 hat (wie in Kommentaren erwähnt). Wenn Sie PadPartialBlocks auf true setzen, werden alle Teilblöcke aufgefüllt, sodass sie volle 2 x 2 Blöcke bilden.Sie können die PadMethod Eigenschaft auf einen der folgenden Werte gesetzt, je nachdem, was Sie brauchen:

  • x wo x eine Zahl ist, die alle weiteren Punkte gesetzt werden.
  • replicate werden die Randelemente der Matrix wiederholen A
  • symmetric Tampon A mit symmetrischen Reflexionen von itsself
+0

Wie behandelt Blockproc Edge Cases? Zum Beispiel, wenn die Eingabematrix nicht jM x kN, sondern stattdessen 5x7 für 2x2 Patches wäre? – marcman

+0

@marcman Ich habe auch etwas hinzugefügt. Wenn Sie definieren, welches Verhalten gewünscht wird, kann ich wahrscheinlich zeigen, wie das geschehen würde. – hbaderts