【opencv小案例-切边】仿射变换与切边

仿射变换

仿射变换可以通过一系列的原子变换的复合来实现包括:平移(Translation)、缩放(Scale)、翻转(Flip)、旋转(Rotation)和错切(Shear).
可以看做原矩阵和一个变换矩阵(3*3且最后一行是(0,0,1))的乘法

  • 平移(刚体变化,即不会产生形变),将每一点移到到(x+t , y+t),这是变换矩阵为:
    在这里插入图片描述

  • 缩放变换 将每一点的横坐标放大或缩小sx倍,纵坐标放大(缩小)到sy倍,
    当sx=sy时称为尺度缩放,不等式称为拉伸变换
    在这里插入图片描述

  • 剪切变换(Shear)
    在这里插入图片描述

  • 旋转变换(Rotation)目标图形围绕原点顺时针旋转theta弧度,变换矩阵为
    在这里插入图片描述

opencv中实现仿射变换

仿射变换一般会涉及到warpAffine和getRotationMatrix2D两个函数。

getRotationMatrix2D
Mat cv::getRotationMatrix2D     (   Point2f     center,
        double      angle,
        double      scale 
)

参数解释
. center: Point2f类型,表示原图像的旋转中心
. angle: double类型,表示图像旋转角度,角度为正则表示逆时针旋转,角度为负表示逆时针旋转(坐标原点是图像左上角)
. scale: 缩放系数 1.0便是不变
功能: 返回一个变换矩阵

warpAffine函数
void cv::warpAffine     (   InputArray      src,
        OutputArray     dst,
        InputArray      M,
        Size    dsize,
        int     flags = INTER_LINEAR,
        int     borderMode = BORDER_CONSTANT,
        const Scalar &      borderValue = Scalar() 
    )

参数解释
. src: 输入图像
. dst: 输出图像,尺寸由dsize指定,图像类型与原图像一致
. M: 2X3的变换矩阵
. dsize: 指定图像输出尺寸
. flags: 插值算法标识符,有默认值INTER_LINEAR
. borderMode: 边界像素模式,有默认值BORDER_CONSTANT
. borderValue: 边界取值,有默认值Scalar()即0

功能: 实现重映射

切边

在这里插入图片描述
这里我们使用方法一

代码:
# include<opencv2\opencv.hpp>
# include <iostream>
# include <math.h>
using namespace std;
using namespace cv;

Mat src, dst,gray_src;
int Max_value = 255;
int threshold_value = 30;
const char *contours_win = "Find ROI";
const char *roi_win = "Mage ROI";
void findROI(int, void*);
void Check_Skew(int, void*);
int main(int argc, char** argv) {
	src = imread("E:/tuku/case3.png");
	if (src.empty()) {
		cout << "can't find this picture...";
		return -1;
	}
	imshow("input Image", src);
	namedWindow(contours_win, 1);
	namedWindow(roi_win, 1);
	createTrackbar("value:", contours_win, &threshold_value, Max_value, findROI);
	Check_Skew(0, 0);
	findROI(0, 0);
	waitKey(0);
	return 0;
}
void Check_Skew(int, void*) {
	cvtColor(src, gray_src, COLOR_BGR2GRAY);
	Mat canny_Imag;
	//边缘检测
	Canny(gray_src, canny_Imag, threshold_value, threshold_value * 2, 3, false);

	vector<vector<Point>> contours;
	vector<Vec4i> hierachy;
	//发现轮廓
	findContours(canny_Imag, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	Mat drawImag = Mat::zeros(src.size(), CV_8UC3);
	float maxh = 0;
	float maxw = 0;
	double degree = 0;
	for (size_t i = 0; i < contours.size(); i++) {
		RotatedRect minRect = minAreaRect(contours[i]);  //RotatedRect是一个存储旋转矩形的类,通常用来存储最小外包矩形函数minAreaRect( )和椭圆拟合函数fitEllipse( )返回的结果
		float degree = abs(minRect.angle);               //类中定义了矩形的中心点center、尺寸size(包括width、height)、旋转角度angle共3个成员变量;
		                                                //  points()函数用于求矩形的4个顶点,boundingRect()函数求包含最小外接矩形的,与坐标轴平行(或垂直)的最小矩形。
		                                                 //类中定义了矩形的中心点center、尺寸size(包括width、height)、旋转角度angle共3个成员变量
		if (degree==0) {     //degree>0
			maxh = max(maxh, minRect.size.height);
			maxw = max(maxw, minRect.size.width);
		}
		RNG rng(12345);
		for (size_t i = 0; i < contours.size(); i++) {
			RotatedRect minRect = minAreaRect(contours[i]);
			if (maxw == minRect.size.width&&maxh == minRect.size.height) {
				degree = abs(minRect.angle);
				Point2f ptrs[4];
				minRect.points(ptrs);
				for (int t = 0; t < 4; t++) {
					Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
					line(drawImag, ptrs[t], ptrs[(t + 1) % 4], color, 2, 8, 0);
				}
			}
		}
	}
	printf("contours max width:%f\n", maxw);
	printf("contours max heighr:%f\n", maxh);
	printf("contours degree:%f\n", degree);
	Point2f center(src.cols / 2, src.rows / 2);
	Mat rotm;
	if (degree == 0 && maxw > maxh) 
		 rotm = getRotationMatrix2D(center, 90, 1.0);  //主要用于获得图像绕着 某一点的旋转矩阵,为后面的仿射变换做准备
	else  rotm = getRotationMatrix2D(center, degree, 1.0);
	warpAffine(src, dst, rotm, src.size(), INTER_LINEAR, 0, Scalar(255, 255, 255));//放射变换
	imshow("Corect image", dst);
}
void findROI(int, void*) {
	Mat canny_Imag;
	Mat dst_gray;
	cvtColor(dst, dst_gray, COLOR_BGR2GRAY);
	Canny(dst_gray, canny_Imag, threshold_value, threshold_value*2, 3, false);

	vector<vector<Point>> contours;
	vector<Vec4i> hierachy;
	//发现轮廓
	findContours(canny_Imag, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	int minw = 0.5*dst_gray.cols;
	int minh = 0.5*dst_gray.rows;
	RNG rng(12345);
	Rect boxx;
	Mat drawImage = Mat::zeros(dst_gray.size(), CV_8UC3);
	for (size_t i = 0; i < contours.size(); i++) {
		RotatedRect minRect = minAreaRect(contours[i]);
		float degree = abs(minRect.angle);
		printf("angle:%f\n", degree);
		if (minRect.size.width > minw&&minRect.size.height > minh&&minw < (dst_gray.cols - 5)) {
			Point2f ptr[4];
			minRect.points(ptr);
			boxx = minRect.boundingRect();   //将获取到的轮廓,提取出来
			Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
			for(int t=0;t<4;t++)
			line(drawImage, ptr[t], ptr[(t + 1) % 4], color, 2, 8, 0);
		}
	}
	imshow(contours_win, drawImage);
	if (boxx.height > 0 && boxx.width > 0) {
		Mat ROI = dst(boxx);//在原图像中,提取ROI
		imshow(roi_win, ROI);
	}
}

RotatedRect是一个存储旋转矩形的类,
通常用来存储最小外包矩形函数minAreaRect( )和椭圆拟合函数fitEllipse( )返回的结果
类中定义了矩形的中心点center、尺寸size(包括width、height)、旋转角度angle共3个成员变量;
points()函数用于求矩形的4个顶点,boundingRect()函数求包含最小外接矩形的,与坐标轴平行(或垂直)的最小矩形。

效果图:

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值