OpenCV和C++实现图像的翻转(镜像)、平移、旋转、仿射与透视变换

目录
  • 一、翻转(镜像)
  • 二、仿射扭曲
    • 获取变换矩阵
    • 仿射扭曲函数 warpAffine
    • 旋转
    • 平移
  • 三、仿射变换
  • 四、透视变换
    • 综合示例
  • 总结

官网教程

一、翻转(镜像)

头文件 quick_opencv.h:声明类与公共函数

#pragma once
#include <opencv2\opencv.hpp>
using namespace cv;

class QuickDemo {
public:
	...
	void flip_Demo(Mat& image);
	void rotate_Demo(Mat& image);
	void move_Demo(Mat& image);
	void Affine_Demo(Mat& image);
	void toushi_Demo(Mat& image);
	void perspective_detect(Mat& image);

};

主函数调用该类的公共成员函数

#include <opencv2\opencv.hpp>
#include <quick_opencv.h>
#include <iostream>
using namespace cv;

int main(int argc, char** argv) {
	Mat src = imread("D:\\Desktop\\pandas.jpg");
	if (src.empty()) {
		printf("Could not load images...\n");
		return -1;
	}
	namedWindow("input", WINDOW_NORMAL);
	imshow("input", src);

	QuickDemo qk;

	...
	qk.Affine_Demo(src);
	qk.move_Demo(src);
	qk.flip_Demo(src);
	qk.toushi_Demo(src);
	qk.perspective_detect(src);

	waitKey(0);
	destroyAllWindows();
	return 0;
}

源文件 quick_demo.cpp:实现类与公共函数

void QuickDemo::flip_Demo(Mat& image) {
	Mat dst0, dst1, dst2;
	flip(image, dst0, 0);
	flip(image, dst1, 1);
	flip(image, dst2, -1);
	imshow("dst0_上下翻转", dst0);
	imshow("dst1_左右翻转", dst1);
	imshow("dst2_对角线翻转", dst2);  //旋转180度
}

二、仿射扭曲

二维图像一般情况下的变换矩阵(旋转+平移),当我们只需要平移的时候,取 θ 的值为0,a和b的值就代表了图像沿x轴和y轴移动的距离;其中原图 (原图大小,不执行缩放)

获取变换矩阵

变换矩阵计算:

其中:

Mat getRotationMatrix2D( Point2f center,      源图像中旋转的中心
double angle,      角度以度为单位的旋转角度。正值表示逆时针旋转(坐标原点假定为左上角)。
double scale     各向同性比例因子。
)

仿射扭曲函数 warpAffine

函数签名

void warpAffine( InputArray src,              输入矩阵
OutputArray dst,            输出矩阵
InputArray M,              2×3 变换矩阵
Size dsize,              输出图像大小
int flags = INTER_LINEAR,       插值方式:默认线性插值
int borderMode = BORDER_CONSTANT, 边缘处理方式
const Scalar& borderValue = Scalar()   边缘填充值,默认=0
);

保留所有原图像素的旋转,原理:

旋转

void QuickDemo::rotate_Demo(Mat& image) {
	Mat dst_0, dst_1, M;
	int h = image.rows;
	int w = image.cols;
	M = getRotationMatrix2D(Point(w / 2, h / 2), 45, 1.0);
	warpAffine(image, dst_0, M, image.size());

	double cos = abs(M.at<double>(0, 0));
	double sin = abs(M.at<double>(0, 1));

	int new_w = cos * w + sin * h;
	int new_h = cos * h + sin * w;
	M.at<double>(0, 2) += (new_w / 2.0 - w / 2);
	M.at<double>(1, 2) += (new_h / 2.0 - h / 2);
	warpAffine(image, dst_1, M, Size(new_w, new_h), INTER_LINEAR, 0, Scalar(255, 255, 0));
	imshow("旋转演示0", dst_0);
	imshow("旋转演示1", dst_1);
}

依次为:原图,旋转45度,保留所有原图像素的旋转45度

平移

void QuickDemo::move_Demo(Mat& image) {
	Mat dst_move;
	Mat move_mat = (Mat_<double>(2, 3) << 1, 0, 10, 0, 1, 30);//沿x轴移动10沿y轴移动30
	warpAffine(image, dst_move, move_mat, image.size());
	imshow("dst_move", dst_move);

	double angle_ = 3.14159265354 / 16.0;
	cout << "pi=" << cos(angle_) << endl;
	Mat rota_mat = (Mat_<double>(2, 3) << cos(angle_), -sin(angle_), 1, sin(angle_), cos(angle_), 1);
	warpAffine(image, rotate_dst, rota_mat, image.size());
	imshow("rotate_dst", rotate_dst);
}

