matlab - Inverser une interpolation de rotation



image-processing matrix (1)

J'ai fait un petit test en C ++ sur votre matrice P1.csv 750x1000 . Je l'ai fait pivoter de +10deg puis de -10deg avec interpolation bilinéaire autour du centre de la matrice.

La corrélation résultante (sur le 749x749 milieu du résultat 0.8275936 ) est 0.8275936 Donc, soit vous ne 0.8275936 pas les mêmes données (peut-être un certain décalage entre les matrices), soit vous tronquez le résultat d'une manière ou d'une autre. Par exemple, je fais cela à partir de mon code de rotation de matrice entière et tout en oubliant de supprimer des entiers tronquant la corrélation était d'environ 0.3 ce qui est similaire à vos revendications.

Comme je n'utilise pas Matlab ici ma source C ++, vous pouvez essayer de porter ou vérifier avec vos implémentations:

//---------------------------------------------------------------------------
const float deg=M_PI/180.0;
const float rad=180.0/M_PI;
int x0,y0,r0; 
matrix A,B,C;
float c=0.0,ang=10.0*deg;
//---------------------------------------------------------------------------
void rotcw(matrix &B,matrix &A,int x0,int y0,float ang) // rotate A -> B by angle ang around (x0,y0) CW if ang>0
    {
    int x,y,ix0,iy0,ix1,iy1;
    float xx,yy,fx,fy,c,s,q;
    B.resize(A.xs,A.ys);
    // circle kernel
    c=cos(-ang); s=sin(-ang);
    // rotate
    for (y=0;y<A.ys;y++)
     for (x=0;x<A.xs;x++)
        {
        // offset so (0,0) is center of rotation
        xx=x-x0;
        yy=y-y0;
        // rotate (fx,fy) by ang
        fx=float((xx*c)-(yy*s));
        fy=float((xx*s)+(yy*c));
        // offset back and convert to ints and weights
        fx+=x0; ix0=floor(fx); fx-=ix0; ix1=ix0+1; if (ix1>=A.xs) ix1=ix0;
        fy+=y0; iy0=floor(fy); fy-=iy0; iy1=iy0+1; if (iy1>=A.ys) iy1=iy0;
        // bilinear interpolation A[fx][fy] -> B[x][y]
        if ((ix0>=0)&&(ix0<A.xs)&&(iy0>=0)&&(iy0<A.ys))
            {
            xx=float(A[ix0][iy0])+(float(A[ix1][iy0]-A[ix0][iy0])*fx);
            yy=float(A[ix0][iy1])+(float(A[ix1][iy1]-A[ix0][iy1])*fx);
            xx=xx+((yy-xx)*fy); q=xx;
            } else q=0;
        B[x][y]=q;
        }
    }
//---------------------------------------------------------------------------
float correl(matrix &A,matrix &B,int x0,int y0,int x1,int y1)
    {
    int x,y;
    float sxy=0.0,sx=0.0,sy=0.0,sxx=0.0,syy=0.0,n=(x1-x0+1)*(y1-y0+1),a,b;
    for (x=x0;x<=x1;x++)
     for (y=y0;y<=y1;y++)
        {
        a=A[x][y];
        b=B[x][y];
        sx+=a; sxx+=a*a;
        sy+=b; syy+=b*b;
        sxy+=a*b;
        }
    a=(n*sxy)-(sx*sy);
    b=sqrt((n*sxx)-(sx*sx))*sqrt((n*syy)-(sy*sy));
    if (fabs(b)<1e-10) return 0.0;
    return a/b;
    }
//---------------------------------------------------------------------------

matrix A est juste un tableau 2D dynamique (j'ai éclaté pour cela) comme float A[A.xs][A.ys];xs,ys est la taille. A.resize(xs,ys) redimensionnera la matrice A à une nouvelle taille. Ici source:

//---------------------------------------------------------------------------
class matrix
    {
public:
    int xs,ys;
    float **a;  // float a[xs][ys]

    matrix()    { a=NULL; xs=0; ys=0; }
    matrix(matrix& q)   { *this=q; }
    ~matrix()   { free(); }
    matrix* operator = (const matrix *q) { *this=*q; return this; }
    matrix* operator = (const matrix &q) { resize(q.xs,q.ys); for (int x=0;x<xs;x++) for (int y=0;y<ys;y++)  a[x][y]=q.a[x][y]; return this; }
    float* operator[] (int x) { return a[x]; };

    void free() { if (a) { if (a[0]) delete[] a[0]; delete[] a; } a=NULL; xs=0; ys=0; }
    void resize(int _xs,int _ys)
        {
        free();
        if (_xs<=0) return;
        if (_ys<=0) return;
        a=new float*[_xs]; if (a==NULL) return;
        float *aa=new float[_xs*_ys];   if (aa==NULL) return;
        xs=_xs; ys=_ys;
        for (int x=0;x<xs;x++,aa+=ys) a[x]=aa;
        }
    };
//---------------------------------------------------------------------------

Le test ressemble à ceci:

x0=A.xs>>1; // center for rotation
y0=A.ys>>1;
if (x0<y0) r0=x0-1; else r0=y0-1; // mid square size for correltaion
rotcw(B,A,x0,y0,+ang);
rotcw(C,B,x0,y0,-ang);
c=correl(A,C,x0-r0,y0-r0,x0+r0,y0+r0);

En raison de l'interpolation bilinéaire, les cellules pivotent vers les cellules voisines. Si vous devez effectuer plusieurs rotations (par exemple pour déterminer l'angle inconnu), vous devez toujours faire pivoter la matrice d'origine au lieu d'appliquer plusieurs fois la rotation sur la matrice.

Voici l'aperçu de votre P1

sur la matrice originale A gauche dans la matrice B en rotation moyenne de +10deg CW et sur la matrice droite C de -10deg CW C rotation. Les pixels bleus sont positifs et les pixels rouges sont des valeurs négatives. Le rectangle vert est la zone corrélée (sqrt de la zone chevauchée carrée)

[Edit1] Je joue avec la coloration un peu

soit a0=-13.487; a1=9.3039; a0=-13.487; a1=9.3039; être les valeurs min et max de votre matrice A Ensuite, pour calculer la couleur RVB à partir de n'importe quelle valeur de A,B ou C j'ai utilisé ceci:

DWORD col(float x)
    {
    DWORD c; int sh;
    if (x>=0) { sh= 0; x/=a1; } // positive values in Blue
    else      { sh=16; x/=a0; } // negative values in Red
    x*=255.0*50.0; // 50.0x saturated to emphasize used values
    c=x; if (c>255) c=255; // clamp to 8bit per channel
    return c<<sh;
    }

Et voici le résultat recolorié:

Comme vous pouvez le voir il ya des caractéristiques qui pourraient être utilisées pour détecter la cabine l'angle de rotation et le centre de rotation ... Il suffit de localiser / croiser les trous dans A et B et ensuite calculer l'angle de différence. Après la rotation calculer le décalage et vous devriez obtenir tout ce dont vous avez besoin ...

Pour un projet, j'ai une matrix<float> qui tourne de quelques degrés. Je n'ai aucun contrôle sur ce processus (supposons qu'il utilise le plus proche voisin), je veux inverser cette opération de rotation et obtenir la matrice initiale (ou une matrice très proche de celle-ci).

Mon hypothèse initiale était que si je fais tourner la matrice pivotée avec -angle et -angle la partie du milieu, j'aurais la matrice d'origine mais les résultats indiquent que la qualité chute de façon spectaculaire.

Considérons ma matrice originale (la première image de la figure ) est une matrice 10x10 de 1 à 100. Je la fais pivoter de +10 degrés, puis de -10 degrés. La deuxième image de la figure est ma matrice résultante. Ensuite, je recadre à partir du milieu de la deuxième matrice et corréler avec la matrice initiale .

J'ai testé cela avec 1000 matrice aléatoire de 1000 * 1000; quand je fais une rotation de -10 degrés avec une interpolation bicubic ou bilinear , le résultat de corrélation moyen est d'environ 0,37 alors que le nearest neighbor est de 0,25.

Si les deux interpolations sont bilinear ou bicubic , le résultat de la corrélation est d'environ 0,45-0,5.

Je me demande s'il existe un moyen de minimiser la perte causée par l'interpolation. Notez que dans l'expérience réelle je n'ai pas l'image originale, je ne fais qu'estimer l'angle de rotation, donc il y a une autre baisse de performance causée par la précision de l'estimation de l'angle de rotation. J'ai cherché en ligne mais je n'ai rien trouvé à ce sujet.

Voici mon code de test simple dans matlab,

res = 0;
for i = 0:1000
    a = uint8(rand(1000,1000)*255);
    arr = imrotate(imrotate(a,10, 'bicubic'), -10, 'bicubic');

    [r1,c1] = size(a);
    [r2,c2] = size(arr);
    rd = ceil((c2-c1)/2);
    cd = ceil((r2-r1)/2);
    c_arr = arr(cd:end-cd, rd:end-rd);

    res = res+corr2(a, c_arr);
end
res/1000




interpolation