基于OpenCV的循环行、列移动函数circShift()
///*12 在Matlab中有个circshift()函数,可以实现行、列的循环移动
/// 在返卷积运算中,会用到这个函数。所以,在Opencv中我也定义同样功能的函数
/// 该函数有3个参数,第1个src是输入矩阵或图像,第2、3个参数分别是
/// 沿着'行'方向移动的函数,和沿着‘列’方向移动的列数。
以前在写这段代码的时候,没有考虑效率问题,今天重写改写了程序。函数名、3个形参,与malab中用到的完全一致。
与matlab不同的是,本函数不能一次同时执行行、列平移。
同时本文也给了另外一个版本,用remap函数实现矩阵的平行移动,而且可以同时实现行、列的循环平移,这一点上与matlab完全一样了。
最近又搞了个平行加速版,用paralle_for_,可以对处理764×1162尺寸的图像提高2ms,参见函数三。速度比函数二提高了2ms。而函数一却是函数三的6倍速度
函数一:
void circShift(Mat&src,//原矩阵 int shift_m,//循环移动的行数或列数 const int RowOrCol=1)//默认为1,表示行循环移动;否则列循环 { int m=shift_m; int rows=src.rows; m %=rows; if(m<0) m=rows+m; else if(m==0){ return ; } if(RowOrCol!=1)//如果是列偏移,将原矩阵转置 src=src.t(); src.push_back( src(Range(0,m),Range::all()));//将准备平移的行添加到src的末尾 src.data +=src.step[0]*m;//将data指针下移m行 src.pop_back(m);//将末尾多余的行移除 if(RowOrCol!=1)//将转置矩阵复原 src=src.t(); }
函数二,remap实现:
void circshift(Mat&src,//原图像 Size size)//height>0循环上一移,反之循环下移;width>0循环左移,反之右移 { Mat srcx(src.size(),CV_32F); Mat srcy(src.size(),CV_32F); int rows=src.rows,cols=src.cols; int height=size.height%rows; int width=size.width%cols;
if(height<0)
height +=rows;
if(width<0)
width +=cols;float x,y;
for(int i=0;i<rows;i++)
{ for(int j=0;j<cols;j++)
{
x=(j+width)%cols;
y=(i+height)%rows;
srcx.ptr<float>(i)[j]=x;
srcy.ptr<float>(i)[j]=y;
}
}
remap(src,src,srcx,srcy,INTER_NEAREST);
}
函数三,加速版746×1162尺寸的图像,比前面的函数二提高了2ms,不过最快的还是函数一,是函数三的6倍:
void circshift(Mat&src,//原图像 Size size)//height>0循环上一移,反之循环下移;width>0循环左移,反之右移 { Mat srcx(src.size(),CV_32F); Mat srcy(src.size(),CV_32F); int rows=src.rows,cols=src.cols; int height=size.height%rows; int width=size.width%cols; float *psrcx=(float*)srcx.data; float *psrcy=(float*)srcy.data; int totalPixs=src.rows*src.cols; parallel_for_(Range(0,totalPixs),[&](const Range&range){ for(int r=range.start;r<range.end;r++) { int i=r/rows;//第i行 int j=r%cols;//第j列 psrcx[r]=(j+width+cols)%cols; psrcy[r]=(i+height+rows)%rows; } remap(src,src,srcx,srcy,INTER_NEAREST); });
测试程序,对imgc移动3列:
int main() { // Mat img1=imread("D:/CodeWork/MyImage/baboon.jpg",0); Mat imgc=(Mat_<uchar>(9,12) <<0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11); Mat imgr=imgc.t(); cout<<"original imgc="<<endl<<imgc<<endl; circShift(imgc,0,3); // circShift(imgc,0,3); cout<<"3 cols-shifted imgc="<<endl<<imgc<<endl; waitKey(); return 0; }
运行结果如下:
测试程序,对imgr移动3行:
int main() { // Mat img1=imread("D:/CodeWork/MyImage/baboon.jpg",0); Mat imgc=(Mat_<uchar>(9,12) <<0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11, 0,1,2,3,4,5,6,7,8,9,10,11); Mat imgr=imgc.t(); cout<<"original imgr="<<endl<<imgr<<endl; circShift(imgr,0,3); cout<<"3 rows-shifted imgr="<<endl<<imgr<<endl; waitKey(); return 0; }
运行结果如下: