OpenCV中flip函数实现

一、flip()函数原型介绍

void cv::flip(InputArray src,OutputArray dst, int flipCode)
各参数含义
src:输入图像。
dst:输出图像。
flip:翻转方式标志。数值大于0,表示绕y轴进行翻转;数值等于0,表示绕x轴进行翻转;数值小于0,表示绕两个轴翻转。
以上就是OpenCV中flip()函数的原型,函数的功能和参数都比较简单,就是实现对图像进行一个翻转功能,得到翻转后的图像。

二、二维图形的几何变换

若我们不使用flip()函数如何实现图像的翻转。首先就必须了解二维图像的几何变换。使用齐次坐标表示点的变换非常方便。下面说明在实现图像翻转过程中使用的二维齐次坐标变换矩阵。
二维齐次坐标变换矩阵为3*3的矩阵,其形式为:

在这里插入图片描述
该矩阵中每个元素都有特殊含义。其中,2*2矩阵{a,b;c,d}可以对图像进行缩放、旋转、对称、和错切等变换;[c f]^T对图像进行平移变换;[g h]则是对图像进行投影变换;[i]则是对图像整体进行缩放变化。要实现图像的翻转,需要对图像进行对称变换和平移变换。只需要用到a,b,c,d,e,f六个元素。我们根据变换矩阵对平移变换和对称变换进行讨论,暂不涉及其它变换。
设对像素点P0(y0,x0)进行变换后得到的坐标为(y1,x1).
1:平移变换
以图像左上角为坐标原点对像素点P0(y0,x0)向y方向平移ty个像素单位,向x方向平移tx个像素单位。x1,y1表示平移后的坐标。则点P0与变换矩阵之间的计算为:
注:在下文中始终以图像或矩阵左上角作为坐标原点
在这里插入图片描述
2:对称变换

在这里插入图片描述
对称变换其实只是a,b,d,e取0、1、-1等这些特殊值产生的一些特殊效果。例如:
(1) 当b=d=0,a=-1,e=1时,有x1=-x0,y1=y0,产生与y轴对称的图形;
(2) 当b=d=0,a=1,e=-1时,有x1=x0,y1=-y0,产生与x轴对称的图形;
(3) 当b=d=0,a=e=-1时,有x1=-x0,y1=-y0,产生与原点对称的图形;
(4) 当b=d=1,a=e=0时,有x1=y0,y1=x0,产生与直线y=x对称的图形;

三、自定义flip函数的思路

图像由一个个像素组成,这些像素就形成了以像素为基本单位的二维矩阵。将图像进行翻转就是将这个二维矩阵进行翻转。我们先在一个大小为rows*cols矩阵A对元素p(y,x)进行关于x轴翻转的变换形成矩阵B。在关于x轴对称变换过程中x值保持不变,y值变为原值的相反数。在矩阵B中不存在坐标为(-y,x)的点,需要进行一个平移操作,将点向y轴方向平移rows个单位。得到点p(y,x)关于x轴翻转后对应坐标为(-y+rows,x)的点。确定好翻转后的坐标,最后进行赋值B[-y+rows][x]=A[y][x],就完成了这一个元素关于x轴的翻转。
在这里插入图片描述
对矩阵A的每一个元素都进行如上操作就可以实现矩阵A关于x轴的翻转得到矩阵B。

三、算法代码

#define xsymmetry 0//x轴对称
#define ysymmetry 1//y轴对称
#define xysymmetry -1//先以x对称,再以y轴对称

void coordinateTransform(int x0, int y0, int &x1, int &y1, int transformType, int x_offset, int y_offset)
{/*x0,y0为原图像中某一像素点的坐标
 *x1,y1,为图像像素点(y,x)经过类型为transformType的变换后对应的坐标
 *x_offset,y_offset分别为x(横)方向,y(纵)方向的偏移量
 */

	if (transformType == xsymmetry)
	{//x对称变换
		x1 = x0;
		y1 = -y0 + y_offset;
	}
	else if (transformType == ysymmetry)
	{//y对称变换
		x1 = -x0 + x_offset;
		y1 = y0;
	}
	else if (transformType == xysymmetry)
	{//先x轴再y轴对称(原点对称)
		x1 = -x0 + x_offset;
		y1 = -y0 + y_offset;
	}
}

