一. 场景说明
已知某个物体的四个角点(比如:车牌、表格等)坐标和对应的图片,如何通过透视变换获得矫正的图片。
原理解析:
- 对四个点进行排序(四个点可能是乱序的);
- 获得透视变换矩阵;
- 获得矫正的图片;
二. 代码实现
#include <iostream>
#include <string>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
int sort_points(cv::Point2f points[])
{
cv::Point2f tempPoint;
// 按照x轴坐标从小到大排序
for(int i=0; i<3; i++)
{
for(int j=i+1; j<4; j++)
{
if(points[i].x > points[j].x)
{
tempPoint = points[i];
points[i] = points[j];
points[j] = tempPoint;
}
}
}
// 按照纵坐标排序,坐标顺序为:0左下角 1左上角 2右上角 3右下角
if(points[0].y < points[1].y)
{
tempPoint = points[0];
points[0] = points[1];
points[1] = tempPoint;
}
if(points[2].y > points[3].y)
{
tempPoint = points[2];
points[2] = points[3];
points[3] = tempPoint;
}
return 0;
}
cv::Mat warp_img(cv::Point2f points[], const cv::Mat image)
{
cv::Point2f pts_src[4] = {points[0], points[1], points[2], points[3]};
int img_crop_height = int(sqrt(pow(pts_src[0].x - pts_src[1].x, 2) +
pow(pts_src[0].y - pts_src[1].y, 2)));
int img_crop_width = int(sqrt(pow(pts_src[1].x - pts_src[2].x, 2) +
pow(pts_src[1].y - pts_src[2].y, 2)));
cv::Point2f pts_dst[4];
pts_dst[0] = cv::Point2f(0, img_crop_height - 1);
pts_dst[1] = cv::Point2f(0, 0);
pts_dst[2] = cv::Point2f(img_crop_width - 1, 0);
pts_dst[3] = cv::Point2f(img_crop_width - 1, img_crop_height - 1);
cv::Mat M = cv::getPerspectiveTransform(pts_src, pts_dst);
cv::Mat crop_image;
cv::warpPerspective(image, crop_image, M,
cv::Size(img_crop_width, img_crop_height),
cv::BORDER_REPLICATE);
return crop_image;
}
int main()
{
std::string img_path = "../test.jpg";
cv::Mat image = cv::imread(img_path);
cv::Mat image2 = image.clone();
cv::Point2f points[4];
points[0] = cv::Point2f(464, 2862);
points[1] = cv::Point2f(2697, 2925);
points[2] = cv::Point2f(2706, 3566);
points[3] = cv::Point2f(431, 3487);
sort_points(points);
for(int i=0; i<4; i++)
{
cv::circle(image, points[i], 20, cv::Scalar(0,0,255), cv::FILLED, 0);
std::cout << "points:" << points[i] << std::endl;
}
cv::imwrite("../result.jpg", image);
cv::Mat crop_img = warp_img(points, image2);
cv::imwrite("../crop_img.jpg", crop_img);
return 0;
}
三. 效果展示
原图:
坐标显示:
透视变换后的图:
欢迎技术交流: