对于一个项目,我有matrix<float>
旋转几度。我无法控制这个过程(假设它正在使用最近邻居),我想要反转这个旋转操作并获得初始矩阵(或非常接近它的矩阵)。
我最初的假设是,如果我用-angle
旋转旋转的矩阵并裁剪中间部分,我会得到原始矩阵,但结果表明质量会急剧下降。
考虑我的原始矩阵(图中的第一张图像)是从1到100的10x10矩阵。我将其旋转+10度,然后旋转-10度。图中的第二张图像是我得到的矩阵。然后我从第二个矩阵的中间进行裁剪,并将其与初始矩阵相关联。
我用1000 * 1000的随机矩阵测试了这个;当我使用bicubic
或bilinear
插值旋转-10度时,平均相关结果约为0.37,而nearest neighbor
为0.25。
如果两个插值均为bilinear
或bicubic
,则相关结果约为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
答案 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
在中间旋转矩阵A
左侧原始矩阵B
上+10deg CW
,右侧矩阵C
向后旋转-10deg CW
。蓝色像素为正,红色像素为负值。绿色矩形是相关区域(方形重叠区域的sqrt)
[Edit1]我玩了一下着色
让a0=-13.487; a1=9.3039;
成为A
矩阵中的最小值和最大值。然后从A,B
或C
的任何值计算 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;
}
这里重新着色的结果:
正如您所看到的,有些功能可用于检测展位的旋转角度和旋转中心......只需找到/交叉匹配A
和B
中的孔,然后计算差异角度。旋转后计算偏移量,你应该得到你所需要的一切......