拍摄或者扫描图像不是规则的矩形,会对后期处理产生不好的影响,需要通过透视变换矫正得到正确的形状
计算透视变换函数api
Mat cv::getPerspectiveTransform (
InputArray src,
InputArray dst,
int solveMethod = DECOMP_LU
)
参数说明
使用变换函数纠正函数api
void cv::warpPerspective ( InputArray src,
OutputArray dst,
InputArray M,
Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar & borderValue = Scalar()
)
参数说明
#include
#include
#include
using namespace std;
using namespace cv;
#define PIC_PATH "/work/opencv_pic/"
#define PIC_NAME "case5.png"
int main(void)
{
Mat src,gray_src;
//获取完整的图片路径及名称
string pic = string(PIC_PATH)+string(PIC_NAME);
//打印图片路径
cout << "pic path is :"<<pic<<endl;
//读取图片
src = imread(pic);
//判断图片是否存在
if(src.empty())
{
cout<<"pic is not exist!!!!"<<endl;
return -1;
}
//显示图片
namedWindow("src pic",WINDOW_AUTOSIZE);
imshow("src pic",src);
cvtColor(src,gray_src,COLOR_BGR2GRAY);
//图片与背景有巨大的反差 先将图片二值化 方便提取主体部分
Mat binaryimg;
threshold(gray_src,binaryimg,0,255,THRESH_BINARY | THRESH_OTSU);
//imshow("binaryimg",binaryimg);
//图片反向 进行去噪
bitwise_not(binaryimg,binaryimg);
//imshow("bitnot binaryimg",binaryimg);
//主题部分内部仍有黑色噪点干扰存在 闭操作
Mat kernel = getStructuringElement(MORPH_RECT,Size(3,3),Point(-1,-1));
morphologyEx(binaryimg,binaryimg,MORPH_CLOSE,kernel,Point(-1,-1),3);
//imshow("close opera binaryimg",binaryimg);
//查找轮廓 绘制轮廓
vector<vector<Point>> contours;
findContours(binaryimg,contours,RETR_TREE,CHAIN_APPROX_SIMPLE);
Mat contourimg = Mat::zeros(src.size(),src.type());
for(size_t i=0;i<contours.size();i++)
{
Rect rect = boundingRect(contours[i]);
//通过轮廓外界矩形大小 滤除国徽部分干扰
if(rect.width > src.cols/2 && rect.height > src.rows/2)
drawContours(contourimg,contours,i,Scalar(0,0,255),2);
}
imshow("contourimg",contourimg);
int height = src.rows;
int width = src.cols;
//霍夫直线检测
Mat hough;
//霍夫检测单通道图
cvtColor(contourimg,hough,COLOR_BGR2GRAY);
vector<Vec4i> lines;
double accu = min(height*0.5,width*0.5);
HoughLinesP(hough,lines,1,CV_PI/180.0,accu,accu,0);
//绘制直线
Mat lineimg = Mat::zeros(src.size(),src.type());
for(size_t i=0;i<lines.size();i++)
{
Vec4i linep = lines[i];
line(lineimg,Point(linep[0],linep[1]),Point(linep[2],linep[3]),Scalar(0,0,255),2,8);
}
imshow("hough line img",lineimg);
//判断四条线的位置 上下左右
// 定位直线
int deltah = 0;
Vec4i topLine, bottomLine, leftLine, rightLine;
for (size_t i = 0; i < lines.size(); i++){
Vec4i ln = lines[i];
deltah = abs(ln[3] - ln[1]); //直线两点之间的竖直差
if (ln[3] < height / 2.0 && ln[1] < height / 2.0 && deltah < accu - 1){
topLine = lines[i];
}
if (ln[3] > height / 2.0 && ln[1] > height / 2.0 && deltah < 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;
// 拟合四条直线方程
float k1, c1;
k1 = float(topLine[3] - topLine[1]) / float(topLine[2] - topLine[0]);
c1 = topLine[1] - k1*topLine[0];
float k2, c2;
k2 = float(bottomLine[3] - bottomLine[1]) / float(bottomLine[2] - bottomLine[0]);
c2 = bottomLine[1] - k2*bottomLine[0];
float k3, c3;
k3 = float(leftLine[3] - leftLine[1]) / float(leftLine[2] - leftLine[0]);
c3 = leftLine[1] - k3*leftLine[0];
float k4, c4;
k4 = float(rightLine[3] - rightLine[1]) / float(rightLine[2] - rightLine[0]);
c4 = rightLine[1] - k4*rightLine[0];
// 四条直线交点
Point p1; // 左上角
p1.x = static_cast<int>((c1 - c3) / (k3 - k1));
p1.y = static_cast<int>(k1*p1.x + c1);
Point p2; // 右上角
p2.x = static_cast<int>((c1 - c4) / (k4 - k1));
p2.y = static_cast<int>(k1*p2.x + c1);
Point p3; // 左下角
p3.x = static_cast<int>((c2 - c3) / (k3 - k2));
p3.y = static_cast<int>(k2*p3.x + c2);
Point p4; // 右下角
p4.x = static_cast<int>((c2 - c4) / (k4 - k2));
p4.y = static_cast<int>(k2*p4.x + c2);
cout << "p1(x, y)=" << p1.x << "," << p1.y << endl;
cout << "p2(x, y)=" << p2.x << "," << p2.y << endl;
cout << "p3(x, y)=" << p3.x << "," << p3.y << endl;
cout << "p4(x, y)=" << p4.x << "," << p4.y << endl;
// 显示四个点坐标
circle(lineimg, p1, 2, Scalar(0,255, 0), 2, 8, 0);
circle(lineimg, p2, 2, Scalar(0,255, 0), 2, 8, 0);
circle(lineimg, p3, 2, Scalar(0,255, 0), 2, 8, 0);
circle(lineimg, p4, 2, Scalar(0,255, 0), 2, 8, 0);
//line(lineimg, Point(topLine[0], topLine[1]), Point(topLine[2], topLine[3]), Scalar(0, 255, 0), 2, 8, 0);
imshow("four corners", lineimg);
// 透视变换
vector<Point2f> src_corners(4); // 原来的点
src_corners[0] = p1;
src_corners[1] = p2;
src_corners[2] = p3;
src_corners[3] = p4;
vector<Point2f> dst_corners(4); // 目标点位
dst_corners[0] = Point(0,0);
dst_corners[1] = Point(width, 0);
dst_corners[2] = Point(0, height);
dst_corners[3] = Point(width , height);
// 获取变换矩阵
Mat reslutImg;
//获取透视转换矩阵
Mat warpmatrix = getPerspectiveTransform(src_corners, dst_corners);
//将原图通过转换矩阵矫正
warpPerspective(src, reslutImg, warpmatrix, reslutImg.size(), INTER_LINEAR);
imshow("dst", reslutImg);
waitKey(0);
destroyAllWindows();
return 0;
}