【问题标题】:OpenCV Mat rotation gets wrong resultOpenCV Mat 旋转得到错误的结果
【发布时间】:2015-04-29 12:44:14
【问题描述】:

我想将图像旋转 90 度。我的代码如下:

int main(int argc, const char * argv[]) {
    Mat img = imread("/Users/chuanliu/Desktop/src4/p00.JPG");

    resize(img, img, Size(1024, 683));
    imwrite("/Users/chuanliu/Desktop/resize.jpg", img);
    Mat dst;
    Mat rot_mat = getRotationMatrix2D(Point(img.cols / 2.0, img.rows / 2.0), 90, 1);
    warpAffine(img, dst, rot_mat, Size(img.rows, img.cols));

    imwrite("/Users/chuanliu/Desktop/roatation.jpg", dst);

    return 0;
}

但结果如下:
轮换前:

旋转后:

旋转中心好像有问题。但我不认为我设置了错误的中心。有没有人可以告诉我什么是错的?

【问题讨论】:

  • 您的预期结果是旋转后的原始图像没有黑色边框且右侧没有裁剪边框?
  • @Micka 是的。我预计它只是在中间没有黑色区域
  • 旋转中心是正确的,但旋转是单应性,因此您必须在旋转后移动图像才能放置在正确的位置。

标签: c++ opencv


【解决方案1】:

中心是根据源图像的尺寸Point(img.cols / 2.0, img.rows / 2.0) 指定的,但在调用warpAffine 时,您不仅要旋转图像,还要在输出尺寸中交换宽度和高度:

Size(img.rows, img.cols)

所以看起来您可能需要根据输出图像坐标指定中心;例如。 Point(rows/2, cols/2).

更新:

不,这不是解决方案。其实有一个非常简单高效的方法可以将图片旋转90度:使用cv::transpose()函数:

int main()
{
    cv::Mat img = cv::imread("5syfi.jpg");
    cv::Mat img_rotated;

    cv::transpose(img, img_rotated);  

    cv::imwrite("out.jpg", img_rotated);

    return 0;
}

结合使用cv::transpose()(旋转)和cv::flip()(垂直和水平镜像),您可以非常快速地执行90、180和270度的旋转。

使用warpAffine() 更灵活,但计算成本也更高(即更慢)。因此,如果您只需要旋转 90 度的倍数,请使用cv::transpose。如果您需要旋转任意角度,请使用warpAffine/warpPerspective 函数。 @Micka 的回答提供了一个很好的例子来说明如何做到这一点。

【讨论】:

  • 是的,你是对的。现在我知道问题所在了,谢谢。
  • 你试过了吗?对我来说它裁剪图像被裁剪到左侧并在右侧留下黑色边框,因为旋转后,结果图像的左上角具有负坐标。
  • 请使用更新后的答案进行验证。 @Micka 是对的,旋转中心不是问题。
【解决方案2】:

改编我的回答:

OpenCV 2.4.3 - warpPerspective with reversed homography on a cropped image

您可以使用此代码:

int main(int argc, const char * argv[]) {
cv::Mat img = cv::imread("../inputData/rotationInput.jpg");

cv::imshow("input", img);

cv::Mat dst;
cv::Mat rot_mat = cv::getRotationMatrix2D(cv::Point(img.cols / 2.0, img.rows / 2.0), 90, 1);
//cv::warpAffine(img, dst, rot_mat, cv::Size(img.rows, img.cols));

// since I didnt write the code for affine transformations yet, we have to embed the affine rotation matrix in a perspective transformation
cv::Mat perspRotation = cv::Mat::eye(3,3, CV_64FC1);
for(int j=0; j<rot_mat.rows; ++j)
    for(int i=0; i<rot_mat.cols; ++i)
    {
        perspRotation.at<double>(j,i) = rot_mat.at<double>(j,i);
    }

// image boundary corners:
std::vector<cv::Point> imageCorners;
imageCorners.push_back(cv::Point(0,0));
imageCorners.push_back(cv::Point(img.cols,0));
imageCorners.push_back(cv::Point(img.cols,img.rows));
imageCorners.push_back(cv::Point(0,img.rows));

// look at where the image will be placed after transformation:
cv::Rect warpedImageRegion = computeWarpedContourRegion(imageCorners, perspRotation);

// adjust the transformation so that the top-left corner of the transformed image will be placed at (0,0) coordinate
cv::Mat adjustedTransformation = adjustHomography(warpedImageRegion, perspRotation);

// finally warp the image
cv::warpPerspective(img, dst, adjustedTransformation, warpedImageRegion.size());



//mwrite("/Users/chuanliu/Desktop/roatation.jpg", dst);
cv::imwrite("../outputData/rotationOutput.png", dst);
cv::imshow("out", dst);
cv::waitKey(0);

return 0;
}

使用这些辅助函数:

cv::Rect computeWarpedContourRegion(const std::vector<cv::Point> & points, const cv::Mat & homography)
{
    std::vector<cv::Point2f> transformed_points(points.size());

    for(unsigned int i=0; i<points.size(); ++i)
    {
        // warp the points
        transformed_points[i].x = points[i].x * homography.at<double>(0,0) + points[i].y * homography.at<double>(0,1) + homography.at<double>(0,2) ;
        transformed_points[i].y = points[i].x * homography.at<double>(1,0) + points[i].y * homography.at<double>(1,1) + homography.at<double>(1,2) ;
    }

    // dehomogenization necessary?
    if(homography.rows == 3)
    {
        float homog_comp;
        for(unsigned int i=0; i<transformed_points.size(); ++i)
        {
            homog_comp = points[i].x * homography.at<double>(2,0) + points[i].y * homography.at<double>(2,1) + homography.at<double>(2,2) ;
            transformed_points[i].x /= homog_comp;
            transformed_points[i].y /= homog_comp;
        }
    }

    // now find the bounding box for these points:
    cv::Rect boundingBox = cv::boundingRect(transformed_points);
    return boundingBox;
}


cv::Mat adjustHomography(const cv::Rect & transformedRegion, const cv::Mat & homography)
{
    if(homography.rows == 2) throw("homography adjustement for affine matrix not implemented yet");

    // unit matrix
    cv::Mat correctionHomography = cv::Mat::eye(3,3,CV_64F);
    // correction translation
    correctionHomography.at<double>(0,2) = -transformedRegion.x;
    correctionHomography.at<double>(1,2) = -transformedRegion.y;


    return correctionHomography * homography;
}

并产生 90° 的输出:

这个输出为 33°

顺便说一句,如果您只想旋转 90°/180°,那么可能有比图像变形更有效和更准确(关于插值)的方法!!

【讨论】:

    猜你喜欢
    • 2013-11-30
    • 1970-01-01
    • 1970-01-01
    • 2014-10-21
    • 2011-02-21
    • 2023-03-17
    • 1970-01-01
    • 2020-03-01
    • 2023-02-11
    相关资源
    最近更新 更多