三、仿射变换

Mat getAffineTransform(    返回变换矩阵
const Point2f src[],      变换前三个点的数组
const Point2f dst[]     变换后三个点的数组
);
void

void QuickDemo::Affine_Demo(Mat& image) {
	Mat warp_dst;
	Mat warp_mat(2, 3, CV_32FC1);

	Point2f srcTri[3];
	Point2f dstTri[3];

	/// 设置源图像和目标图像上的三组点以计算仿射变换
	srcTri[0] = Point2f(0, 0);
	srcTri[1] = Point2f(image.cols - 1, 0);
	srcTri[2] = Point2f(0, image.rows - 1);
	for (size_t i = 0; i < 3; i++){
		circle(image, srcTri[i], 2, Scalar(0, 0, 255), 5, 8);
	}

	dstTri[0] = Point2f(image.cols * 0.0, image.rows * 0.13);
	dstTri[1] = Point2f(image.cols * 0.95, image.rows * 0.15);
	dstTri[2] = Point2f(image.cols * 0.15, image.rows * 0.9);

	warp_mat = getAffineTransform(srcTri, dstTri);
	warpAffine(image, warp_dst, warp_mat, warp_dst.size());
	imshow("warp_dst", warp_dst);
}

四、透视变换

获取透射变换的矩阵:

Mat getPerspectiveTransform(   返回变换矩阵
const Point2f src[],     透视变换前四个点的 数组
const Point2f dst[],     透视变换后四个点的 数组
int solveMethod = DECOMP_LU
)

透射变换

void warpPerspective( InputArray src,         原图像
OutputArray dst,         返回图像
InputArray M,           透视变换矩阵
Size dsize,          返回图像的大小(宽,高)
int flags = INTER_LINEAR,   插值方法
int borderMode = BORDER_CONSTANT,  边界处理
const Scalar& borderValue = Scalar()    缩放处理
)

void QuickDemo::toushi_Demo(Mat& image) {
	Mat toushi_dst, toushi_mat;
	Point2f toushi_before[4];
	toushi_before[0] = Point2f(122, 220);
	toushi_before[1] = Point2f(397, 121);
	toushi_before[2] = Point2f(133, 339);
	toushi_before[3] = Point2f(397, 218);

	int width_0  = toushi_before[1].x - toushi_before[0].x;
	int height_0 = toushi_before[1].y - toushi_before[0].y;
	int width_1 = toushi_before[2].x - toushi_before[0].x;
	int height_1 = toushi_before[2].y - toushi_before[0].y;

	int width = (int)sqrt(width_0 * width_0 + height_0 * height_0);
	int height = (int)sqrt(width_1 * width_1 + height_1 * height_1);

	Point2f toushi_after[4];
	toushi_after[0] = Point2f(2, 2);                    // x0, y0
	toushi_after[1] = Point2f(width+2, 2);              // x1, y0
	toushi_after[2] = Point2f(2, height+2);             // x0, y1
	toushi_after[3] = Point2f(width + 2, height + 2);   // x1, y1

	for (size_t i = 0; i < 4; i++){
		cout << toushi_after[i] << endl;
	}

	toushi_mat = getPerspectiveTransform(toushi_before, toushi_after);
	warpPerspective(image, toushi_dst, toushi_mat, Size(width, height));
	imshow("toushi_dst", toushi_dst);
}

综合示例

自动化透视矫正图像:

流程:

  1. 灰度化二值化
  2. 形态学去除噪点
  3. 获取轮廓
  4. 检测直线
  5. 计算直线交点
  6. 获取四个透视顶点
  7. 透视变换

inline void Intersection(Point2i& interPoint, Vec4i& line1, Vec4i& line2) {
	// x1, y1, x2, y2 = line1[0], line1[1], line1[2], line1[3]

	int A1 = line1[3] - line1[1];
	int B1 = line1[0] - line1[2];
	int C1 = line1[1] * line1[2] - line1[0] * line1[3];

	int A2 = line2[3] - line2[1];
	int B2 = line2[0] - line2[2];
	int C2 = line2[1] * line2[2] - line2[0] * line2[3];

	interPoint.x = static_cast<int>((B1 * C2 - B2 * C1) / (A1 * B2 - A2 * B1));
	interPoint.y = static_cast<int>((C1 * A2 - A1 * C2) / (A1 * B2 - A2 * B1));
}

void QuickDemo::perspective_detect(Mat& image) {
	Mat gray_dst, binary_dst, morph_dst;
	// 二值化
	cvtColor(image, gray_dst, COLOR_BGR2GRAY);
	threshold(gray_dst, binary_dst, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);

	//形态学操作
	Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
	morphologyEx(binary_dst, morph_dst, MORPH_CLOSE, kernel, Point(-1, -1), 3);
	bitwise_not(morph_dst, morph_dst);
	imshow("morph_dst2", morph_dst);

	//轮廓查找与可视化
	vector<vector<Point>> contours;
	vector<Vec4i> hierarches;
	int height = image.rows;
	int width = image.cols;
	Mat contours_Img = Mat::zeros(image.size(), CV_8UC3);
	findContours(morph_dst, contours, hierarches, RETR_TREE, CHAIN_APPROX_SIMPLE);
	for (size_t i = 0; i < contours.size(); i++){
		Rect rect = boundingRect(contours[i]);
		if (rect.width > width / 2 && rect.width < width - 5) {
			drawContours(contours_Img, contours, i, Scalar(0, 0, 255), 2, 8, hierarches, 0, Point());
		}
	}
	imshow("contours_Img", contours_Img);

	vector<Vec4i> lines;
	Mat houghImg;
	int accu = min(width * 0.5, height * 0.5);
	cvtColor(contours_Img, houghImg, COLOR_BGR2GRAY);
	HoughLinesP(houghImg, lines, 1, CV_PI / 180, accu, accu*0.6, 0);

	Mat lineImg = Mat::zeros(image.size(), CV_8UC3);
	for (size_t i = 0; i < lines.size(); i++){
		Vec4i ln = lines[i];
		line(lineImg, Point(ln[0], ln[1]), Point(ln[2], ln[3]), Scalar(0, 0, 255), 2, 8, 0);
	}

	// 寻找与定位上下左右四条直线
	int delta = 0;
	Vec4i topline = { 0, 0, 0, 0 };
	Vec4i bottomline;
	Vec4i leftline, rightline;
	for (size_t i = 0; i < lines.size(); i++) {
		Vec4i ln = lines[i];
		delta = abs(ln[3] - ln[1]); // y2-y1

		//topline
		if (ln[3] < height / 2.0 && ln[1] < height / 2.0 && delta < accu - 1) {
			if (topline[3] > ln[3] && topline[3] > 0) {
				topline = lines[i];
			}
			else {
				topline = lines[i];
			}
		}
		if (ln[3] > height / 2.0 && ln[1] > height / 2.0 && delta < accu - 1) {
			bottomline = lines[i];
		}
		if (ln[0] < width / 2.0 && ln[2] < width / 2.0) {
			leftline = lines[i];
		}
		if (ln[0] > width / 2.0 && ln[2] > width / 2.0) {
			rightline = lines[i];
		}
	}

	cout << "topline: " << topline << endl;
	cout << "bottomline: " << bottomline << endl;
	cout << "leftline: " << leftline << endl;
	cout << "rightline: " << rightline << endl;

	// 计算上述四条直线交点(两条线的交点:依次为左上,右上,左下,右下)
	Point2i p0, p1, p2, p3;
	Intersection(p0, topline, leftline);
	Intersection(p1, topline, rightline);
	Intersection(p2, bottomline, leftline);
	Intersection(p3, bottomline, rightline);

	circle(lineImg, p0, 2, Scalar(255, 0, 0), 2, 8, 0);
	circle(lineImg, p1, 2, Scalar(255, 0, 0), 2, 8, 0);
	circle(lineImg, p2, 2, Scalar(255, 0, 0), 2, 8, 0);
	circle(lineImg, p3, 2, Scalar(255, 0, 0), 2, 8, 0);
	imshow("Intersection", lineImg);

	//透视变换
	vector<Point2f> src_point(4);
	src_point[0] = p0;
	src_point[1] = p1;
	src_point[2] = p2;
	src_point[3] = p3;

	int new_height = max(abs(p2.y - p0.y), abs(p3.y - p1.y));
	int new_width = max(abs(p1.x - p0.x), abs(p3.x - p2.x));
	cout << "new_height = " << new_height << endl;
	cout << "new_width = " << new_width << endl;

	vector<Point2f> dst_point(4);
	dst_point[0] = Point(0,0);
	dst_point[1] = Point(new_width, 0);
	dst_point[2] = Point(0, new_height);
	dst_point[3] = Point(new_width, new_height);

	Mat resultImg;
	Mat wrap_mat = getPerspectiveTransform(src_point, dst_point);
	warpPerspective(image, resultImg, wrap_mat, Size(new_width, new_height));
	imshow("resultImg", resultImg);
}

