web-dev-qa-db-ja.com

自動遠近補正OpenCV

IOSプログラムで自動遠近法補正を実装しようとしていますが、チュートリアルで見つけたテストイメージを使用すると、すべてが期待どおりに動作します。しかし、写真を撮ると、奇妙な結果が返ってきます。

私はこれにあるコードを使用しています tutorial

次のような画像を指定すると:

enter image description here

結果としてこれを取得します:

enter image description here

dstが私に与えるものがここにあります。

enter image description here

これを使用して、コードを含むメソッドを呼び出しています。

quadSegmentation(Img, bw, dst, quad);

チュートリアルと比較して非常に多くの緑色の線が表示されている場合、誰にも教えてもらえますか?そして、どうすればこれを修正し、カードのみを含むように画像を適切にトリミングできますか?

26
Clip

必要な透視変換のために、

ソースポイント->ソースイメージ内の四角形の頂点の座標。

宛先ポイント->宛先イメージの対応する四角形の頂点の座標。

ここでは、輪郭プロセスによってこれらのポイントを計算します。

ソース画像の四角形の頂点の座標を計算します

  • ぼかし、しきい値処理を行うだけで、カードを輪郭として取得し、輪郭を見つけたり、最大の輪郭を見つけたりすることができます。
  • 最大の輪郭を見つけた後、 多角形曲線に近似 を計算するだけで、ここでカードのコーナーを表す4ポイントを取得するはずです。パラメーターepsilonを調整して、4つの座標を作成できます。

enter image description here

宛先イメージの対応する四角形の頂点の座標を計算します

  • これは、最大の輪郭の境界矩形を計算することで簡単に見つけることができます。

enter image description here

下の画像では、赤い長方形がソースポイントを表し、宛先ポイントが緑を表しています。

enter image description here

座標の順序を調整し、遠近法変換を適用します

  • ここでは、座標の順序を手動で調整し、並べ替えアルゴリズムを使用できます。
  • 次に、 変換行列 を計算し、 wrapPrespective を適用します

最終結果を見る

enter image description here

コード

 Mat src=imread("card.jpg");
 Mat thr;
 cvtColor(src,thr,CV_BGR2GRAY);
 threshold( thr, thr, 70, 255,CV_THRESH_BINARY );

 vector< vector <Point> > contours; // Vector for storing contour
 vector< Vec4i > hierarchy;
 int largest_contour_index=0;
 int largest_area=0;

 Mat dst(src.rows,src.cols,CV_8UC1,Scalar::all(0)); //create destination image
 findContours( thr.clone(), contours, hierarchy,CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE ); // Find the contours in the image
 for( int i = 0; i< contours.size(); i++ ){
    double a=contourArea( contours[i],false);  //  Find the area of contour
    if(a>largest_area){
    largest_area=a;
    largest_contour_index=i;                //Store the index of largest contour
    }
 }

 drawContours( dst,contours, largest_contour_index, Scalar(255,255,255),CV_FILLED, 8, hierarchy );
 vector<vector<Point> > contours_poly(1);
 approxPolyDP( Mat(contours[largest_contour_index]), contours_poly[0],5, true );
 Rect boundRect=boundingRect(contours[largest_contour_index]);
 if(contours_poly[0].size()==4){
    std::vector<Point2f> quad_pts;
    std::vector<Point2f> squre_pts;
    quad_pts.Push_back(Point2f(contours_poly[0][0].x,contours_poly[0][0].y));
    quad_pts.Push_back(Point2f(contours_poly[0][1].x,contours_poly[0][1].y));
    quad_pts.Push_back(Point2f(contours_poly[0][3].x,contours_poly[0][3].y));
    quad_pts.Push_back(Point2f(contours_poly[0][2].x,contours_poly[0][2].y));
    squre_pts.Push_back(Point2f(boundRect.x,boundRect.y));
    squre_pts.Push_back(Point2f(boundRect.x,boundRect.y+boundRect.height));
    squre_pts.Push_back(Point2f(boundRect.x+boundRect.width,boundRect.y));
    squre_pts.Push_back(Point2f(boundRect.x+boundRect.width,boundRect.y+boundRect.height));

    Mat transmtx = getPerspectiveTransform(quad_pts,squre_pts);
    Mat transformed = Mat::zeros(src.rows, src.cols, CV_8UC3);
    warpPerspective(src, transformed, transmtx, src.size());
    Point P1=contours_poly[0][0];
    Point P2=contours_poly[0][1];
    Point P3=contours_poly[0][2];
    Point P4=contours_poly[0][3];


    line(src,P1,P2, Scalar(0,0,255),1,CV_AA,0);
    line(src,P2,P3, Scalar(0,0,255),1,CV_AA,0);
    line(src,P3,P4, Scalar(0,0,255),1,CV_AA,0);
    line(src,P4,P1, Scalar(0,0,255),1,CV_AA,0);
    rectangle(src,boundRect,Scalar(0,255,0),1,8,0);
    rectangle(transformed,boundRect,Scalar(0,255,0),1,8,0);

    imshow("quadrilateral", transformed);
    imshow("thr",thr);
    imshow("dst",dst);
    imshow("src",src);
    imwrite("result1.jpg",dst);
    imwrite("result2.jpg",src);
    imwrite("result3.jpg",transformed);
    waitKey();
   }
   else
    cout<<"Make sure that your are getting 4 corner using approxPolyDP..."<<endl;
37
Haris

teetheこれは通常、コードを採用するのではなく、特定の問題を解決するために他の誰かのコードに依存しているときに起こります。処理段階、およびそれらとあなたの画像の違いを見てください(彼らの画像から始めて、コードが機能することを確認する方法としては良い考えです):

  1. エッジマップを取得します。 -おそらくあなたのエッジが素晴らしいので動作します
  2. ハフ変換で線を検出します。 -輪郭だけでなく、カードの内側にも線があるため、失敗します。したがって、多くの誤ったアラーム線が予想されます
  3. ライン間の交点を見つけてコーナーを取得します。 -上記の理由で失敗する
  4. 近似多角形曲線に4つの頂点があるかどうかを確認します。 -失敗
  5. 左上隅、左下隅、右上隅、右下隅を決定します。 -失敗
  6. 透視変換を適用します。 -完全に失敗

問題を解決するには、周辺の線のみが抽出されるようにする必要があります。常に暗い背景がある場合は、この事実を使用して、他のコントラスト/極性を持つ線を破棄できます。または、すべての線を抽出してから、画像の境界に最も近い線を選択できます(背景に線がない場合)。

6
Vlad