2

JavaCV/OpenCVで可変角度(22°など)でいくつかの画像を回転させたいです。現時点では私が使用しています cvWarpAffine()

私の問題は、回転後に画像の端を失うことです。そのため、dst.imageを大きくして中心点を移動する必要があります。このページで、画像の新しいサイズを計算するための AS コードを見つけました。しかし、JavaCV/OpenCVで実現する方法がわかりません

やがて私は次のコードを持っています:

public CvMat rotateImage(int angle) {
    CvPoint2D32f center = new CvPoint2D32f(input.cols() / 2.0F,
            input.rows() / 2.0F);

    CvMat rotMat = cvCreateMat(2, 3, CV_32F);
    cv2DRotationMatrix(center, angle, 1, rotMat);
    CvMat dst = cvCreateMat(input.rows(), input.cols(), input.type());
    cvWarpAffine(input, dst, rotMat);
    return dst;

}

誰かがアイデアを持っていますか?

ご挨拶

//アップデート

わかりません...何かが間違っています。回転した画像を計算すると、結果は正しい寸法になりますが、ほとんどが黒です (0 と 360° が機能します)。コードは次のとおりです。

public CvMat rotateImage(float angle) {
    CvPoint2D32f center = new CvPoint2D32f(input.cols() / 2.0F,
            input.rows() / 2.0F);
    CvBox2D box = new CvBox2D(center, cvSize2D32f(input.cols() - 1,
            input.rows() - 1), angle);
    CvPoint2D32f points = new CvPoint2D32f(4);
    cvBoxPoints(box, points);
    CvMat pointMat = cvCreateMat(1, 4, CV_32FC2);
    pointMat.put(0, 0, 0, points.position(0).x());
    pointMat.put(0, 0, 1, points.position(0).y());
    pointMat.put(0, 1, 0, points.position(1).x());
    pointMat.put(0, 1, 1, points.position(1).y());
    pointMat.put(0, 2, 0, points.position(2).x());
    pointMat.put(0, 2, 1, points.position(2).y());
    pointMat.put(0, 3, 0, points.position(3).x());
    pointMat.put(0, 3, 1, points.position(3).y());
    CvRect boundingRect = cvBoundingRect(pointMat, 0);

    CvMat dst = cvCreateMat(boundingRect.height(), boundingRect.width(),
            input.type());

    CvPoint2D32f centerDst = new CvPoint2D32f(center.x()
            + (dst.cols() / 2.0F), center.y() + (dst.rows() / 2.0F));

    CvMat rotMat = cvCreateMat(2, 3, CV_32F);
    cv2DRotationMatrix(centerDst, angle, 1, rotMat);
    CvMat trans = cvCreateMat(3, 3, CV_32F);
    cvZero(trans);
    trans.put(0, 2, dst.cols() / 2.0F);
    trans.put(1, 2, dst.rows() / 2.0F);

    trans.put(0, 0, 1);
    trans.put(1, 1, 1);
    trans.put(2, 2, 1);

    CvMat newRot = cvCreateMat(3, 3, CV_32F);
    cvZero(newRot);
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
            newRot.put(i, j, rotMat.get(i, j));
        }
    }

    newRot.put(2, 2, 1);
    cvMul(trans, newRot, newRot, 1);

    cvWarpPerspective(input, dst, newRot);
    // cvWarpAffine(input, dst, dstRotMat);

    return dst;

}

次のrotMatようになります。

[ 0.9396926, 0.34202015, -311.1334
 -0.34202015, 0.9396926, 601.47485 ]

(trans組織の画像のサイズは 1428x928px です):

[ 1.0, 0.0, 836.0
0.0, 1.0, 699.0
0.0, 0.0, 1.0 ]

そしてそのnewRot

[ 0.9396926, 0.0, -260107.52
-0.0, 0.9396926, 420430.94
0.0, 0.0, 1.0 ]

私は間違いを見つけることができません

//更新 2