关键步骤可视化



总结

到此这篇关于OpenCV和C++实现图像的翻转(镜像)、平移、旋转、仿射与透视变换的文章就介绍到这了,更多相关OpenCV和C++图像翻转平移旋转内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++中实现OpenCV图像分割与分水岭算法

    分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水岭算法的一个重要特征. API介绍 void watershed( InputArray image, InputOutputArray markers ); 参数说明: image: 必须是一个8bit 3通道彩色图像矩阵序列 markers: 在执行分水岭函数watershed之前,必须对第二个参数markers

  • C++ opencv霍夫圆检测使用案例详解

    本程序是一个最简单的霍夫圆检测函数的使用案例,刚刚学会的用法,发一下,可以参考,参数啥的可根据图片调节. #pragma once #include<quickopencv.h> #include<vector> #include <stdio.h> #include <iostream> #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgpr

  • C++ opencv实现车道线识别

    本文实例为大家分享了C++ opencv实现车道线识别的具体代码,供大家参考,具体内容如下 先上图 1. 2. (一)目前国内外广泛使用的车道线检测方法主要分为两大类: (1) 基于道路特征的车道线检测: (2) 基于道路模型的车道线检测. 基于道路特征的车道线检测作为主流检测方法之一,主要是利用车道线与道路环境的物理特征差异进行后续图像的分割与处理,从而突出车道线特征,以实现车道线的检测.该方法复杂度较低,实时性较高,但容易受到道路环境干扰. 基于道路模型的车道线检测主要是基于不同的二维或三维

  • 使用c++实现OpenCV图像横向&纵向拼接

    功能函数 // 图像拼接 cv::Mat ImageSplicing(vector<cv::Mat> images,int type) { if (type != 0 && type != 1) type = 0; int num = images.size(); int newrow = 0; int newcol = 0; cv::Mat result; // 横向拼接 if (type == 0) { int minrow = 10000; for (int i = 0;

  • 使用c++实现OpenCV绘制图形旋转矩形

    目录 功能函数 // 绘制旋转矩形 void DrawRotatedRect(cv::Mat mask,const cv::RotatedRect &rotatedrect,const cv::Scalar &color,int thickness, int lineType) { // 提取旋转矩形的四个角点 cv::Point2f ps[4]; rotatedrect.points(ps); // 构建轮廓线 std::vector<std::vector<cv::Poin

  • c++ 基于opencv 识别、定位二维码

    前言 因工作需要,需要定位图片中的二维码:我遂查阅了相关资料,也学习了opencv开源库.通过一番努力,终于很好的实现了二维码定位.本文将讲解如何使用opencv定位二维码. 定位二维码不仅仅是为了识别二维码:还可以通过二维码对图像进行水平纠正以及相邻区域定位.定位二维码,不仅需要图像处理相关知识,还需要分析二维码的特性,本文先从二维码的特性讲起. 1 二维码特性 二维码在设计之初就考虑到了识别问题,所以二维码有一些特征是非常明显的. 二维码有三个"回""字形图案,这一点非常

  • OpenCV和C++实现图像的翻转(镜像)、平移、旋转、仿射与透视变换

    目录 一.翻转(镜像) 二.仿射扭曲 获取变换矩阵 仿射扭曲函数 warpAffine 旋转 平移 三.仿射变换 四.透视变换 综合示例 总结 官网教程 一.翻转(镜像) 头文件 quick_opencv.h:声明类与公共函数 #pragma once #include <opencv2\opencv.hpp> using namespace cv; class QuickDemo { public: ... void flip_Demo(Mat& image); void rotat

  • 详解Python+OpenCV进行基础的图像操作

    目录 介绍 形态变换 腐蚀 膨胀 创建边框 强度变换 对数变换 线性变换 去噪彩色图像 使用直方图分析图像 介绍 众所周知,OpenCV是一个用于计算机视觉和图像操作的免费开源库. OpenCV 是用 C++ 编写的,并且有数千种优化的算法和函数用于各种图像操作.很多现实生活中的操作都可以使用 OpenCV 来解决.例如视频和图像分析.实时计算机视觉.对象检测.镜头分析等. 许多公司.研究人员和开发人员为 OpenCV 的创建做出了贡献.使用OpenCV 很简单,而且 OpenCV 配备了许多工

  • opencv python如何实现图像二值化

    这篇文章主要介绍了opencv python如何实现图像二值化,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码如下 import cv2 as cv import numpy as np import matplotlib.pyplot as plt # 二值图像就是将灰度图转化成黑白图,没有灰,在一个值之前为黑,之后为白 # 有全局和局部两种 # 在使用全局阈值时,我们就是随便给了一个数来做阈值,那我们怎么知道我们选取的这个数的好坏呢?答

  • Python OpenCV读取中文路径图像的方法

    引言 这几天做点小东西,涉及到OpenCV读取中文图像的问题 如果直接读取中文路径的图像,往往返回[] import cv2 cv_im = cv2.imread('老干妈.jpg') 缘起 偶然发现opencv 读取图像,解决imread不能读取中文路径的问题文章,代码简单有效,可以参考下文章底部附录 im = cv2.imdecode(np.fromfile(im_name,dtype=np.uint8),-1) 但是作者代码注释中说该方法读取的图像的通道就会变为RGB,但是我实验仍为BGR

  • OpenCV实现低对比度图像脏污区域检测

    目录 1. 低对比度图像脏污区域检测 2. 实现方法介绍 3. C++源码实现 4.结果 总结 参考 1. 低对比度图像脏污区域检测 先上图: 第一张图如果不是标注结果,我都没有发现脏污区域在哪里,第二张图还清晰一些,基本可以看出来图像靠近左边缘的位置有偏暗的区域,这就是我们所说的脏污区域了,也是我们要检测的区域. 标注结果图: 2. 实现方法介绍 这里介绍两种实现方法, 第一种是用C++实现参考博文的方法,即利用梯度方法来检测,具体步骤如下: 对图像进行高斯模糊去噪,梯度计算对噪声很敏感: 调

  • 利用C++ OpenCV 实现从投影图像恢复仿射特性

    目录 原理 实现思路 主要代码 原理 我们通过相机拍摄的图片存在各种畸变,其中投影畸变使得原本平行的直线不再平行,就会产生照片中近大远小的效果,要校正这一畸变,书中给了很多方法,这里是其中的一种. 我们可以将投影变换拆分成相似变换.仿射变换和投影变换三部分, 如下图, 其中相似变换和仿射变换不会改变infinite line,只有投影变换会改变.因此只要找到畸变图像中的这条线,就能够恢复图像的仿射特性(相当于逆转投影变换).而要确定这条线的位置,就得至少知道线上的两个点.我们知道,所有平行线的交

  • 聊聊Qt+OpenCV联合开发之图像的创建与赋值问题

    目录 一.Mat基本结构 二.图像的克隆及拷贝 1.clone函数 2.copyTo函数 3.示例 三.创建图像 1.创建空白图像: 2.创建通道都为1的图: 3.拷贝和赋值的区别 3.1用Scalar函数设置m3对象为绿色 3.2m3赋值给m4,m4改为黄色 3.3拷贝m3给m4,m4改为黄色 一.Mat基本结构 1.Mat不但是一个非常有用的图像容器类,同时也是一个通用的矩阵类,它mat分为头部(包括图像的大小.宽高.类型.通道数等)和数据部分(像素的值的集合) 2.获取的mat对象赋值给另

  • Java OpenCV图像处理之自定义图像滤波算子

    目录 示例代码 效果图 示例代码 package com.xu.image; import java.io.File; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.Point; import org.opencv.highgui.HighGui; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Img

  • OpenCV 通过Mat遍历图像的方法汇总

    目录 方法一.直接对图像像素修改.at<typename>(i,j) 二.用指针.ptr<uchar>(k)来遍历输入图像,数组[]生成输出图像 三.用指针.ptr<uchar>(k)来遍历输入图像,指针方式生成输出图像 四.用指针.ptr<uchar>(k)来遍历输入图像,指针方式结合位运算生成输出图像 五.用指针.ptr<uchar>(k)来遍历输入图像,指针方式结合取模运算生成输出图像 六.连续图像isContinuous()函数方法. 七

  • Python OpenCV超详细讲解图像堆叠的实现

    目录 准备工作 水平堆叠 垂直堆叠 图像栈堆叠 准备工作 右击新建的项目,选择Python File,新建一个Python文件,然后在开头import cv2导入cv2库,import numpy并且重命名为np. import cv2 import numpy as np 我们还要知道在OpenCV中,坐标轴的方向是x轴向右,y轴向下,坐标原点在左上角,比如下面这张长为640像素,宽为480像素的图片.OK,下面开始本节的学习吧. 水平堆叠 调用np的hstack()水平堆栈方法,参数是我们要

随机推荐