使用到的函数:
void remap(InputArray src,OutputArray dst,InputArray map1,InputArray map2,int Interpolation,int borderMode=BORDER_CONSTANT,const Scalar& borderValue=Scalar())
remap()函数的作用:将一般几何变换应用于图像
(1)stc: 原图像
(2)dst:输出图像
(3)map1:表示点(x,y)的第一个映射;或者表示CV_16SC2 , CV_32FC1 或CV_32FC2类型的X值
(4)map2:根据map1来确定表示哪种对象:若map1表示点(x,y)时,参数不代表任何值;若表示CV_16UC1 , CV_32FC1类型的Y值(第二个值)
(5)interpolation(插值方式):
INTER_NEAREST - 最近邻插值
INTER_LINEAR – 双线性插值(默认值)
- borderMode(边界模式):有默认值BORDER_CONSTANT,表示目标图像中“离群点(outliers)”的像素值不会被此函数修改。
- borderValue(当有常数边界时使用的值):其有默认值Scalar( ),即默认值为Scalar( 0,0,0)
几何变换方式:
向前映射:已知变换函数得原图像一点变换后得目标图像位置
向后映射:已知目标图像的一点在原图像的位置
特效变换采用的是向后映射的方法:已知输出图像上整数点位置(x’,y’)在变换前位于输入图像上的位置(x,y),一般来说这是个非整数点位置,利用其周围整数点位置的输入图像像素值进行插值,就得到了该点的像素值。通过遍历输出图像,经过坐标变换、插值两步操作,即可将每一个像素值计算出来。
(1)扭曲变换公式:
图像围绕一个坐标为(Xc,Yc)的定位点旋转一个随空间变化的旋转角度,这个角度在定位点的值为α,α的值随着与中心径向距离的增加而线性减少。这种效果局限于最大半径为rmax的区域,这个区域以外的像素保持不变。
//扭曲变换函数
void WrapImage(Mat &mapx, Mat &mapy, int width, int height, int alpha)
{
//alpha:离中心定点越远扭曲程度越高
//图像绕(xc,yc)旋转,rmax扭曲范围
float xc = width / 2.0;
float yc = height / 2.0;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
//改变map_x & map_y的值.
float dx = i - xc;
float dy = j - yc;
float r = sqrt(dx*dx + dy*dy);
//double atan2(double y,double x) 返回的是原点至点(x,y)的方位角,即与 x 轴的夹角。
float theta = atan2(dx, dy);
float beta = theta + alpha*((rmax - r) / rmax);
if (r <= rmax)
{
float x = xc + r*cos(beta);
float y = yc + r*sin(beta);
mapx.at(i, j) = static_cast(x);
mapy.at(i, j) = static_cast(y);
}
else
{
mapx.at(i, j) = static_cast(j);
mapy.at(i, j) = static_cast(i);
}
}
}
}
(2)波动变换公式:
图像沿x和y方向产生一个局部波动,映射的参数为(非零)周期长度Lx,Ly以及相关联的振幅值Ax,Ay
//波动变换函数
void WaveImage(Mat &mapx, Mat &mapy, int width, int height, float ax, float ay, float Tx, float Ty)
{
//ax,ay:振幅;Tx,Ty:周期
int i, j;
for (i = 0; i < width; i++)
{
for (j = 0; j < height; j++)
{
float x = i + ax*sin((2 * PI * j) / Tx);
float y = j + ay*sin((2 * PI * i) / Ty);
mapx.at(i, j) = static_cast(y);
mapy.at(i, j) = static_cast(x);
}
}
}
(3)球形变换公式:
当ρ值<0时图像不是球形变换,当ρ值>0时才是球形变换
//球形变换函数
void SphericalImage(Mat &mapx, Mat &mapy, int width, int height, float rho)
{
//定点(xc, yc), rmax变换范围
//要是中间是球形的话需要rho>1
float xc = width / 2.0;
float yc = height / 2.0;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
//改变map_x & map_y的值.
float dx = i - xc;
float dy = j - yc;
float r = sqrt(dx*dx + dy*dy);
float z = sqrt(rmax*rmax - r*r);
float thetax = sqrt(dx*dx + z*z);
float thetay = sqrt(dy*dy + z*z);
float betax = (1 - (1.0 / rho))*asin(dx / (thetax));
float betay = (1 - (1.0 / rho))*asin(dy / (thetay));
if (r <= rmax)
{
float x = i - z*tan(betax);
float y = j - z*tan(betay);
mapx.at(j, i) = static_cast(x);
mapy.at(j, i) = static_cast(y);
}
else
{
mapx.at(i, j) = static_cast(j);
mapy.at(i, j) = static_cast(i);
}
}
}
}
嘻嘻嘻