透视校正--鼠标沿着物体画4条线

.pro

QT -= gui

CONFIG += c++11 console
CONFIG -= app_bundle

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += main.cpp 
    function.cpp


OPENCV_ROOT_PATH = /home/yhl/software_install/opencv3.2


INCLUDEPATH += $${OPENCV_ROOT_PATH}/include 
               $${OPENCV_ROOT_PATH}/include/opencv 
               $${OPENCV_ROOT_PATH}/include/opencv2



LIBS += -L$${OPENCV_ROOT_PATH}/lib


LIBS += -lopencv_core 
        -lopencv_highgui 
        -lopencv_imgproc 
        -lopencv_imgcodecs

HEADERS += 
    function.h

function.h

#ifndef FUNCTION_H
#define FUNCTION_H

#include <iostream>
#include "opencv2/opencv.hpp"
#include "math.h"
using namespace std;
using namespace cv;


double get_point_angle(CvPoint pointO,CvPoint pointA);

double dis_pt(Point &pt1, Point &pt2);

double get_ang(vector<Point> &v_pt);

cv::Mat rotateImg(cv::Mat & img, double degree,cv::Mat &map_matrix);

vector<Point> rot_pt(vector<Point> &v_pt,const cv::Mat &map_matrix);

bool correct_(const vector<Point> &v_pt,cv::Mat &SrcImg,cv::Mat &m_MingP,bool b_debug);

#endif // FUNCTION_H

function.cpp

#include "function.h"


/************************************************************************
*函数名:        get_point_angle
*
*函数作用:      已知2个坐标点,求从 0------->x 逆时针需旋转多少角度到该位置
*
*                   |
*                   |
*                   |
*                   |
*------------------------------------> x
*                   | 0
*                   |
*                   |
*                   |
*                   v
*                   y
*
*函数参数:
*CvPoint2D32f pointO  - 起点
*CvPoint2D32f pointA  - 终点
*
*函数返回值:
*double         向量OA,从 0------->x 逆时针需旋转多少角度到该位置
**************************************************************************/
double get_point_angle(CvPoint pointO,CvPoint pointA)
{
    double angle = 0;
    CvPoint point;
    double temp;

    point = cvPoint((pointA.x - pointO.x), (pointA.y - pointO.y));

    if ((0==point.x) && (0==point.y))
    {
        return 0;
    }

    if (0==point.x)
    {
        angle = 90;
        return angle;
    }

    if (0==point.y)
    {
        angle = 0;
        return angle;
    }

    temp = fabsf(float(point.y)/float(point.x));
    temp = atan(temp);
    temp = temp*180/CV_PI ;

    if ((0<point.x)&&(0<point.y))
    {
        angle = 360 - temp;
        return angle;
    }

    if ((0>point.x)&&(0<point.y))
    {
        angle = 360 - (180 - temp);
        return angle;
    }

    if ((0<point.x)&&(0>point.y))
    {
        angle = temp;
        return angle;
    }

    if ((0>point.x)&&(0>point.y))
    {
        angle = 180 - temp;
        return angle;
    }

    printf("sceneDrawing :: getAngle error!");
    return -1;
}

double dis_pt(Point &pt1, Point &pt2)
{
    return (sqrt(pow(pt1.x-pt2.x,2) + pow(pt1.y-pt2.y,2)));
}

double get_ang(vector<Point> &v_pt)
{
    if(v_pt.size()<1) { return 0;}
    double len_1 = dis_pt(v_pt[0],v_pt[1]);
    double len_2 = dis_pt(v_pt[2],v_pt[1]);
    double ang = 0.0;
    if(len_1 > len_2)
    {
        ang = get_point_angle(v_pt[0],v_pt[1]);
    }else
    {
        ang = get_point_angle(v_pt[2],v_pt[1]);
    }
    return ang;
}

cv::Mat rotateImg(cv::Mat & img, double degree,cv::Mat &map_matrix_1)
{
    if (degree == 0)
    {
        cv::Mat m = img.clone();
        return m;
    }

    degree = -degree;
    double angle = degree  * 1.0 * CV_PI / 180.;
    double a = sin(angle), b = cos(angle);
    int width = img.cols;
    int height = img.rows;
    int width_rotate = int(height * fabs(a) + width * fabs(b));
    int height_rotate = int(width * fabs(a) + height * fabs(b));

    // [ m0  m1  m2 ] ===>  [ A11  A12   b1 ]
    // [ m3  m4  m5 ] ===>  [ A21  A22   b2 ]
    float map[6];
    //    cv::Mat map_matrix = cv::Mat(2, 3, CV_32F, map);
    Mat map_matrix = cv::Mat(2, 3, CV_32F, map);

    CvPoint2D32f center = cvPoint2D32f(width / 2, height / 2);
    CvMat map_matrix2 = map_matrix;
    cv2DRotationMatrix(center, degree, 1.0, &map_matrix2);
    map[2] += (width_rotate - width) / 2;
    map[5] += (height_rotate - height) / 2;
    cv::Mat img_rotate;

    warpAffine(img, img_rotate, map_matrix, cv::Size(width_rotate, height_rotate), 1, 0, 0);
    map_matrix_1 = map_matrix.clone();
    return img_rotate;
}

