本章内容:
卡片检测
1. 读入图片
2. canny 边缘检测
3. 寻找最外层轮廓
4. 通过最大弧长获取卡片轮廓
5. 计算卡片的最小外接矩形
6. 计算软转矩阵,并进行仿射变换校正
7. 计算单应性矩阵,并进行单应性变换校正
1. canny 边缘检测
输出结果:
2. 轮廓提取
输出结果:
3. 最小外接矩形提取分割轮廓
输出结果:
4. 旋转校正
输出结果:
5.单应性变换校正
输出结果
代码
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>int main(int argc, char* argv[]){
/* 本章内容:
卡片检测
1. 读入图片
2. canny检测
3. 寻找最外层轮廓
4. 通过最大弧长获取卡片轮廓
5. 计算卡片的最小外接矩形
6. 计算软转矩阵,并进行仿射变换校正
7. 计算单应性矩阵,并进行单应性变换校正
*/
cv::String fileName = "/home/wang/dev/Image/card1.jpg";
cv::Mat src = cv::imread(fileName,cv::IMREAD_REDUCED_COLOR_8);
if(src.empty()){
std::cout << "读入图像文件失败\n" << std::endl;
return -1;
}
cv::imshow("src", src);
// 灰度化,边缘检测
cv::Mat gray;
cv::cvtColor(src,gray,cv::COLOR_BGR2GRAY);
cv::Mat dstCanny;
cv::Canny(gray,dstCanny,50,100);
cv::imshow("Canny edges", dstCanny);// 轮廓查找
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hireachy;
cv::findContours(dstCanny, contours,hireachy,cv::RETR_EXTERNAL,cv::CHAIN_APPROX_SIMPLE);// 计算轮廓最大弧长以及id
double arcLen=0;
int arcIdx =0;
double degree;
for(int i=0; i < contours.size();i++){
double temArc= cv::arcLength(contours[i],false);
if(temArc > arcLen){
arcLen =temArc;
arcIdx = i;
}
}
std::cout << "srcLen = " << arcLen << " arcIdx = " << arcIdx << std::endl;
cv::drawContours(src,contours,arcIdx,cv::Scalar(0,255,0),2);
cv::imshow("外层轮廓", src);// 最小外接矩形分割轮廓
cv::RotatedRect rect = cv::minAreaRect(contours[arcIdx]);
degree = rect.angle;
cv::Point2f pts[4];
rect.points(pts);
for(int i=0; i<4;i++) cv::line(src,pts[i],pts[(i+1)%4],cv::Scalar(0,0,255),2);
cv::imshow("最小外接矩形", src);// 仿射变换
// CV_EXPORTS_W Mat getRotationMatrix2D(Point2f center, double angle, double scale);
cv::Point2f center(src.rows/2,src.cols/2);
cv::Mat romH = cv::getRotationMatrix2D(center,degree + 90,1);
/*CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst,
InputArray M, Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
*/
cv::Mat dstAff;
cv::warpAffine(src,dstAff,romH,src.size());
cv::imshow("dstAff",dstAff);// 单应性矩阵校正
// 计算单应性矩阵
float wMax=rect.size.width;
float hMax=rect.size.height;
std::vector<cv::Point2f> pt1s;
pt1s.push_back(pts[0]);
pt1s.push_back(pts[1]);
pt1s.push_back(pts[2]);
pt1s.push_back(pts[3]);
std::vector<cv::Point2f> pt2s;
pt2s.push_back(cv::Point2f(0,0));
pt2s.push_back(cv::Point2f(wMax,0));
pt2s.push_back(cv::Point2f(wMax,hMax));
pt2s.push_back(cv::Point2f(0,hMax));cv::Mat Hom = cv::findHomography(pt1s,pt2s,cv::RANSAC);
cv::Mat dstHom;
cv::warpPerspective(src,dstHom,Hom,cv::Size(wMax,hMax));
cv::imshow("单应性变换",dstHom);cv::waitKey(0);
return 0;
}