一.简介

图像的几何变换有距离变换 坐标映射 平移  镜像 旋转  缩放  仿射变换等

二.重映射

把一张图像重新排列像素,比如倒置

CV_EXPORTS_W void remap( InputArray src, OutputArray dst,

InputArray map1, InputArray map2,

int interpolation, int borderMode=BORDER_CONSTANT,

const Scalar& borderValue=Scalar());

  • src

    源图像
  • dst
    目标图像
  • map1
    x坐标
  • map2
    y坐标
  • interpolation
    表示插值方法
  • borderMode
    表示边界插值类型
  • borderValue

   表示插值数值

#include <iostream>
#include "opencv2/opencv.hpp" using namespace std; int main(int argc, char* argv[]) { cv::Mat srcImage = cv::imread("a.jpg");
if(!srcImage.data)
return -1; // 输出矩阵
cv::Mat resultImage(srcImage.size(), srcImage.type()); // x与y方向矩阵
cv::Mat xMapImage(srcImage.size(), CV_32FC1);
cv::Mat yMapImage(srcImage.size(), CV_32FC1); // 取图像的宽高
int rows = srcImage.rows;
int cols = srcImage.cols; // 图像遍历
for( int j = 0; j < rows; j++ )
{
for( int i = 0; i < cols; i++ )
{ //x与y均翻转
xMapImage.at<float>(j,i) = cols - i;
yMapImage.at<float>(j,i) = rows - j;
}
} // 重映射操作
remap(srcImage, resultImage, xMapImage, yMapImage, CV_INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0,0,0)); // 输出结果
cv::imshow("srcImage", srcImage);
cv::imshow("resultImage", resultImage); cv::waitKey(0); return 0; }

三.平移

图像的平移操作是将图像的所有像素坐标进行水平或垂直方向移动

//图像平移并且图像大小不变和改变

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream> // 平移操作 图像大小不变
cv::Mat imageTranslation1(cv::Mat& srcImage,int xOffset,int yOffset)
{ int nRows = srcImage.rows;
int nCols = srcImage.cols; cv::Mat resultImage(srcImage.size(), srcImage.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)
resultImage.at<cv::Vec3b>(i,j) = srcImage.ptr<cv::Vec3b>(y)[x];
}
}
return resultImage;
} // 平移操作,图像大小改变
cv::Mat imageTranslation2(cv::Mat& srcImage, int xOffset, int yOffset)
{ // 设置平移尺寸
int nRows = srcImage.rows + abs(yOffset);
int nCols = srcImage.cols + abs(xOffset); cv::Mat resultImage(nRows, nCols, srcImage.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)
resultImage.at<cv::Vec3b>(i,j) = srcImage.ptr<cv::Vec3b>(y)[x];
}
}
return resultImage;
} int main()
{ // 图像读取及判定是否正确读入
cv::Mat srcImage = cv::imread("a.jpg");
if(!srcImage.data)
return -1; cv::imshow("srcImage", srcImage);
int xOffset = 50, yOffset = 80; // 图像左平移不改变大小
cv::Mat resultImage1 = imageTranslation1(srcImage, xOffset, yOffset);
cv::imshow("resultImage1", resultImage1); // 图像左平移改变大小
cv::Mat resultImage2 = imageTranslation2(srcImage, xOffset, yOffset);
cv::imshow("resultImage2", resultImage2); //图像右平移不改变大小
xOffset = -50, yOffset = -80;
cv::Mat resultImage3 = imageTranslation1(srcImage, xOffset, yOffset);
cv::imshow("resultImage3", resultImage3); cv::waitKey(0);
return 0;
}

四.缩放

图像缩放会减少或增加图像数据的像素个数,造成信息的丢失

1.基于等间隔提取图像缩放

等间隔提取图像缩放是通过对源图像进行均匀采样来完成的

2.基于区域子块提取图像缩放

区域子块提取图像缩放是通过对源图像进行区域子块划分,然后提取子块中像素值作为采样像素以构成新图像来完成

提取子块像素值常用的有计算子块像素的中值和计算子块像素的均值

对源图像的区域划分也有根据缩放因子等比例提取子块和自适应因子提取子块

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream> using namespace cv; // 基于等间隔提取图像缩放
cv::Mat imageReduction1(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<int>((i + 1) / kx + 0.5) - 1;
// 根据垂直因子计算坐标
int y = static_cast<int>((j + 1) / ky + 0.5) - 1;
resultImage.at<cv::Vec3b>(i, j) = srcImage.at<cv::Vec3b>(x, y);
}
}
return resultImage;
} cv::Vec3b areaAverage(const cv::Mat& srcImage,Point_<int> leftPoint, Point_<int> rightPoint)
{
int temp1 = 0, temp2 = 0, temp3 = 0;
// 计算区域子块像素点个数
int nPix = (rightPoint.x - leftPoint.x + 1) * (rightPoint.y - leftPoint.y + 1);
// 区域子块各个通道对像素值求和
for (int i = leftPoint.x; i <= rightPoint.x; i++){
{
for (int j = leftPoint.y; j <= rightPoint.y; j++)
{ temp1 += srcImage.at<cv::Vec3b>(i, j)[0];
temp2 += srcImage.at<cv::Vec3b>(i, j)[1];
temp3 += srcImage.at<cv::Vec3b>(i, j)[2];
}
} // 对每个通道求均值
Vec3b vecTemp;
vecTemp[0] = temp1 / nPix;
vecTemp[1] = temp2 / nPix;
vecTemp[2] = temp3 / nPix; return vecTemp;
} } cv::Mat imageReduction2(const 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<int>((i + 1) / kx + 0.5) - 1;
for (int j = 0; j < nCols; ++j)
{
// 根据垂直因子计算坐标
int y = static_cast<int>((j + 1) / ky + 0.5) - 1;
// 求解区域子块的均值
resultImage.at<Vec3b>(i, j) = areaAverage(srcImage, Point_<int>(leftRowCoordinate, leftColCoordinate), Point_<int>(x, y));
// 更新下子块左上角的列坐标,行坐标不变
leftColCoordinate = y + 1;
}
leftColCoordinate = 0;
// 更新下子块左上角的行坐标
leftRowCoordinate = x + 1;
} return resultImage;
} int main()
{ cv::Mat srcImage = cv::imread("a.jpg");
if (!srcImage.data)
return -1;
cv::imshow("srcImage", srcImage); cv::Mat resultImage1 = imageReduction1(srcImage, 0.5, 0.5);
cv::imshow("res1", resultImage1); cv::Mat resultImage2 = imageReduction2(srcImage, 0.5, 0.5);
cv::imshow("res2", resultImage2); cv::waitKey(0);
return 0;
}

五.旋转

1.角度旋转

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <cmath> using namespace cv;
using namespace std; cv::Mat angleRotate(cv::Mat& src, 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 = src.rows;
int nSrcCols = src.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]; // 计算出极值点
float kxMin = min( min( min(0.0f, a1), a2), a3);
float kxMax = max( max( max(0.0f, a1), a2), a3);
float kyMin = min( min( min(0.0f, b1), b2), b3);
float kyMax = max( max( max(0.0f, b1), b2), b3); // 计算输出矩阵的尺寸
int nRows = abs(kxMax - kxMin);
int nCols = abs(kyMax - kyMin);
cv::Mat dst(nRows, nCols, src.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<cv::Vec3b>(i, j) = src.at<cv::Vec3b>(y, x);
}
}
}
return dst;
} int main()
{
cv::Mat srcImage = cv::imread("a.jpg");
if (!srcImage.data)
return -1;
cv::imshow("srcImage", srcImage);
int angle = 30;
cv::Mat resultImage = angleRotate(srcImage, angle);
imshow("resultImage", resultImage);
cv::waitKey(0);
return 0;
}

2.直接翻转

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <cmath> using namespace cv;
using namespace std; int main()
{ cv::Mat srcImage = cv::imread("a.jpg");
if (!srcImage.data)
return -1; // 逆时针旋转90度
cv::Mat resultImage1;
transpose(srcImage, resultImage1); // 水平翻转
cv::Mat resultImage2;
flip(resultImage1, resultImage2, 1); // 垂直翻转
cv::Mat resultImage3;
flip(resultImage1, resultImage3, 0); // 垂直和水平翻转
cv::Mat resultImage4;
flip(srcImage, resultImage4, -1); cv::imshow("srcImage", srcImage);
cv::imshow("resultImage1", resultImage1);
cv::imshow("resultImage2", resultImage2);
cv::imshow("resultImage3", resultImage3);
cv::imshow("resultImage4", resultImage4); cv::waitKey(0);
return 0;
}

六.仿射变换

OpenCV2:第六章 图像几何变换的更多相关文章

  1. OpenCV2:第十一章 图像转换

    一.简介 二.例子 #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #inclu ...

  2. 【数字图像处理】六.MFC空间几何变换之图像平移、镜像、旋转、缩放具体解释

    本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行解说,主要通过MFC单文档视图实现显示BMP图片空间几何变换.包含图像平移.图形 ...

  3. 精通Web Analytics 2.0 (8) 第六章:使用定性数据解答”为什么“的谜团

    精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第六章:使用定性数据解答"为什么"的谜团 当我走进一家超市,我不希望员工会认出我或重新为我布置商店. 然而, ...

  4. Laxcus大数据管理系统2.0(8)- 第六章 网络通信

    第六章 网络通信 Laxcus大数据管理系统网络建立在TCP/IP网络之上,从2.0版本开始,同时支持IPv4和IPv6两种网络地址.网络通信是Laxcus体系里最基础和重要的一环,为了能够利用有限的 ...

  5. Android群英传》读书笔记 (3) 第六章 Android绘图机制与处理技巧 + 第七章 Android动画机制与使用技巧

    第六章 Android绘图机制与处理技巧 1.屏幕尺寸信息屏幕大小:屏幕对角线长度,单位“寸”:分辨率:手机屏幕像素点个数,例如720x1280分辨率:PPI(Pixels Per Inch):即DP ...

  6. 第十六章——处理锁、阻塞和死锁(3)——使用SQLServer Profiler侦测死锁

    原文:第十六章--处理锁.阻塞和死锁(3)--使用SQLServer Profiler侦测死锁 前言: 作为DBA,可能经常会遇到有同事或者客户反映经常发生死锁,影响了系统的使用.此时,你需要尽快侦测 ...

  7. Android群英传笔记——第六章:Android绘图机制与处理技巧

    Android群英传笔记--第六章:Android绘图机制与处理技巧 一直在情调,时间都是可以自己调节的,不然世界上哪有这么多牛X的人 今天就开始读第六章了,算日子也刚好一个月了,一个月就读一半,这效 ...

  8. 第六章P2P技术及应用

    第六章P2P技术及应用 P2P技术在我们日常生活中非常实用,例如我们常用的QQ.PPLive.BitTorrent就是基于P2P技术研发.下面将本章中的重点内容进行归纳. 文章中的Why表示产生的背景 ...

  9. o'Reill的SVG精髓(第二版)学习笔记——第六章

    第六章:坐标系统变换 想要旋转.缩放或者移动图片到新的位置.可以给对应的SVG元素添加transform属性. 6.1 translate变换 可以为<use>元素使用x和y属性,以在特性 ...

随机推荐

  1. Unity网格合并_材质合并[转]

    http://blog.csdn.net/chenggong2dm/article/details/41699029

  2. 3DMAX 合并镜像物体

    如果镜像文件是实例,那么就不能用附加选项,所以可以先删除一半,再copy镜像出来,然后点选可编辑网格,在一个物体上选附加,再点选另一半即可

  3. Luogu P2170选学霸【并查集+背包】By cellur925

    题目传送门 开始看到本题完全认为就是个彻头彻尾的并查集,只要把实力相当的人都并到一个集合中,最后再找一共有多少联通块即可. 后来发现这是大错特错的qwq.因为选了一个集合中的某人,那这个集合中所有人就 ...

  4. TensorFlow多线程输入数据处理框架(三)——组合训练数据

    参考书 <TensorFlow:实战Google深度学习框架>(第2版) 通过TensorFlow提供的tf.train.batch和tf.train.shuffle_batch函数来将单 ...

  5. AForge.net简介和认识

    AForge.NET是一个专门为开发者和研究者基于C#框架设计的,他包括计算机视觉与人工智能,图像处理,神经网络,遗传算法,机器学习,模糊系统,机器人控制等领域.这个框架由一系列的类库组成.主要包括有 ...

  6. iOS 在UITextView中查找某个Range所在的Rect

    代码如下(Swift 4): extension UITextView { /// 查找文本范围所在的矩形范围 /// /// - Parameter range: 文本范围 /// - Return ...

  7. visual studio各版本下载

    软件包括以下几种: cn_visual_studio_2010_ultimate_x86_dvd_532347.part1.rar cn_visual_studio_2010_ultimate_x86 ...

  8. bzoj 4456 [Zjoi2016]旅行者

    题面 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 题解 分治 设当前work的区间为(x1,y1,x2,y2) 我们将长边分成两半 不妨 ...

  9. AtCoder Grand Contest 017 B

    B - Moderate Differences Time limit : 2sec / Memory limit : 256MB Score : 400 points Problem Stateme ...

  10. h5-15-svg格式图片

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...