(opencv)图像几何变换——平移

图像的平移操作是将图像的所有像素坐标进行水平或垂直方向移动,也就是将所有像素点按照给定的偏移量在水平方向沿x轴、垂直方向上沿y轴移动。平移变换分为两种类型:图像大小变化与图像大小不变。第一种类型保证图像平移的完整信息,第二种图像导致原始图像的部分信息可能丢失。图像平移变换公式如下:(不会用csdn自带的公式编辑器,使用mathtype打出来再截图的)

 对4*4图像矩阵向右平移x轴一个单位,向下平移y轴一个单位,若移动后图像的大小保持不变,多余部分填充为白色时满足:

对4*4图像矩阵向左平移x轴一个单位,向上平移y轴一个单位,若移动后图像的大小变换,多余部分填充为白色时满足:

 

举例说明: 

#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;

//平移操作,图像大小不变
Mat imgTranslation1(Mat& src, int xOffset, int yOffset)
{
	int nRows = src.rows;
	int nCols = src.cols;
	Mat result (src.size(), src.type());
	//遍历图像
	for (int i = 0; i < nRows; ++i)
	{
		for (int j = 0; j < nCols; ++j)
		{
			int x = j - xOffset;
			int y = i - yOffset;
			if (x >= 0 && y >= 0 && x < nCols && y < nRows)
			{
				result.at<Vec3b>(i, j) = src.ptr<Vec3b>(y)[x];
			}
		}
	}
	return result;
}

//平移操作,图像大小改变
Mat imgTranslation2(Mat& src, int xOffset, int yOffset)
{
	//设置平移尺寸
	int nRows = src.rows + abs(yOffset);
	int nCols = src.cols + abs(xOffset);
	Mat result(nRows,nCols, src.type());
	//遍历图像
	for (int i = 0; i < nRows; ++i)
	{
		for (int j = 0; j < nCols; ++j)
		{
			//映射变换
			int x = j - xOffset;
			int y = i - yOffset;
			if (x >= 0 && y >= 0 && x < nCols && y < nRows)
			{
				result.at<Vec3b>(i, j) = src.ptr<Vec3b>(y)[x];
			}
		}
		
	}
	return result;
}
int main()
{
	Mat src = imread("C:\\Users\\32498\\Pictures\\16.png");
	if (!src.data)
	{
		return -1;
	}
	imshow("src", src);
	int xOffset = 50, yOffset = 80;
	//图像左平移不改变大小
	Mat dst1 = imgTranslation1(src, xOffset, yOffset);
	imshow("dst1", dst1);
	//图像左平移改变大小
	Mat dst2 = imgTranslation2(src, xOffset, yOffset);
	imshow("dst2", dst2);
	//图像右平移不改变大小
	Mat dst3 = imgTranslation1(src, -xOffset, -yOffset);
	imshow("dst3", dst3);
	waitKey();
	return 0;

}

运行结果如下: 

 

 对程序中的此行代码进行说明

result.at<Vec3b>(i, j) = src.ptr<Vec3b>(y)[x];

result图像(i,j)处的像素值等于src图像第y行,第x个坐标的像素值。这其实是对图像进行逐像素操作。

 ①opencv中的Mat数据类型指针ptr的使用

    cv::Mat image = cv::Mat(400, 600, CV_8UC1); //宽400,长600
    uchar * data00 = image.ptr<uchar>(0);
    uchar * data10 = image.ptr<uchar>(1);
    uchar * data01 = image.ptr<uchar>(0)[1];

        对上面的注解:(注意看这些的区别)

定义一个Mat变量image,

data00是指向image第一行第一个元素的指针

data10是指向image第二行第一个元素的指针

data01是指向image第一行第二个元素的指针 

②Vec3b类型的含义

Vec3b可以看作是vector<uchar,3>,即一个uchar类型,长度为3的vector向量。(不知道vector容器含义的同学可以这样理解vector,它就是一个数组,只不过这个数组的大小可以随时改变,故称vector为动态数组)

由于在opencv中读取到的Mat图像数据都是用uchar类型的数据存储,对于RGB三通道的图像,每个点的数据都是一个vec3b类型的数据。

使用at定位方法如下:

Mat img=imread("123.png");

//(row,col)为所需要定位点的坐标
img.at<Vec3b>(row,col)[0]=255; //修改点(row,col)的B通道数据
img.at<Vec3b>(row,col)[1]=255; //修改点(row,col)的G通道数据
img.at<Vec3b>(row,col)[2]=255; //修改点(row,col)的R通道数据


 同时还需要注意的是,它返回的是uchar类型,直接使用cout输出为字符格式,需要强制转换为int 类型之后输出:


cout<<(int)img.at<Vec3b>(row,col)[0];

猜你喜欢

转载自blog.csdn.net/yangSHU21/article/details/131139829