Ce problème m'a pris pas mal de temps mais si vous avez la bonne approche, c'est très simple.
Notez que cela ne fonctionne que pour une matrice carrée . Pour un rectangle, vous devrez utiliser l'autre algorithme (transposition et retournement). Si vous voulez le faire sur place, vous devrez peut-être redimensionner temporairement le tableau.
Simplifier le problème
Considérons la matrice suivante :
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Faites une rotation de 90 degrés et regardez uniquement les coins (numéros 1, 4, 16 et 13). Si vous avez du mal à le visualiser, aidez-vous d'un post-it.
Considérons maintenant la suivante :
1 - - 2
- - - -
- - - -
4 - - 3
Faites-la pivoter de 90 degrés et remarquez comment les chiffres sont tournés de manière circulaire : 2 devient 1, 3 devient 2, 4 devient 3, 1 devient 4.
Coins tournants
Pour faire pivoter les coins, il est nécessaire de définir tous les coins en fonction du premier coin :
- Le premier coin serait
(i, j)
- Le deuxième coin serait
(SIZE - j, i)
- Le troisième coin serait
(SIZE - i, SIZE - j)
- Le quatrième angle serait
(j, SIZE - i)
Notez que les tableaux sont basés sur 0, donc SIZE
devra également être basé sur 0. (c'est-à-dire que vous devrez soustraire 1).
Maintenant que vous avez compris l'idée des coins tournants, nous allons étendre l'idée des "coins tournants" aux "quadrants tournants". Le même principe s'applique.
Code
Vous devrez vous assurer qu'aucun numéro n'est écrasé. Autrement dit, vous devrez faire tourner 4 numéros à la fois simultanément.
#include <algorithm>
#include <numeric>
#include <vector>
using std::iota;
using std::swap;
using std::vector;
// Rotates 4 numbers.
// e.g: 1, 2, 3, 4 becomes 4, 1, 2, 3
// int& means numbers are passed by reference, not copy.
void rotate4(int &a, int &b, int &c, int &d)
{
swap(a, b);
swap(b, c);
swap(c, d);
}
void rotateMatrix(vector<vector<int>>& m) {
int n = m.size();
// NOTE: i and j from 0 to n/2 is a quadrant
for (int i = 0; i < n/2; i++) {
// NOTE : here + 1 is added to make it work when n is odd
for (int j = 0; j < (n + 1)/2; j++) {
int r_i = (n - 1) - i;
int r_j = (n - 1) - j;
rotate4(
m [i] [j],
m [r_j] [i],
m [r_i] [r_j],
m [j] [r_i]
);
}
}
}
void fillMatrix(vector<vector<int>>& m) {
int offset = 0;
for (auto &i : m) {
iota(i.begin(), i.end(), offset);
offset += i.size();
}
}
// Usage:
const int size = 8;
vector<vector<int>> matrix (size, vector<int>(size));
fillMatrix(matrix);
rotateMatrix(matrix);
Impression
Pour imprimer la matrice, vous pouvez utiliser :
#include <algorithm>
#include <iostream>
#include <iterator>
using std::copy;
using std::cout;
using std::ostream;
using std::ostream_iterator;
using std::vector;
ostream& operator<<(ostream& os, vector<vector<int>>& m) {
for (auto const &i : m) {
copy(i.begin(), i.end(), ostream_iterator<int>(os, " "));
os << "\n";
}
return os;
}
// Usage
cout << matrix;
4 votes
Comment comptez-vous faire pivoter une image non carrée sans allouer d'espace supplémentaire ? Prévoyez-vous d'échanger les indices x/y au cours du processus ?
0 votes
Pouvez-vous nous dire en détail comment l'image est stockée exactement ?
3 votes
Oh, un tableau plat... Duh, j'aurais dû y penser.
0 votes
Un problème intéressant. Je suppose que si l'image est monochrome à 1 bit par pixel, cela pourrait ajouter un autre niveau de complexité au problème.
0 votes
Je rencontre ce problème pourtant lorsque je traite une image yuv420p, je dois la faire pivoter de 90deg puis la convertir au format jpeg. J'ai vraiment besoin de la faire pivoter sur place car l'image est un flux vidéo, environ 25 fps, et nécessite une faible latence. Quelqu'un pourrait-il me donner un algorithme efficace ?
0 votes
Je rencontre ce problème pourtant lorsque je traite une image yuv420p, je dois la faire pivoter de 90deg puis la convertir au format jpeg. J'ai vraiment besoin de la faire pivoter sur place car l'image est un flux vidéo, environ 25 fps, et nécessite une faible latence. Quelqu'un pourrait-il me donner un algorithme efficace ?