图像镜像变换分为水平镜像和竖直镜像。水平镜像是将图像左半部分和右半部分以图像竖直中轴线为中心轴进行兑换;而竖直镜像是将上半部分和下半部分以图像水平中轴线为中心轴进行兑换,如下图所示,

   下面是代码实现


int main(){
#pragma region 镜像处理
/*	Mat image = imread("T1.jpg");
	Mat src=image.clone();
	namedWindow("initial");
	imshow("initial",image);
	waitKey(0);
	int W=image.cols;
	int L=image.rows;

	Vec3b temp;
	//竖直镜像
	for (int x=0;x<W;x++)
	{
		//下面两种变换方法的不同之处在于
		//变换方法一
// 		for (int y1=0,y2=L-1;y2-y1>0;y1++,y2--)
// 		{
// 			temp = image.at<Vec3b>(y1,x);
// 			image.at<Vec3b>(y1,x)=image.at<Vec3b>(y2,x);
// 			image.at<Vec3b>(y2,x)=temp;
// 		}
		//变换方法二
		for (int y1=0,y2=L-1;y1<=y2/2;y1++)
		{
			temp = image.at<Vec3b>(y1,x);
			image.at<Vec3b>(y1,x)=image.at<Vec3b>(y2-y1,x);
			image.at<Vec3b>(y2-y1,x)=temp;
		}
	}
	namedWindow("竖直镜像");
	imshow("竖直镜像",image);
	waitKey(0);

	//水平镜像
	imshow("src",src);
	waitKey(0);
	for (int y=0;y<L;y++)
	{
		for (int x1=0,x2=W-1;x1<x2;x1++,x2--)
		{
			temp=src.at<Vec3b>(y,x1);
			src.at<Vec3b>(y,x1)=src.at<Vec3b>(y,x2);
			src.at<Vec3b>(y,x2)=temp;
		}
	}
	namedWindow("水平镜像");
	imshow("水平镜像",src);
	waitKey(0);

	system("pause");
	return 0;
}
   需要注意的是,图像中点的坐标是从0开始的,在表示图像点的坐标范围以及确定变换中轴线时,都要注意这一点。在竖直镜像变换时,变换是按列进行的,使用了两种变换方法,两种方法的不同在于确定中轴线的方式和下半部分坐标的的表示方式的差别。


   第一种方法是分别为上半部分和下半部分定义一个变量表示y坐标,分别是从0递增和从最后一个点递减,当表示上半部分的y坐标大于下半部分的时候,说明到达了中轴线,停止变换。

   第二种方法是,先确定中轴线,但是奇数个点和偶数个点的中轴线是不同的。假设y1表示列起始点的y坐标,y2表示一列最后一个点的y坐标,用y2/2表示中轴线,当点数为奇数时中轴线时正确的,而当点数是偶数时确定的中轴线时错误的。为了弥补这种错误,在第二种方法中,在变换过程中使用y2-y1确定下半部分要变换的点的位置。