仿射变换
仿射变换可以通过一系列的原子变换的复合来实现包括:平移(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()函数求包含最小外接矩形的,与坐标轴平行(或垂直)的最小矩形。
效果图: