Skip to content

Instantly share code, notes, and snippets.

@goldengrape
Created June 8, 2020 12:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save goldengrape/b666a0e822f6da7b56c0c626b7b140a5 to your computer and use it in GitHub Desktop.
Save goldengrape/b666a0e822f6da7b56c0c626b7b140a5 to your computer and use it in GitHub Desktop.
//
// main.cpp
// warp_in_one_window
//
// Created by GoldenGrape on 2020/6/8.
// Copyright © 2020 goldengrape. All rights reserved.
//
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/calib3d.hpp"
#include <iostream>
using namespace std;
using namespace cv;
vector<Point2f> d_corner(4);
vector<Point2f> o_corner(4);
float width, height;
bool dragging=false;
int selected_corner_i=-1;
Mat H, H_inv;
void init_corners(vector<Point2f> &corner, float width, float height);
void point_warp(Point2f &p_target, const Point2f &p, const Mat &H);
void onMouse(int event, int x, int y, int, void*);
int main(int argc, const char * argv[]) {
// 读取图像
String filename="/Volumes/macTF/lena.png";
Mat img=imread(filename);
width=img.cols; height=img.rows;
// 初始设置参考点为四角
init_corners(d_corner,width,height);
init_corners(o_corner, width, height);
// 初始化映射矩阵, 实际上是单位矩阵
H = findHomography(o_corner, d_corner);
H_inv=H;
// 设置鼠标控制
String win_name="Only one window";
namedWindow(win_name);
setMouseCallback(win_name, onMouse, 0);
// 显示变换图像
bool endProgram = false;
while(!endProgram){
// 控制按键
char c = (char)waitKey( 10 );
// 按q、Q、esc退出
if ((c == 'q') | (c == 'Q') | (c == 27))
{
endProgram = true;
}
// 按r、R旋转
if ((c == 'r') | (c == 'R'))
{
o_corner.push_back(o_corner[0]);
o_corner.erase(o_corner.begin());
}
// 计算映射矩阵H和逆矩阵H_inv
H = findHomography(o_corner, d_corner); //get homography
H_inv= findHomography(d_corner, o_corner);
// 将原始图像映射到新位置上
Mat warped_image;
warpPerspective(img, warped_image, H, Size(width,height));
imshow(win_name, warped_image);
}
return 0;
}
void init_corners(vector<Point2f> &corner, float width, float height){
// 初始化时, 将四角作为参考点
corner[0]=Point2f(0,0);
corner[1]=Point2f(width,0);
corner[2]=Point2f(width,height);
corner[3]=Point2f(0,height);
}
void onMouse(int event, int x, int y, int, void*){
// 有点复杂
// 当鼠标按下时在变形图上找到一点(x,y), 然后找到这一点在原始图上的位置o_corner
// 当鼠标拖动时, 相当于要将原始图上o_corner映射到鼠标点位置
if(event == EVENT_LBUTTONDOWN){
// 以四个象限来规定鼠标点的所属
if (x<width/2){
selected_corner_i=(y < height/2)?0:3;
} else if (x>=width/2){
selected_corner_i=(y < height/2)?1:2;
}
dragging= true;
d_corner[selected_corner_i]=Point2f((float)x,(float)y);
// 通过映射矩阵的逆矩阵H_inv, 计算当前(x,y)点在原始图的位置
point_warp(o_corner[selected_corner_i],
d_corner[selected_corner_i],
H_inv);
} else if (event==EVENT_LBUTTONUP) {
dragging= false;
}
if (dragging & (event == EVENT_MOUSEMOVE) ){
d_corner[selected_corner_i]=Point2f((float)x,(float)y);
}
}
void point_warp(Point2f &p_target, const Point2f &p, const Mat &H){
// 映射矩阵H是一个3x3的矩阵,
// s*[p_target.x, p_target.y, 1]= H * [p.x, p.y, 1]
// 乘出来以后要对第三项归一化
Mat p_vector = (Mat_ <double>(3, 1) << p.x,p.y, 1);
p_vector = H * p_vector;
p_target.x=(float)(p_vector.at<double>(0)/p_vector.at<double>(2));
p_target.y=(float)(p_vector.at<double>(1)/p_vector.at<double>(2));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment