【OpenCV】图像的特效变换

使用到的函数:

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 – 双线性插值(默认值)

  1. borderMode(边界模式):有默认值BORDER_CONSTANT,表示目标图像中“离群点(outliers)”的像素值不会被此函数修改。
  2. 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<float>(i, j) = static_cast<float>(x);
				mapy.at<float>(i, j) = static_cast<float>(y);
			}
			else
			{
				mapx.at<float>(i, j) = static_cast<float>(j);
				mapy.at<float>(i, j) = static_cast<float>(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<float>(i, j) = static_cast<float>(y);
			mapy.at<float>(i, j) = static_cast<float>(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<float>(j, i) = static_cast<float>(x);
				mapy.at<float>(j, i) = static_cast<float>(y);
			}
			else
			{
				mapx.at<float>(i, j) = static_cast<float>(j);
				mapy.at<float>(i, j) = static_cast<float>(i);
			}

		}
	}
}

图像特效变换课程设计代码(带滚动条)下载地址:https://download.csdn.net/download/qq_42417182/10931603

猜你喜欢

转载自blog.csdn.net/qq_42417182/article/details/86590505