opencv笔记4----透视变换

透视变换通过变换矩阵(3*3)将任意视角的照片转换为垂直视角,要得到变换矩阵需要提供两个坐标系的对应点

照片中取点的方法分为手动和自动,自动取点又可以分为检测强角点、检测直线角点、检测圆心等多种方式,随具体情况而定。

本项目要检测不规则工件轮廓,因此将工件置于标准矩形白板上,拍照整个白板,希望检测出白板的四个顶点

直接根据图形特征检测(角点、直线、圆)都会受到环境的干扰,尤其是背景的干扰,可以辅助以颜色分离(HSV空间)再进行图形识别

本程序检测四边直线,再进行延长求解直线交点

注意:检测出的交点是无序的,需要相对于中心的顺时针(or逆)排列


#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

using namespace cv;
Point2f center(0,0);  

//计算直线交点
Point2f computeIntersect(cv::Vec4i a,cv::Vec4i b)  
{  
    int x1 = a[0],y1 = a[1],x2 = a[2],y2 = a[3],x3 = b[0],y3 = b[1],x4 = b[2],y4 = b[3];  
  
    if (float d = ((float)(x1 - x2)*(y3 - y4)-(y1 - y2)*(x3 - x4)))  
    {  
        cv::Point2f pt;  
        pt.x = ((x1*y2 - y1*x2)*(x3 - x4) - (x1 - x2)*(x3*y4 - y3*x4))/d;  
        pt.y = ((x1*y2 - y1*x2)*(y3 - y4) - (y1 - y2)*(x3*y4 - y3*x4))/d;  
        return pt;  
    }  
    else  
        return cv::Point2f(-1,-1);  
}  

//将corners绕center顺时针排列
void sortCorners(std::vector<cv::Point2f>& corners,cv::Point2f center)  
{  
    std::vector<cv::Point2f> top,bot;  
  
    for (unsigned int i =0;i< corners.size();i++)  
    {  
        if (corners[i].y<center.y)  
        {  
            top.push_back(corners[i]);  
        }  
        else  
        {  
            bot.push_back(corners[i]);  
        }  
    }  
  
    cv::Point2f tl = top[0].x > top[1].x ? top[1] : top[0];  
    cv::Point2f tr = top[0].x > top[1].x ? top[0] : top[1];  
    cv::Point2f bl = bot[0].x > bot[1].x ? bot[1] : bot[0];  
    cv::Point2f br = bot[0].x > bot[1].x ? bot[0] : bot[1];  
  
    corners.clear();  
    //注意以下存放顺序是顺时针,当时这里出错了,如果想任意顺序下文开辟的四边形矩阵注意对应  
    corners.push_back(tl);  
    corners.push_back(tr);  
    corners.push_back(br);  
    corners.push_back(bl);  
}  

//透视变换
int main(int argc,char **argv)
{
	Mat src = imread("poker.jpg",1);
	if(src.empty())
		return -1;
	imshow("Source",src);
	
	Mat gray;
	cvtColor(src,gray,CV_BGR2GRAY);
	//imshow("Gray",gray);

	blur(gray,gray,Size(3,3));
	Canny(gray,gray,100,100,3);
	//imshow("Canny",gray);
	std::vector<Vec4i> lines;  
    HoughLinesP(gray,lines,1,CV_PI/180,70,30,10);  



	//线段延长至整幅图像
	for (unsigned int i = 0;i<lines.size();i++)  
    {  
        cv::Vec4i v = lines[i];  
        lines[i][0] = 0;  
        lines[i][1] = ((float)v[1] - v[3])/(v[0] - v[2])* -v[0] + v[1];  
        lines[i][2] = src.cols;  
        lines[i][3] = ((float)v[1] - v[3])/(v[0] - v[2])*(src.cols - v[2]) + v[3];  
    } 

	//存储线的交点
	std::vector<Point2f> corners;
	for (unsigned int i = 0;i<lines.size();i++)  
    {  
        for (unsigned int j=i+1;j<lines.size();j++)  
        {  
            Point2f pt = computeIntersect(lines[i],lines[j]);  
            if (pt.x >= 0 && pt.y >=0)  //交点在图像内
					corners.push_back(pt); 
        }  
    }  

	std::vector<cv::Point2f> approx;  
	approxPolyDP(cv::Mat(corners),approx,arcLength(Mat(corners),true)*0.02,true);  
    if (approx.size()!=4)  
    {  
        std::cout<<"The object is not quadrilateral!"<<std::endl;  
        return -1;  
    }  
	 //get mass center  
    for (unsigned int i = 0;i < corners.size();i++)  
    {  
        center += corners[i];  
    }  
    center *=(1./corners.size());  
    sortCorners(corners,center);  //corners绕center顺时针排列

	//draw lines
	for(int i=0;i<lines.size();++i)
		line(src,Point(lines[i][0],lines[i][1]),Point(lines[i][2],lines[i][3]),Scalar(0,0,0),2,8,0);
	imshow("Source",src);

	//draw corner points  
	circle(src,corners[0],3,CV_RGB(255,0,0),2);  //red
    circle(src,corners[1],3,CV_RGB(0,255,0),2);  //green
    circle(src,corners[2],3,CV_RGB(0,0,255),2);  //blue
    circle(src,corners[3],3,CV_RGB(255,255,255),2);  //white

	circle(src,center,3,CV_RGB(255,255,0),2);  //yellow
	imshow("Source",src);

	Mat quad = Mat::zeros(320,240,CV_8UC3);//校正后图片
 
	//corners of the destination image  
    std::vector<Point2f> quad_pts;  
    quad_pts.push_back(Point2f(0,0));  
    quad_pts.push_back(Point2f(quad.cols,0));//(220,0)  
    quad_pts.push_back(Point2f(quad.cols,quad.rows));//(220,300)  
    quad_pts.push_back(Point2f(0,quad.rows));  
  
    // Get transformation matrix  
    Mat transmtx = getPerspectiveTransform(corners,quad_pts);   //求源坐标系(已畸变的)与目标坐标系(转换后的)的转换矩阵  
  
    // Apply perspective transformation透视转换  
    warpPerspective(src,quad,transmtx,quad.size());  
	imshow("quadrilateral",quad); 
	waitKey(0);
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值