vector<Point> rot_pt(vector<Point> &v_pt,const cv::Mat &map_matrix)
{
    std::cout<<"map_matrix="<<map_matrix<<std::endl;
    float *map = (float *)map_matrix.ptr<float>();

    vector<Point> v_pt2src;
    for(int i=0;i<v_pt.size();i++)
    {
        std::cout<<"src_pt="<<v_pt[i]<<std::endl;
        int x_t = v_pt[i].x;
        int y_t = v_pt[i].y;
        int x =  map[0]* x_t + map[1] * y_t + map[2];
        int y = map[3] * x_t + map[4] * y_t + map[5];
        v_pt2src.push_back(Point(x,y));
    }
    return v_pt2src;
}

//对矩形区域进行修正,防止图片越界
void RoiCorrect(cv::Rect  &r, const cv::Mat &m)
{
    if (r.x < 0) r.x = 0;
    if (r.y < 0) r.y = 0;

    if(r.x >= m.cols-1) r.x=0;
    if(r.y >= m.rows-1) r.y=0;

    if(r.width <= 0) r.width = 1;
    if(r.height <= 0) r.height = 1;

    if(r.x + r.width > m.cols - 1) r.width = m.cols - 1 - r.x;
    if(r.y + r.height > m.rows - 1) r.height = m.rows - 1 - r.y;
}

bool correct_(const vector<Point> &v_pt,cv::Mat &SrcImg,cv::Mat &m_out,bool b_debug)
{
    //   0   2
    //   1   3
    cv::Point pt_tl,pt_bl,pt_tr, pt_br;
    pt_tl = v_pt[3];
    pt_bl = v_pt[2];
    pt_tr = v_pt[0];
    pt_br = v_pt[1];

    Mat m_src_correct;
    cv::Point2f src_pt[4];
    cv::Point2f dst_pt[4];
    src_pt[0] = pt_tl;
    src_pt[1] = pt_bl;
    src_pt[2] = pt_tr;
    src_pt[3] = pt_br;
    //    int height = DisPt2Pt(pt_tl,pt_bl);
    //    int width = DisPt2Pt(pt_tl,pt_tr);
    int T_1 = 0;
    int T_2 = 0;
    dst_pt[0] = cv::Point(MIN(src_pt[0].x,src_pt[1].x) - T_1,MIN(src_pt[0].y,src_pt[2].y));
    dst_pt[1] = cv::Point(MIN(src_pt[0].x,src_pt[1].x) -T_1,MAX(src_pt[1].y,src_pt[3].y));
    dst_pt[2] = cv::Point(MAX(src_pt[2].x,src_pt[3].x) + T_2,MIN(src_pt[0].y,src_pt[2].y));
    dst_pt[3] = cv::Point(MAX(src_pt[2].x,src_pt[3].x) + T_2,MAX(src_pt[1].y,src_pt[3].y));

    //    int T_1 = 0;
    //    int T_2 = 0;
    //    dst_pt[0] = cv::Point(MIN(src_pt[0].x,src_pt[1].x)-T_1,MIN(src_pt[0].y,src_pt[2].y));
    //    dst_pt[1] = cv::Point(dst_pt[0].x-T_1,dst_pt[0].y + height);
    //    dst_pt[2] = cv::Point(dst_pt[0].x+width+T_2,dst_pt[0].y);
    //    dst_pt[3] = cv::Point(dst_pt[0].x+width+T_2,dst_pt[0].y + height);
    int offset_x = (dst_pt[2].x - dst_pt[0].x) * 0.0;//0.05;
    int offset_y = (dst_pt[3].y - dst_pt[2].y) * 0;//0.05;
    Point ptout_tl(dst_pt[0].x-offset_x,dst_pt[0].y-offset_y);
    Point ptout_br(dst_pt[3].x+offset_x,dst_pt[3].y+offset_y);
    Rect roi_mingp = Rect(ptout_tl,ptout_br);

    cv::Mat warpMatrix = cv::getPerspectiveTransform(src_pt, dst_pt);
    cv::warpPerspective(SrcImg, m_src_correct, warpMatrix, SrcImg.size(), cv::INTER_NEAREST, cv::BORDER_CONSTANT);
    RoiCorrect(roi_mingp,m_src_correct);
    Mat m_MingP = m_src_correct(roi_mingp).clone();
    m_out = m_src_correct.clone();
    if(b_debug)
    {
        Mat m_show = m_src_correct.clone();
        rectangle(m_show,roi_mingp,Scalar(0,255,255),3);
        cv::namedWindow("correctSrcImg",cv::WINDOW_NORMAL);
        cv::imshow("correctSrcImg",SrcImg);
        cv::namedWindow("correctPic",cv::WINDOW_NORMAL);
        cv::imshow("correctPic",m_show);
        cv::namedWindow("correctRoi",cv::WINDOW_NORMAL);
        cv::imshow("correctRoi",m_MingP);
        waitKey(0);
    }
    return true;
}

