反转旋转插值

时间:2017-01-26 19:17:57

标签: matlab image-processing matrix rotation interpolation

对于一个项目,我有matrix<float>旋转几度。我无法控制这个过程(假设它正在使用最近邻居),我想要反转这个旋转操作并获得初始矩阵(或非常接近它的矩阵)。

我最初的假设是,如果我用-angle旋转旋转的矩阵并裁剪中间部分,我会得到原始矩阵,但结果表明质量会急剧下降。

考虑我的原始矩阵(图中的第一张图像)是从1到100的10x10矩阵。我将其旋转+10度,然后旋转-10度。图中的第二张图像是我得到的矩阵。然后我从第二个矩阵的中间进行裁剪,并将其与初始矩阵相关联。

Example image

我用1000 * 1000的随机矩阵测试了这个;当我使用bicubicbilinear插值旋转-10度时,平均相关结果约为0.37,而nearest neighbor为0.25。

如果两个插值均为bilinearbicubic,则相关结果约为0.45-0.5。

我想知道是否有办法减少插值造成的损失。请注意,在实际实验中我没有原始图像,我只是估计旋转角度,因此旋转角度估计的精度会导致另一个性能下降。我在网上搜索但找不到任何关于它的信息。

这是我在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

1 个答案:

答案 0 :(得分:1)

我在 P1.csv 750x1000矩阵中对 C ++ 进行了小测试。我按+10deg向后旋转了-10deg,然后在矩阵中心周围进行双线性插值。

产生的相关性(在749x749结果的中间平方)是0.8275936因此,要么您没有关联相同的数据(可能是矩阵之间的某些偏移),要么以某种方式截断结果。例如,我使用整数矩阵旋转代码进行此操作,而忘记删除整数截断,相关性大约为0.3,这与您的声明类似。

由于我不在 Matlab 这里使用 C ++ 来源,您可以尝试移植或检查您的实施:

//---------------------------------------------------------------------------
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只是动态二维数组(我为此而破坏),例如float A[A.xs][A.ys];,其中xs,ys是大小。 A.resize(xs,ys)会将矩阵A的大小调整为新的大小。来源:

//---------------------------------------------------------------------------
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;
        }
    };
//---------------------------------------------------------------------------

测试如下:

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);

由于双线性插值,旋转的单元格会流向相邻的单元格,因此如果需要多次旋转(例如找出未知角度),则应始终旋转原始矩阵,而不是在子单元格上多次旋转结果矩阵。

此处预览 P1

P1 preview

在中间旋转矩阵A左侧原始矩阵B+10deg CW,右侧矩阵C向后旋转-10deg CW。蓝色像素为正,红色像素为负值。绿色矩形是相关区域(方形重叠区域的sqrt)

[Edit1]我玩了一下着色

a0=-13.487; a1=9.3039;成为A矩阵中的最小值和最大值。然后从A,BC的任何值计算 RGB 颜色,我使用了这个:

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;
    }

这里重新着色的结果:

P1 preview recolored

正如您所看到的,有些功能可用于检测展位的旋转角度和旋转中心......只需找到/交叉匹配AB中的孔,然后计算差异角度。旋转后计算偏移量,你应该得到你所需要的一切......

angle