2011-05-22 133 views
14

由于某些原因,每当我使用OpenCV的warpPerspective()函数时,最终变形的图像并不包含原始图像中的所有内容。图像的左侧部分似乎被切断。我认为发生这种情况的原因是因为warpPerspective()在画布的最左侧位置创建了变形图像。有没有办法解决这个问题?谢谢OpenCV warpperspective

回答

1

warpPerspective()正常工作。不需要重写它。 您可能使用不正确。

请记住以下提示:

  1. (0,0)的像素是不是在市中心,而是左上角。所以,如果你放大图像x2,你将失去较低和正确的部分,而不是边界(就像在matlab中)。
  2. 如果两次变形图像,最好将变换相乘并激活一次函数。
  3. 我认为它只适用于char/int矩阵,而不是float/double。
  4. 当您进行转换时,首先应用缩放/倾斜/旋转/透视,最后进行转换。因此,如果部分图像丢失,只需更改矩阵中的换位(最后一列的两行)。
+0

'垫TMP; cv :: resize(imageList [image1],tmp,Size(),scaleFactor,scaleFactor); warpPerspective(tmp,transformedImage,Homography,Size(2 * tmp.cols,2 * tmp.rows));' – Hien 2011-05-23 02:38:47

+0

我不知道如何在评论>。<中格式化。无论如何,这是我目前使用warpPerspective的代码片段。自从我使用高分辨率图像以来,单应从2幅图像的调整版本中提取。你能让我知道我做错了什么吗?谢谢 – Hien 2011-05-23 02:42:10

4

秘密分为两部分:变换矩阵(单应性)和由此产生的图像大小。

  • 通过使用getPerspectiveTransform()计算正确的转换。从原始图像中取4个点,计算它们在目的地的正确位置,将它们按照相同的顺序放入两个向量中,并使用它们来计算透视变换矩阵。

  • 确保目标图像大小(warpPerspective()的第三个参数)正是您想要的。将其定义为Size(myWidth,myHeight)。

26

问题发生的原因是单应图将部分图像映射到图像区域外的负x,y值,因此无法绘制。 我们希望做的是抵消一些像素的扭曲输出,将整个变形图像“分流”为正坐标(因此在图像区域内)。

可以使用矩阵乘法来组合同形(这就是为什么它们如此强大)。如果A和B是单应性,那么AB代表首先应用B的单应性,然后A.因此,我们需要做的是抵消输出是为某个偏移量的平移创建单应矩阵,并且然后预乘上我们原来的单应性矩阵

甲2D单应性矩阵是这样的:

[R11,R12,T1] 
[R21,R22,T2] 
[ P , P , 1] 

其中R表示旋转矩阵,T表示翻译,和P表示的立体翘曲。 所以纯粹的平移单应是这样的:

[ 1 , 0 , x_offset] 
[ 0 , 1 , y_offset] 
[ 0 , 0 , 1 ] 

所以只要你的预乘单应通过类似上述矩阵,并且您的输出图像将被抵消。

(确保你使用的矩阵乘法,而不是元素方式乘法!)

+0

似乎x_offset和y_offset应该乘以-1。我不知道为什么。我尝试了正面,并且将图像朝相反的方向移动。 – Steve 2017-03-12 03:48:21

4

我做了一个方法...... 这是工作。

perspectiveTransform(obj_corners,scene_corners,H); 
int maxCols(0),maxRows(0); 

for(int i=0;i<scene_corners.size();i++) 
{ 
    if(maxRows < scene_corners.at(i).y) 
     maxRows = scene_corners.at(i).y; 
    if(maxCols < scene_corners.at(i).x) 
     maxCols = scene_corners.at(i).x; 
} 

我只是觉得最大的X点和Y点的分别,把它放在

warpPerspective(tmp, transformedImage, homography, Size(maxCols, maxRows)); 
2

尝试以下homography_warp

void homography_warp(const cv::Mat& src, const cv::Mat& H, cv::Mat& dst); 

src是源图像。

H是你的单性生活。

dst是扭曲的图像。

homography_warp调整单应为他的答案通过https://stackoverflow.com/users/1060066/matt-freeman描述https://stackoverflow.com/a/8229116/15485

// Convert a vector of non-homogeneous 2D points to a vector of homogenehous 2D points. 
void to_homogeneous(const std::vector<cv::Point2f>& non_homogeneous, std::vector<cv::Point3f>& homogeneous) 
{ 
    homogeneous.resize(non_homogeneous.size()); 
    for (size_t i = 0; i < non_homogeneous.size(); i++) { 
     homogeneous[i].x = non_homogeneous[i].x; 
     homogeneous[i].y = non_homogeneous[i].y; 
     homogeneous[i].z = 1.0; 
    } 
} 

// Convert a vector of homogeneous 2D points to a vector of non-homogenehous 2D points. 
void from_homogeneous(const std::vector<cv::Point3f>& homogeneous, std::vector<cv::Point2f>& non_homogeneous) 
{ 
    non_homogeneous.resize(homogeneous.size()); 
    for (size_t i = 0; i < non_homogeneous.size(); i++) { 
     non_homogeneous[i].x = homogeneous[i].x/homogeneous[i].z; 
     non_homogeneous[i].y = homogeneous[i].y/homogeneous[i].z; 
    } 
} 

// Transform a vector of 2D non-homogeneous points via an homography. 
std::vector<cv::Point2f> transform_via_homography(const std::vector<cv::Point2f>& points, const cv::Matx33f& homography) 
{ 
    std::vector<cv::Point3f> ph; 
    to_homogeneous(points, ph); 
    for (size_t i = 0; i < ph.size(); i++) { 
     ph[i] = homography*ph[i]; 
    } 
    std::vector<cv::Point2f> r; 
    from_homogeneous(ph, r); 
    return r; 
} 

// Find the bounding box of a vector of 2D non-homogeneous points. 
cv::Rect_<float> bounding_box(const std::vector<cv::Point2f>& p) 
{ 
    cv::Rect_<float> r; 
    float x_min = std::min_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.x < rhs.x; })->x; 
    float x_max = std::max_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.x < rhs.x; })->x; 
    float y_min = std::min_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.y < rhs.y; })->y; 
    float y_max = std::max_element(p.begin(), p.end(), [](const cv::Point2f& lhs, const cv::Point2f& rhs) {return lhs.y < rhs.y; })->y; 
    return cv::Rect_<float>(x_min, y_min, x_max - x_min, y_max - y_min); 
} 

// Warp the image src into the image dst through the homography H. 
// The resulting dst image contains the entire warped image, this 
// behaviour is the same of Octave's imperspectivewarp (in the 'image' 
// package) behaviour when the argument bbox is equal to 'loose'. 
// See http://octave.sourceforge.net/image/function/imperspectivewarp.html 
void homography_warp(const cv::Mat& src, const cv::Mat& H, cv::Mat& dst) 
{ 
    std::vector<cv::Point2f> corners; 
    corners.push_back(cv::Point2f(0, 0)); 
    corners.push_back(cv::Point2f(src.cols, 0)); 
    corners.push_back(cv::Point2f(0, src.rows)); 
    corners.push_back(cv::Point2f(src.cols, src.rows)); 

    std::vector<cv::Point2f> projected = transform_via_homography(corners, H); 
    cv::Rect_<float> bb = bounding_box(projected); 

    cv::Mat_<double> translation = (cv::Mat_<double>(3, 3) << 1, 0, -bb.tl().x, 0, 1, -bb.tl().y, 0, 0, 1); 

    cv::warpPerspective(src, dst, translation*H, bb.size()); 
} 
+0

为什么要翻译-bb.tl()。x和-bb.tl()。y? “ - ”是什么原因? – Steve 2017-03-12 15:06:03

+0

@Steve我的代码是否工作? – 2017-03-12 20:32:36

+0

我没试过。我只是想看看你做了什么。 – Steve 2017-03-12 23:14:28

0

这是我的解决方案

因为在 “warpPerspective()” 第三个参数是变换矩阵,

我们可以创建一个变换矩阵,它首先向后移动图像,然后旋转图像,最后向前移动图像。

在我的情况下,我有一个高度为160像素,宽度为160像素的图像。 欲绕[80,80]的图像,而不是围绕[0,0]

第一,使图像向后移动(这意味着T1)

然后旋转图像(这意味着R)

终于使图像向前移动(这意味着T2)

void rotateImage(Mat &src_img,int degree) 
{ 
float radian=(degree/180.0)*M_PI; 
Mat R(3,3,CV_32FC1,Scalar(0)); 
R.at<float>(0,0)=cos(radian);R.at<float>(0,1)=-sin(radian); 
R.at<float>(1,0)=sin(radian);R.at<float>(1,1)=cos(radian); 
R.at<float>(2,2)=1; 
Mat T1(3,3,CV_32FC1,Scalar(0)); 
T1.at<float>(0,2)=-80; 
T1.at<float>(1,2)=-80; 
T1.at<float>(0,0)=1; 
T1.at<float>(1,1)=1; 
T1.at<float>(2,2)=1; 
Mat T2(3,3,CV_32FC1,Scalar(0)); 
T2.at<float>(0,2)=80; 
T2.at<float>(1,2)=80; 
T2.at<float>(0,0)=1; 
T2.at<float>(1,1)=1; 
T2.at<float>(2,2)=1; 

std::cerr<<T1<<std::endl; 
std::cerr<<R<<std::endl; 
std::cerr<<T2<<std::endl; 
std::cerr<<T2*R*T1<<"\n"<<std::endl; 

cv::warpPerspective(src_img, src_img, T2*R*T1, src_img.size(), cv::INTER_LINEAR); 
}