public CvMat rotateImage(float angle) {
    CvPoint2D32f center = new CvPoint2D32f(input.cols() / 2.0F,
            input.rows() / 2.0F);
    CvBox2D box = new CvBox2D(center, cvSize2D32f(input.cols() - 1,
            input.rows() - 1), angle);
    CvPoint2D32f points = new CvPoint2D32f(4);
    cvBoxPoints(box, points);
    CvMat pointMat = cvCreateMat(1, 4, CV_32FC2);
    pointMat.put(0, 0, 0, points.position(0).x());
    pointMat.put(0, 0, 1, points.position(0).y());
    pointMat.put(0, 1, 0, points.position(1).x());
    pointMat.put(0, 1, 1, points.position(1).y());
    pointMat.put(0, 2, 0, points.position(2).x());
    pointMat.put(0, 2, 1, points.position(2).y());
    pointMat.put(0, 3, 0, points.position(3).x());
    pointMat.put(0, 3, 1, points.position(3).y());
    CvRect boundingRect = cvBoundingRect(pointMat, 0);

    CvMat dst = cvCreateMat(boundingRect.height(), boundingRect.width(),
            input.type());

    // CvPoint2D32f centerDst = new CvPoint2D32f(((dst.cols()-input.cols()
    // )/ 2.0F),(( dst.rows()-input.rows()) / 2.0F));

    CvMat rotMat = cvCreateMat(2, 3, CV_32F);
    cv2DRotationMatrix(center, angle, 1, rotMat);
    CvMat trans = cvCreateMat(3, 3, CV_32F);
    cvZero(trans);
    trans.put(0, 2, (dst.cols() - input.cols()) / 2.0F);
    trans.put(1, 2, (dst.rows() - input.rows()) / 2.0F);

    trans.put(0, 0, 1);
    trans.put(1, 1, 1);
    trans.put(2, 2, 1);

    CvMat newRot = cvCreateMat(3, 3, CV_32F);
    cvZero(newRot);
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
            newRot.put(i, j, rotMat.get(i, j));
        }
    }

    newRot.put(2, 2, 1);
    cvMul(trans, newRot, newRot, 1);

    cvWarpPerspective(input, dst, newRot);
    // cvWarpAffine(input, dst, rotMat);

    System.out.println(rotMat);
    System.out.println(trans);
    System.out.println(newRot);

    return dst;

1 度では、行列は次のようになります。

rotMat:

 [ 0.9998477, 0.017452406, -8.338219
 -0.017452406, 0.9998477, 12.534734 ]

trans

 [ 1.0, 0.0, -8.0
  0.0, 1.0, -12.0
  0.0, 0.0, 1.0 ]

newRot

 [ 0.9998477, 0.0, 66.70575
   -0.0, 0.9998477, -150.41681
   0.0, 0.0, 1.0 ]

最後の

Hammer からの命令の作業 JavaCode:

public CvMat rotateImage(float angle) {
    CvPoint2D32f center = new CvPoint2D32f(input.cols() / 2.0F,
            input.rows() / 2.0F);
    CvBox2D box = new CvBox2D(center, cvSize2D32f(input.cols() - 1,
            input.rows() - 1), angle);
    CvPoint2D32f points = new CvPoint2D32f(4);
    cvBoxPoints(box, points);
    CvMat pointMat = cvCreateMat(1, 4, CV_32FC2);
    pointMat.put(0, 0, 0, points.position(0).x());
    pointMat.put(0, 0, 1, points.position(0).y());
    pointMat.put(0, 1, 0, points.position(1).x());
    pointMat.put(0, 1, 1, points.position(1).y());
    pointMat.put(0, 2, 0, points.position(2).x());
    pointMat.put(0, 2, 1, points.position(2).y());
    pointMat.put(0, 3, 0, points.position(3).x());
    pointMat.put(0, 3, 1, points.position(3).y());
    CvRect boundingRect = cvBoundingRect(pointMat, 0);

    CvMat dst = cvCreateMat(boundingRect.height(), boundingRect.width(),
            input.type());

    CvMat rotMat = cvCreateMat(2, 3, CV_32FC1);
    cv2DRotationMatrix(center, angle, 1, rotMat);

    double y_1 = ((boundingRect.width() - input.cols()) / 2.0F)
            + rotMat.get(0, 2);
    double y_2 = ((boundingRect.height() - input.rows()) / 2.0F + rotMat
            .get(1, 2));

    rotMat.put(0, 2, y_1);
    rotMat.put(1, 2, y_2);

    cvWarpAffine(input, dst, rotMat);

    return dst;

}
4

2 に答える 2

6

opencv には、リンク先のコードが行っている外接する四角形を見つけるための関数が既にあります。これはそれを使用する例です

std::vector<cv::Point2f> points;
points.push_back(cv::Point2f(0,0));
points.push_back(cv::Point2f(13,0));
points.push_back(cv::Point2f(0,11));
points.push_back(cv::Point2f(10,10));


cv::Rect rectangle = cv::boundingRect(points);

返される長方形は、左上隅が (0,0) で、幅が 14、高さが 12 で、すべての点を含む最小の寸法です。必要な手順は次のとおりです。

  1. 画像の 4 隅すべての座標を取得します。
  2. アフィン変換により、これらの各座標を変換します。
  3. これらのポイントを cv::boundingRect に渡して、境界矩形を取得します。

boundingRect によって返される四角形の寸法は、目的の画像に必要な寸法です。外接する長方形の位置は考慮せず、寸法のみを考慮してください。

編集

2 つ目の問題は、古い画像の中心を新しい画像の中心に合わせることです。長方形の寸法が dw と dh だけ変化する場合、

centerNew.x = centerOld.x+dw/2;
centerNew.y = centerOld.y+dh/2;

したがって、古い画像全体を dw/2 だけ右に移動し、下 (正の y) dh/2 に移動する必要があります。この動きは、アフィン変換にラップできます。各ピクセルを変換によってワープしてから、マトリックスによって変換する必要があります

tran_mat = [1,0,dw/2,
            0,1,dh/2]

2つを組み合わせるには、乗算する必要があります

NewWarp = tran_mat*old_warp;

残念ながら、次元が一致しないため、単純に乗算することはできません。その場合、新しい 3 行目として [0,0,1] を追加して、両方を 3x3 行列に変換します。次に、それらを一緒に掛けることができます。次に、その行列を cv::warpPerspective に渡すか、一番下の行を削除してアフィン変換に戻すことができます ([0,0,1] のままにする必要があります)。

編集 2 2 つの問題があると思います。初め

cv2DRotationMatrix(centerDst, angle, 1, rotMat);

centerDst は、入力画像の中心を表す必要があります。

CvPoint2D32f center = new CvPoint2D32f(input.cols() / 2.0F,input.rows() / 2.0F);

だからあなたの電話をに変更してください

cv2DRotationMatrix(center, angle, 1, rotMat);

また、変換行列に入れる変数は、画像 1 の中心と画像 2 の中心の間の距離である必要があります。それを計算する方法はいくつかありますが、

trans.put(0, 2, dst.cols() / 2.0F);
trans.put(1, 2, dst.rows() / 2.0F);

それらの1つではありません。これにより、中心の動きが得られます

trans.put(0, 2, (dst.cols()-input.cols()) / 2.0F);
trans.put(1, 2, (dst.rows()-input.rows()) / 2.0F);

画面から画像全体を翻訳していたため、画面のほとんどが黒かったと思います。

編集3

自分で書いてテストしただけです。これが私のコードです。おそらく、Matx から pt へ、およびその逆へのすべての変換を行わずに、これを行うはるかにエレガントな方法がありますが、これは私にとってはうまくいきます。C++ を使用していますが、それでもプロセスが明確に示されています。ここからどこを逸脱しているかを把握するだけです

cv::Mat im; //your image
cv::Matx23d rot = getRotationMatrix2D(cv::Point2f(im.cols/2,im.rows/2),45,1);
cv::Matx31d tl(0,0,1);
cv::Matx31d tr(im.cols,0,1);
cv::Matx31d bl(0,im.rows,1);
cv::Matx31d br(im.cols,im.rows,1);

