透视校正--鼠标沿着物体画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;
}
好记性不如烂键盘---点滴、积累、进步!