void myFlip(const InputArray &src, OutputArray &dst, int symmetryType)
{
	int dataType = src.type();
	vector<Mat> imgs;
	vector<Mat> imgs1;
	split(src, imgs);//先将初始图像进行通道分离

	//图像的宽度和高度
	int width = imgs[0].cols;
	int height = imgs[0].rows;
	int type = imgs[0].type();
	int x, y;//原图像中像素点的坐标,(以图像左上角为原点)
	int x1, y1;//像素点(y,x)变换后对应的坐标
	for (int t = 0;t < src.channels();t++)
	{
	    //定义一个与输入图像src大小一致的Mat变量用于保存翻转后单个通道形成的图像
		Mat tempImg(Size(width,height),type);
		for (y = 0;y < height;y++)
		{
			for (x = 0;x < width;x++)
			{
				coordinateTransform(x, y, x1, y1, symmetryType, width, height);

				*(tempImg.data + tempImg.step[0] * y + tempImg.step[1] * x) =
					*(imgs[t].data + imgs[t].step[0] * y1 + imgs[t].step[1] * x1);
			}
		}

		imgs1.push_back(tempImg);
	}
	merge(imgs1, dst);//合并通道
}

多通道图像先进行通道分离,再对每个通道都要进行翻转变换,最后合并成翻转后的完整图像。
直接使用像素坐标进行元素访问,避免了对Mat变量类型的讨论。其它访问Mat元素的方式都需要明确数据类型。

四、自定义函数与库函数flip()的效果对比

int main()
{
	Mat img = imread("../lena.png", IMREAD_GRAYSCALE);
	Mat img0 = imread("../lena.png");
	if (img.empty())
	{
		cout << "打开图像文件失败,请确认文件名称是否正确" << endl;
		return -1;
	}

	Mat img_x, img_y, img_xy;//灰度图像
	Mat img_x0, img_y0, img_xy0;//彩色图像

    //
	Mat myimg_x, myimg_y, myimg_xy;//灰度图像
	Mat myimg_x0, myimg_y0, myimg_xy0;//彩色图像

	//灰度图像的翻转操作
	flip(img, img_x, 0);
	flip(img, img_y, 1);
	flip(img, img_xy, -1);
	myFlip(img, myimg_x, 0);
	myFlip(img, myimg_y, 1);
	myFlip(img, myimg_xy, -1);

	//彩色图像的翻转操作
	flip(img0, img_x0, 0);//翻转 x轴对称
	flip(img0, img_y0, 1);//翻转 y轴对称
	flip(img0, img_xy0, -1);//翻转 先x轴对称再y轴对称
	myFlip(img0, myimg_x0, 0);//翻转 x轴对称
	myFlip(img0, myimg_y0, 1);//翻转 x轴对称
	myFlip(img0, myimg_xy0, -1);//翻转 x轴对称

	//灰度图像的显示
	imshow("img", img);
	imshow("myimg_x", myimg_x);
	imshow("myimg_y", myimg_y);
	imshow("myimg_xy", myimg_xy);
	imshow("img_x", img_x);
	imshow("img_y", img_y);
	imshow("img_xy", img_xy);

	//彩色图像显示
	imshow("img0", img0);
	imshow("img_x0", img_x0);
	imshow("myimg_x0", myimg_x0);
	imshow("myimg_y0", myimg_y0);
	imshow("myimg_xy0", myimg_xy0);
	imshow("img_y0", img_y0);
	imshow("img_xy0", img_xy0);

	waitKey();
	return 0;
}

原灰度图和原彩色图
在这里插入图片描述

关于x轴翻转后的图像灰度图像(以my开头的是自定义函数myFlip()的测试效果)
在这里插入图片描述

关于x轴翻转再关于y轴翻转后的彩色图像(以my开头的是自定义函数myFlip()的测试效果)
在这里插入图片描述
效果一致,测试成功。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zmq1998

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值