std::vector<cv::Point2f> pts;
cv::Matx21d tl2 = rot*tl;
cv::Matx21d tr2 = rot*tr;
cv::Matx21d bl2 = rot*bl;
cv::Matx21d br2 = rot*br;
pts.push_back(cv::Point2f(tl2(0),tl2(1)));
pts.push_back(cv::Point2f(tr2(0),tr2(1)));
pts.push_back(cv::Point2f(bl2(0),bl2(1)));
pts.push_back(cv::Point2f(br2(0),br2(1)));

cv::Rect bounds = cv::boundingRect(pts);

cv::Matx33d tran(1,0,(bounds.width-im.cols)/2,
                 0,1,(bounds.height-im.rows)/2,
                 0,0,1);
cv::Matx33d rot33;
for(int i = 0; i < 6; i++)
    rot33(i) = rot(i);
rot33(2,0) = 0;
rot33(2,1) = 0;
rot33(2,2) = 1;
cv::Matx33d combined = tran*rot33;
cv::Matx23d final;
for(int i = 0; i < 6; i++)
    final(i) = combined(i);

cv::Size im_size(bounds.width,bounds.height);
cv::warpAffine(im, drawing_image,final, im_size);

編集4

rotation = 45 deg;
width = 300 height = 287

rotation matrix
[0.7071067811865476, 0.7071067811865475, -57.18228688765842;
 -0.7071067811865475, 0.7071067811865476, 147.9497474683058]

translation matrix
[1, 0, 58;
 0, 1, 64;
 0, 0, 1]

combined matrix
[0.7071067811865476, 0.7071067811865475, 0.8177131123415791;
-0.7071067811865475, 0.7071067811865476, 211.9497474683058]

これが元の画像です

元の画像

ここでは、投稿したコードをそのまま使用して45度回転させています。

45度の画像

于 2012-08-14T21:11:43.557 に答える
0

ハンマーによる答えは私のためにトリックをしました。しかし、それはエラーを与えました。構文を少し変更する必要がありました。これは私のために働いた機能です。

Mat rotateImage(Mat im, double angle){
cv::Matx23d rot = getRotationMatrix2D(cv::Point2f(im.cols/2,im.rows/2),angle,1);
cv::Matx31d tl(0,0,1);
cv::Matx31d tr(im.cols,0,1);
cv::Matx31d bl(0,im.rows,1);
cv::Matx31d br(im.cols,im.rows,1);

std::vector<cv::Point2f> pts;
cv::Matx21d tl2 = rot*tl;
cv::Matx21d tr2 = rot*tr;
cv::Matx21d bl2 = rot*bl;
cv::Matx21d br2 = rot*br;
pts.push_back(cv::Point2f(tl2(0),tl2(1)));
pts.push_back(cv::Point2f(tr2(0),tr2(1)));
pts.push_back(cv::Point2f(bl2(0),bl2(1)));
pts.push_back(cv::Point2f(br2(0),br2(1)));

cv::Rect bounds = cv::boundingRect(pts);

cv::Matx33d tran(1,0,(bounds.width-im.cols)/2,0,1,(bounds.height-im.rows)/2,0,0,1);
cv::Matx33d rot33;
for(int i = 0; i < 2; i++)
    for(int j=0; j<3; j++)
        rot33(i,j) = rot(i,j);

rot33(2,0) = 0;
rot33(2,1) = 0;
rot33(2,2) = 1;
cv::Matx33d combined = tran*rot33;
cv::Matx23d finall;
for(int i = 0; i < 2; i++)
    for(int j=0; j<3; j++)
        finall(i,j) = combined(i,j);

cv::Size im_size(bounds.width,bounds.height);
Mat drawing_image;
cv::warpAffine(im, drawing_image,finall, im_size);

return drawing_image;
}
于 2016-10-09T20:14:27.633 に答える