opencv版本:opencv3.4.1
目录
1. 图像翻转(坐标映射)
2. 平移
3. 缩放
4. 旋转
int main()
{
cv::Mat srcImage = cv::imread("./lena.jpg");
if(!srcImage.data){
return -1;
}
int rows = srcImage.rows;
int cols = srcImage.cols;
//输出矩阵定义
cv::Mat resultImage(rows, cols, srcImage.type());
//x与y方向的矩阵
cv::Mat xMapImage(rows, cols, CV_32FC1);
cv::Mat yMapImage(rows, cols, CV_32FC1);
//图像遍历
for(int r = 0; r < rows; r++){
for(int c = 0; c < cols; c++){
//x与y均翻转
xMapImage.at(r,c) = cols-c;
yMapImage.at(r,c) = rows-r;
}
}
remap(srcImage, resultImage, xMapImage, yMapImage, CV_INTER_LINEAR, cv::BORDER_CONSTANT,Scalar(0,0,0));
cv::imwrite("resultImage.jpg", resultImage);
}
效果:
有两种情况,(a)平移时图像大小保持不变; (b)平移时图像大小变化;
//平移不改变图像
//参数:平移的图像,平移的x和y偏移量;
cv::Mat imageTranslateNoChange(cv::Mat &srcImage, int xOffset, int yOffset)
{
int nRows = srcImage.rows;
int nCols = srcImage.cols;
cv::Mat resultImage(nRows, nCols, srcImage.type());
//遍历图像
for(int r = 0 ; r < nRows; r++){
for(int c = 0; c < nCols; c++){
int x = c - xOffset;
int y = r - yOffset;
//边界判断;
if(x >= 0 && y >= 0 && x < nCols && y < nRows){
resultImage.at(r, c) = srcImage.ptr(y)[x];
}
}
}
return resultImage;
}
//平移,会改变图像
cv::Mat imageTranslateChange(cv::Mat &srcImage, int xOffset, int yOffset)
{
int nRows = srcImage.rows + abs(yOffset);//加上y
int nCols = srcImage.cols + abs(xOffset);//加上x
cv::Mat resultImage(nRows, nCols, srcImage.type());
//遍历图像
for(int r = 0 ; r < nRows; r++){
for(int c = 0; c < nCols; c++){
int x = c - xOffset;
int y = r - yOffset;
//边界判断;
if(x >= 0 && y >= 0 && x < nCols && y < nRows){
resultImage.at(r, c) = srcImage.ptr(y)[x];
}
}
}
return resultImage;
}
int main()
{
cv::Mat srcImage = cv::imread("./lena.jpg");
if(!srcImage.data){
return -1;
}
//cv::Mat resultImage = imageTranslateNoChange(srcImage, 200, 50);
//cv::imwrite("translateNoChange.jpg", resultImage);
cv::Mat resultImage = imageTranslateChange(srcImage, 80, 80);
cv::imwrite("translateChange.jpg", resultImage);
return 0;
}
效果:
//等间隔提取图像缩放
cv::Mat imageEquidistant(cv::Mat& srcImage, float kx, float ky)
{
//获取输出图像分辨率
int nRows = cvRound(srcImage.rows * kx);
int nCols = cvRound(srcImage.cols * ky);
cv::Mat resultImage(nRows, nCols, srcImage.type());
for(int i = 0; i < nRows; ++i){
for(int j = 0; j < nCols; ++j){
//根据水平因子计算坐标
int x = static_cast((i+1)/kx+0.5)-1;
//根据垂直因子计算坐标
int y = static_cast((j+1)/ky+0.5)-1;
resultImage.at(i, j) = srcImage.at(x,y);
}
}
return resultImage;
}
static cv::Vec3b areaAverage(cv::Mat& srcImage, Point_ leftPoint, Point_ rightPoint)
{
int temp1 = 0, temp2=0, temp3=0;
//计算区域子块像素点个数
int nPix = (rightPoint.x - leftPoint.x) * (rightPoint.y - leftPoint.y);
//对区域子块各个通道对像素求和
for(int i = leftPoint.x; i < rightPoint.x ;++i){
for(int j = leftPoint.y; j < rightPoint.y; ++j){
temp1 += srcImage.at(i,j)[0];
temp2 += srcImage.at(i,j)[1];
temp3 += srcImage.at(i,j)[2];
}
}
//对每个通道求均值
Vec3b vecTemp;
vecTemp[0] = temp1 / nPix;
vecTemp[1] = temp2 / nPix;
vecTemp[2] = temp3 / nPix;
return vecTemp;
}
//基于子块提取图像缩放
cv::Mat imageRegionSubBlock(cv::Mat& srcImage, double kx, double ky)
{
//获取输出图像分辨率
int nRows = cvRound(srcImage.rows * kx);
int nCols = cvRound(srcImage.cols * ky);
cv::Mat resultImage(nRows, nCols, srcImage.type());
//区域子块的左上角行列坐标
int leftRowCoordinate = 0;
int leftColCoordinate = 0;
for(int i = 0; i < nRows; ++i){
//根据水平因子计算坐标
int x = static_cast((i+1)/kx+0.5)-1;
for(int j = 0; j < nCols; ++j){
//根据垂直因子计算坐标
int y = static_cast((j+1)/ky+0.5)-1;
//求解区域子块的均值;
resultImage.at(i, j) = areaAverage(srcImage,Point_(leftRowCoordinate,leftColCoordinate),Point_(x,y));
//更新子块左上角的列坐标
leftColCoordinate = y + 1;
}
leftColCoordinate = 0;
//更新子块左上角的行坐标
leftRowCoordinate = x + 1;
}
return resultImage;
}
int main()
{
cv::Mat srcImage = cv::imread("./lena.jpg");
if(!srcImage.data){
return -1;
}
cv::Mat resultImage;
//resultImage = imageEquidistant(srcImage, 0.5, 0.5);
resultImage = imageRegionSubBlock(srcImage, 0.5, 0.5);
cv::imwrite("RegionSubBlock.jpg", resultImage);
return 0;
}
效果:
cv::Mat imageRotate(cv::Mat& srcImage, int angle)
{
//角度转换
float alpha = angle * CV_PI / 180;
//构造旋转矩阵
float rotateMat[3][3] = {
{cos(alpha), -sin(alpha), 0},
{sin(alpha), cos(alpha), 0},
{0 , 0, 1}
};
int nSrcRows = srcImage.rows;
int nSrcCols = srcImage.cols;
//计算旋转后图像矩阵的各个顶点位置
float a1 = nSrcCols * rotateMat[0][0] ;
float b1 = nSrcCols * rotateMat[1][0] ;
float a2 = nSrcCols * rotateMat[0][0] + nSrcRows * rotateMat[0][1];
float b2 = nSrcCols * rotateMat[1][0] + nSrcRows * rotateMat[1][1];;
float a3 = nSrcRows * rotateMat[0][1] ;
float b3 = nSrcRows * rotateMat[1][1] ;
int kxMin = min(min(min(0.0f,a1),a2),a3);
int kxMax = max(max(max(0.0f,a1),a2),a3);
int kyMin = min(min(min(0.0f,b1),b2),b3);
int kyMax = max(max(max(0.0f,b1),b2),b3);
//计算输出矩阵的尺寸
int nRows = abs(kxMax - kxMin);
int nCols = abs(kyMax - kyMin);
cv::Mat dst(nRows, nCols, srcImage.type(), cv::Scalar::all(0));
for(int i = 0; i < nRows; ++i){
for(int j = 0 ; j < nCols; ++j){
//旋转坐标转换
int x = (j + kxMin) * rotateMat[0][0] - (i + kyMin) * rotateMat[0][1];
int y = -(j + kxMin) * rotateMat[1][0] + (i + kyMin) * rotateMat[1][1];
//区域旋转
if((x >= 0) && (x < nSrcCols) && (y >= 0) && y < nSrcRows){
dst.at(i, j) = srcImage.at(y,x);
}
}
}
return dst;
}
4.1 旋转30和60度;
int main()
{
cv::Mat srcImage = cv::imread("./lena.jpg");
if(!srcImage.data){
return -1;
}
cv::Mat resultImage;
//resultImage = imageRotate(srcImage,30);
resultImage = imageRotate(srcImage,60);
cv::imwrite("rotate60.jpg", resultImage);
return 0;
}
效果:
图像翻转是图像旋转的特例,opencv中提供了traspose与filp函数对图像进行矩阵转置变换;可以将图像进行水平或垂直翻转;
4.2 图像翻转
int main()
{
cv::Mat srcImage = cv::imread("./lena.jpg");
if(!srcImage.data){
return -1;
}
cv::Mat resultImage;
//transpose(srcImage, resultImage);//逆时针旋转90;
//flip( srcImage, resultImage, 0); //垂直翻转
//flip( srcImage, resultImage, 1); //水平翻转
//flip( srcImage, resultImage, -1);//垂直和水平翻转
cv::imwrite("flip-1.jpg", resultImage);
return 0;
}
效果:
5. 仿射变换
int main()
{
cv::Mat srcImage = cv::imread("./lena.jpg");
if(!srcImage.data){
return -1;
}
int nRows = srcImage.rows;
int nCols = srcImage.cols;
//定义仿射变换的二维点数组
//源图像和目标图像对应映射的三个点
cv::Point2f srcPoint[3];
cv::Point2f resPoint[3];
srcPoint[0] = cv::Point2f(0, 0);
srcPoint[1] = cv::Point2f(nCols-1, 0);
srcPoint[2] = cv::Point2f(0,nRows-1);
resPoint[0] =cv::Point2f(nCols*0, nRows*0.33);
resPoint[1] =cv::Point2f(nCols*0.85, nRows*0.25);
resPoint[2] =cv::Point2f(nCols*0.15, nRows*0.7);
//定义仿射变换矩阵
cv::Mat warpMat(cv::Size(2,3), CV_32F);
cv::Mat resultImage;
cv::Mat::zeros(nRows, nCols, srcImage.type());
//计算仿射变换矩阵,即仿射变换的2x3数组
warpMat = cv::getAffineTransform(srcPoint, resPoint);
//根据仿射矩阵计算图像仿射变换
cv::warpAffine(srcImage, resultImage, warpMat, cv::Size(resultImage.rows,resultImage.cols));
cv::imwrite("warpAffine.jpg", resultImage);
#if 1
//设置仿射变换参数
cv::Point2f centerPoint = cv::Point2f(nCols/2, nRows/2);
double angle = -50;
double scale = 0.7;
//获取仿射变换矩阵
warpMat = getRotationMatrix2D(centerPoint, angle, scale);
//对源图像进行角度仿射变换
cv::warpAffine(srcImage, resultImage, warpMat, cv::Size(resultImage.rows,resultImage.cols));
#endif
cv::imwrite("warpAffine-angle.jpg", resultImage);
return 0;
}
效果: