user149691
user149691

Reputation: 607

OpenCV. How do I multiply point and matrix (CvMat)

I have matrix that is used for rotation:

CvMat* rot_mat = cvCreateMat(2, 3, CV_32FC1);
cv2DRotationMatrix(center, angle, scale, rot_mat);
...

This matrix is used for image operations.

cvWarpAffine(..., ..., rot_mat, ..., ...);

I have to know, how this matrix should affect exact pixel - location it should be transfered.

How can I multiply 2D point (pixel location) and my matrix to find out where pixel should be transferred?

Upvotes: 4

Views: 12511

Answers (4)

cyborg
cyborg

Reputation: 594

  1. For 3D points
std::vector<cv::Point3d> transform_3d_points(std::vector<cv::Point3d> points3d, cv::Mat transformation_matrix){
  std::vector<cv::Point3d> transformed_points3d;
  cv::perspectiveTransform(points3d, transformed_points3d, transformation_matrix);
  return transformed_points3d;
}
  1. For 2D points
std::vector<cv::Point2d> transform_2d_points(std::vector<cv::Point2d> points2d, cv::Mat transformation_matrix){
  std::vector<cv::Point2d> transformed_points2d;
  cv::perspectiveTransform(points2d, transformed_points2d, transformation_matrix);
  return transformed_points2d;
}

For 3d points , the transformation matrix should be 4*4 homogeneous. e.g.

cv::Mat transformation_matrix = (cv::Mat_<double>(4, 4) << 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
std::vector<cv::Points3d> points3d = { cv::Points3d(0,0,0),  cv::Points3d(1,1,1) }

For 2d points , the transformation matrix should be 3*3 homogeneous. e.g.

cv::Mat transformation_matrix = (cv::Mat_<double>(3, 3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
std::vector<cv::Points2d> points2d = { cv::Points2d(0,0),  cv::Points3d(1,1) }

Upvotes: 0

goe
goe

Reputation: 2303

If you already have the information stored in cv::Point elements you can transform that info into a matrix without memory copy using the cv::Mat constructor, like

cv::Mat V = cv::Mat(v, false); // false to avoid memory copy

After the operations using 'V' you can back to the original structure like

 V.copyTo( cv::Mat(p, false) );

You can parse a single point or a list (std::vector) of them with the same constructor. This sample code can show the idea better:

#include <iostream>
#include <opencv2/core/core.hpp>

int main( )
{
    std::vector< cv::Point2f > v(3);
    v[0] = cv::Point2f(1, 1);
    v[1] = cv::Point2f(2, 2);
    v[2] = cv::Point2f(3, 3);

    cv::Mat V = cv::Mat(v, false); // false to avoid memory copy

    std::vector< cv::Point2f > p(3);
    V.copyTo( cv::Mat(p, false) );

    for (int i = 0; i < 3; ++i) {
        std::cout << p[i] << std::endl;
    }

    return 0;
}

Upvotes: 2

Yonatan Simson
Yonatan Simson

Reputation: 2575

I found an answer to this in this forum. Just in case the link fails here is the solution:

cv::Point2f operator*(cv::Mat M, const cv::Point2f& p)
{ 
    cv::Mat_<double> src(3/*rows*/,1 /* cols */); 

    src(0,0)=p.x; 
    src(1,0)=p.y; 
    src(2,0)=1.0; 

    cv::Mat_<double> dst = M*src; //USE MATRIX ALGEBRA 
    return cv::Point2f(dst(0,0),dst(1,0)); 
} 

Upvotes: 8

user149691
user149691

Reputation: 607

I have implemented some silly code for that. I guess there should be more sophisticated solution:

CvMat* rot_mat; 
CvPoint* p;

...

float* data = (float*)(rot_mat->data.ptr);  
float newX = data[0] * p->x + data[1] * p->y + data[2]; 
float newY = data[3] * p->x + data[4] * p->y + data[5]; 

Upvotes: -2

Related Questions