C++ OpenCV manually intercepts images for perspective transformation

learn better from others,

be the better one.

—— "Weika Zhixiang"

8b933d58b171e062191aa215afdc9166.jpeg

The length of this article is 2683 words , and it is expected to read for 6 minutes

foreword

Part of the previous article " C++ OpenCV Detecting and Extracting the Digital Huarong Road Chessboard " used perspective transformation, but because some pictures have too many interference items when adapting to edge detection, the desired things cannot be extracted, so this article Just did a small exercise of manually picking up the position to do perspective transformation.

c9ffabadc9976e407f0cd15e69d05703.png

achieve effect

3b1be889834e70a4144c3dd24be483b2.gif

d35ab7e473e8a25502ebecb904ae0102.jpeg

18f974808b2e665b665f4cb2609ff369.jpeg

As can be seen from the figure above, after manually clicking the blue quadrangular frame stippled in 4 positions, the effect of perspective transformation is performed on this image, which is also the final desired result. Next, let’s see how to achieve it.

Micro card Zhixiang

Q&A on key issues

Realize the manual click to capture the image for perspective transformation. Points to note?

A

1. For mouse events, it is necessary to ensure that the defined Point2f pointer must be initialized and cleared every time the image is switched, so that you can judge which point to assign a value to when you click.

2. When all 4 points are completed, the width and height of the rectangle need to be calculated using the Euclidean distance according to the position of the points.

3. You need to pay attention to the order of clicking. What you do now is to click clockwise from the upper left. If you don’t follow this plan, there will be problems with perspective transformation. At that time, there was a sorting function written in the CvUtils class in the source code, but Not used here.

Code

d247b86a0cf21d84c3e69a4ca9bc690d.png

Micro card Zhixiang

main.cpp code

#pragma once
#include <iostream>
#include <opencv2/opencv.hpp>
#include "../../Utils/CvUtils.h"




using namespace std;
using namespace cv;


//设置图片所以路径
String FilePaths = "D:/Business/DemoTEST/CPP/OpenCVDemoCpp/OpenCVSplitImage/pic";
//获取目录下的所有文件
vector<String> files;




//鼠标回调函数
void onMouse(int event, int x, int y, int flags, void* ustc);


Mat src;
Mat srccopy; //用于拷贝出的源图像
string showsrc = "图像";
int imgindex = 0;
//设置透视变换的点
Point2f vertices[4];




//给透视变换点进行赋值,返回值为3时,说明4个点都已经赋值了,可以进行下一步操作
int setPerspectivePoint(Point2f* vts, int x, int y, bool isinit = false);




int main(int argc, char** argv) {
  glob(FilePaths, files);


  if (files.size() <= 0) {
    cout << "找不到图片文件" << endl;
    waitKey(0);
    return -1;
  }


  //初始化透视变换的点
  setPerspectivePoint(vertices, 0, 0, true);


  //关闭所有显示窗口
  destroyAllWindows();


  cout << "srcindex:" << imgindex << endl;
  String file = files[imgindex];
  src = imread(file);
  CvUtils::MatResize(src);
  CvUtils::SetShowWindow(src, showsrc, 50, 20);
  imshow(showsrc, src);
  //复制下源图
  src.copyTo(srccopy);


  //设置鼠标响影事件
  setMouseCallback(showsrc, onMouse);


  waitKey(0);


  return 0;
}




void onMouse(int event, int x, int y, int flags, void* ustc)
{
  //鼠标左键按下
  if (event == EVENT_LBUTTONUP)
  {
    //设置选择的点
    int ptindex = setPerspectivePoint(vertices, x, y);


    //在图像上画出点击位置
    circle(src, Point(x, y), 3, Scalar(255, 0, 0), -1);
    //选中的点进行画线
    if (ptindex > 0 && ptindex <= 3) {
      line(src, vertices[ptindex], vertices[ptindex - 1], Scalar(255, 0, 0), 3);
      //当是最后一个点时和起始点进行画线连接
      if (ptindex == 3) {
        line(src, vertices[ptindex], vertices[0], Scalar(255, 0, 0), 3);
      }
    }


    imshow(showsrc, src);


    if (ptindex == 3) {
      //根据最小矩形和多边形拟合的最大四个点计算透视变换矩阵    
      Point2f rectPoint[4];
      //计算旋转矩形的宽和高
      float rWidth = CvUtils::CalcPointDistance(vertices[0], vertices[1]);
      float rHeight = CvUtils::CalcPointDistance(vertices[1], vertices[2]);
      //计算透视变换的四个顶点
      rectPoint[0] = Point2f(0, 0);
      rectPoint[1] = rectPoint[0] + Point2f(rWidth, 0);
      rectPoint[2] = rectPoint[1] + Point2f(0, rHeight);
      rectPoint[3] = rectPoint[0] + Point2f(0, rHeight);




      //计算透视变换矩阵    
      Mat warpmatrix = getPerspectiveTransform(vertices, rectPoint);
      Mat resultimg;
      //透视变换
      warpPerspective(srccopy, resultimg, warpmatrix, resultimg.size(), INTER_LINEAR);


      //载取透视变换后的图像显示出来
      Rect cutrect = Rect(rectPoint[0], rectPoint[2]);
      Mat cutMat = resultimg(cutrect);


      CvUtils::SetShowWindow(cutMat, "cutMat", 600, 20);
      imshow("cutMat", cutMat);
    }


  }
  else if (event == EVENT_RBUTTONUP) {
    //初始化透视变换的点
    setPerspectivePoint(vertices, 0, 0, true);


    imgindex++;
    if (imgindex < files.size()) {
      //关闭所有显示窗口
      destroyAllWindows();


      cout << "srcindex:" << imgindex << endl;
      String file = files[imgindex];
      src = imread(file);
      CvUtils::MatResize(src);
      CvUtils::SetShowWindow(src, showsrc, 50, 20);
      imshow(showsrc, src);


      //复制下源图
      src.copyTo(srccopy);


      //设置鼠标响影事件
      setMouseCallback(showsrc, onMouse);
    }
    waitKey(0);
  }
}




//给透视变换点进行赋值,返回值为true时,说明4个点都已经赋值了,可以进行下一步操作
int setPerspectivePoint(Point2f* vts, int x, int y, bool isinit)
{
  int res = 0;
  if (isinit) {
    for (int i = 0; i < 4; ++i) {
      vts[i].x = -1.0f;
      vts[i].y = -1.0f;
    }
  }
  else {
    for (int i = 0; i < 4; ++i) {
      if (vts[i].x == -1.0f && vts[i].y == -1.0f) {
        res = i;
        vts[i].x = x;
        vts[i].y = y;
        break;
      }
    }
  }
  return res;
}

01

Initialize Point2f points and assign values

b42477ad606378a4f6a5340d0efff668.png

2d197725add37516524ac2026a463e33.png

This is implemented with a function, adding a bool item of isinit. When it is true, directly assign all Point2f pointers to -1.0f. If it is a mouse click, it will automatically judge and assign a value to the first point and return the current position. number.

02

mouse click event

43958a5d451516f66fde3cc73418d929.png

When the left button is clicked, call the above function to obtain the current assigned point, and then draw a line connecting the current point with the previous point. If it is the last point, in addition to connecting with the previous point, it must also be connected with the starting point. Make a connection.

727b7f937454dd3dbaa6ef7e566b3b77.png

When the return value of ptindex is 3, it means that all 4 points have been assigned, and then enter the perspective transformation operation. Where CalcPointDistance is used to calculate the width and height of the rectangle.

0a820d2a66645e650c79aa344a5e53ab.png

The length is calculated by the Euclidean distance. There are some other passing functions in CvUtils. The complete source code can be seen at the end of the article.

7571341da5c9f24f7e2f480b178f3cd7.png

After clicking the right mouse button, it will jump to the next picture in the specified folder, and initialize the selection point that needs perspective transformation. Such a small demo of manually intercepting images for perspective transformation is completed.

source address

https://github.com/Vaccae/OpenCVDemoCpp.git

Click to read the original text to see the code address of "Code Cloud"

over

7b94daf77fc3e03b0651fd22a8ef5b21.png

4e748fc5855b2d54ed08634c6d9d534e.png

Wonderful review of the past

04b88d7a7911ddfe01f71ef58e07e5c7.jpeg

Use OpenCV to make a simple color extractor


604ff5ca402b1c4a7157d91792435aa2.jpeg

Fun Algorithm--OpenCV Huarongdao AI Automatic Problem Solving


7449a91b96ca954df470ae9228c97b20.jpeg

Live! How I made a digital Huarong Road game with OpenCV! (with source code)


Guess you like

Origin blog.csdn.net/Vaccae/article/details/126944941