图像的平移操作是将图像的所有像素坐标进行水平或垂直方向移动,也就是将所有像素点按照给定的偏移量在水平方向沿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];