main.cpp

#include "function.h"

void on_MouseHandle(int event, int x, int y, int flag, void* param);
void DrawRectangle(Mat& img, Rect box);

int cnt = 1;
vector<Point> v_pt;
Mat m_src_cp;
/*****************鼠标操作*****************/
Rect g_rect;
bool g_DrawFlag = false;
RNG g_rng(12345);
Point pt_start,pt_end;
void MouseEvent( Mat &srcImage )
{
    //准备参数
    g_rect = Rect(-1, -1, 0, 0);
    //Mat srcImage(600, 600, CV_8UC3), tempImage;
    m_src_cp = srcImage.clone();
    Mat tempImage;
    srcImage.copyTo(tempImage);
    g_rect = Rect(-1, -1, 0, 0);
    //srcImage = Scalar::all(0);

    //设置鼠标操作回调函数
    namedWindow("Win");
    setMouseCallback("Win", on_MouseHandle, (void*)&srcImage);

    //绘画
    while (1)
    {
        srcImage.copyTo(tempImage);
        if (g_DrawFlag && 2 != cnt) {
            //DrawRectangle(tempImage, g_rect);
            line(tempImage,pt_start,pt_end,Scalar(g_rng.uniform(0, 255),
                                                  g_rng.uniform(0, 255), g_rng.uniform(0, 255)),2);
        }

        imshow("Win", tempImage);//imshow("Win", srcImage);//        imshow("Win", tempImage);

        //std::cout<<"v_pt_size="<<v_pt.size()<<std::endl;

        if (waitKey(10) == 27) break;//ESC 退出
    }
}
//鼠标回调事件
void on_MouseHandle(int event, int x, int y, int flag, void* param)
{
    Mat& image = *(Mat*)param;
    switch (event)
    {
    case EVENT_MOUSEMOVE://移动
        if (g_DrawFlag) {
            pt_end = Point(x,y);
            cnt += 1;
        }
        break;
    case EVENT_LBUTTONDOWN://左键按下
        g_DrawFlag = true;
        //设置g_rect的初始值在同一个点
        //g_rect = Rect(x, y, 0, 0);

        if(1 == cnt)
        {
            pt_start = Point(x,y);
        }else
        {
            pt_start = pt_end;
        }
        cnt += 1;
        break;
    case EVENT_LBUTTONUP://左键抬起
        g_DrawFlag = false;
        v_pt.push_back(pt_end);
        line(image,pt_start,pt_end,Scalar(g_rng.uniform(0, 255),
                                          g_rng.uniform(0, 255), g_rng.uniform(0, 255)),2);
        break;
    }
}
//矩形绘制函数
void DrawRectangle(Mat& img, Rect box)
{
    //rectangle画矩形
    //tl左上角的点,br右下角的点
    //Scalar设置颜色,设置为3通道
    //g_rng.uniform(0, 255)随机颜色
    rectangle(img, box.tl(), box.br(), Scalar(g_rng.uniform(0, 255),
                                              g_rng.uniform(0, 255), g_rng.uniform(0, 255)));
}


int main(int argc, char *argv[])
{
    Mat srcImage = imread("/home/yhl/下载/1113_1.jpg");
    MouseEvent(srcImage);

    double ang = get_ang(v_pt);
    Mat map_matrix = cv::Mat(2, 3, CV_32F);
    Mat m_rot = rotateImg(m_src_cp,ang,map_matrix);
    vector<Point> v_pt_rot = rot_pt(v_pt,map_matrix);
    cv::Mat m_out;
    bool b_debug = false;
    correct_(v_pt_rot,m_rot,m_out,b_debug);

    namedWindow("perspective",0);
    imshow("perspective",m_out);
    waitKey(0);
    return 0;
}
原文地址:https://www.cnblogs.com/yanghailin/p/11855614.html