2013-02-19 98 views
18

這個問題已經asked,但我仍然不明白。我通過從一組點中調用cv::findHomography來獲得單應性矩陣。我需要檢查它是否有關。
建議的方法是計算內部極大再投影誤差並將其與閾值進行比較。但經過這樣的過濾後,我一直使用目標包圍盒變換成幾乎一條直線或一些奇怪的非凸四邊形,有自相交等瘋狂變換。
可以使用什麼約束來檢查單應矩陣本身是否足夠?如何檢查獲得的單應矩陣是否好?

+0

請參閱[這裏] [1]的答案我張貼前一段時間。 [1]:http://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv/10981249#10981249 – 2013-02-19 13:42:08

回答

25

你的問題是數學問題。給定3x3的矩陣,決定它是否代表了一個良好的剛性轉換。 這是很難界定什麼是「好」,但這裏有一些線索,可以幫助你

  1. 單應應保留多邊形點的方向。設計一個簡單的測試。點(0,0),(imwidth,0),(寬度,高度),(0,高度)表示具有順時針排列點的四邊形。在這些點上應用單應性,並查看它們是否仍順時針排列,如果它們逆時針旋轉,那麼您的單元鏡頭正在翻轉(鏡像)有時仍然正常的圖像。但是,如果你的觀點不符合你的「壞單應」
  2. 單應性不會太多地改變對象的比例。例如,如果您希望它將圖像縮小或放大X倍,請檢查此規則。用單應變換4個點(0,0),(imwidth,0),(width-1,height),(0,height),並計算四邊形面積(opencv計算面積的面積)的地區太大(或太小),你可能有一個錯誤。
  3. 好的單應性通常使用較低的視角值。通常情況下,如果圖像的大小是〜1000x1000像素,那麼這些值應該是〜0.005-0.001。高視角會導致巨大的扭曲,這可能是一個錯誤。如果你不知道這些值在哪裏閱讀我的文章: trying to understand the Affine Transform 。它解釋了仿射變換數學,其他2個值是透視參數。

我認爲,如果你檢查上述3個條件(條件2是最重要的),你將能夠檢測到大部分的問題。 祝你好運

+1

除了第一個建議檢查的http:/ /answers.opencv.org/question/2588/check-if-homography-is-good/。計算單應矩陣中應該是旋轉子矩陣的行列式,並檢查其是否大於或等於零告訴你方向是否保留(基本上計算這樣的行列式等於畢達哥拉斯公式)。 – rbaleksandar 2014-05-27 12:35:21

0

編輯:此答案與問題無關,但討論可能有助於嘗試使用匹配結果進行識別的人像我一樣!

這可能幫助別人:

Point2f[] objCorners = { new Point2f(0, 0), 
    new Point2f(img1.Cols, 0), 
    new Point2f(img1.Cols, img1.Rows), 
    new Point2f(0, img1.Rows) }; 

Point2d[] sceneCorners = MyPerspectiveTransform3(objCorners, homography); 
double marginH = img2.Width * 0.1d; 
double marginV = img2.Height * 0.1d; 
bool homographyOK = isInside(-marginH, -marginV, img2.Width + marginH, img2.Height + marginV, sceneCorners); 
if (homographyOK) 
    for (int i = 1; i < sceneCorners.Length; i++) 
     if (sceneCorners[i - 1].DistanceTo(sceneCorners[i]) < 1) 
     { 
      homographyOK = false; 
      break; 
     } 
if (homographyOK) 
    homographyOK = isConvex(sceneCorners); 
if (homographyOK) 
    homographyOK = minAngleCheck(sceneCorners, 20d); 




    private static bool isInside(dynamic minX, dynamic minY, dynamic maxX, dynamic maxY, dynamic coors) 
     { 
      foreach (var c in coors) 
       if ((c.X < minX) || (c.Y < minY) || (c.X > maxX) || (c.Y > maxY)) 
        return false; 
      return true; 
     }  
     private static bool isLeft(dynamic a, dynamic b, dynamic c) 
     { 
      return ((b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X)) > 0; 
     } 
     private static bool isConvex<T>(IEnumerable<T> points) 
     { 
      var lst = points.ToList(); 
      if (lst.Count > 2) 
      { 
       bool left = isLeft(lst[0], lst[1], lst[2]); 
       lst.Add(lst.First()); 
       for (int i = 3; i < lst.Count; i++) 
        if (isLeft(lst[i - 2], lst[i - 1], lst[i]) != left) 
         return false; 
       return true; 
      } 
      else 
       return false; 
     } 
     private static bool minAngleCheck<T>(IEnumerable<T> points, double angle_InDegrees) 
     { 
      //20d * Math.PI/180d 
      var lst = points.ToList(); 
      if (lst.Count > 2) 
      {     
       lst.Add(lst.First()); 
       for (int i = 2; i < lst.Count; i++) 
       { 
        double a1 = angleInDegrees(lst[i - 2], lst[i-1]); 
        double a2 = angleInDegrees(lst[i], lst[i - 1]); 
        double d = Math.Abs(a1 - a2) % 180d; 

        if ((d < angle_InDegrees) || ((180d - d) < angle_InDegrees)) 
         return false; 
       } 
       return true; 
      } 
      else 
       return false; 
     } 
     private static double angleInDegrees(dynamic v1, dynamic v2) 
     { 
      return (radianToDegree(Math.Atan2(v1.Y - v2.Y, v1.X - v2.X))) % 360d; 
     } 
     private static double radianToDegree(double radian) 
     { 
      var degree = radian * (180d/Math.PI); 
      if (degree < 0d) 
       degree = 360d + degree; 

      return degree; 
     } 
     static Point2d[] MyPerspectiveTransform3(Point2f[] yourData, Mat transformationMatrix) 
     { 
      Point2f[] ret = Cv2.PerspectiveTransform(yourData, transformationMatrix); 
      return ret.Select(point2fToPoint2d).ToArray(); 
     } 

enter image description here

+0

太多的代碼沒有評論只是*有用*爲絕望 – user3085931 2017-01-25 09:16:20

+0

我認爲函數名稱解釋自己。這是我能夠做到的。總結:在單應性變換後,如果發現的形狀是1)在可接受區域內,2)大小是可接受的,3)形狀是凸的或不是(這裏是錯誤的)4)形狀的內角是可接受的或不。有一些錯誤,當我的工作結束時我會更新代碼。是的,如果還有其他方法可以實現更好的檢查,我絕望了。我也喜歡絕望,並且一直在閱讀其他人的代碼。 – Koray 2017-01-25 10:15:12

+0

供參考:http://stackoverflow.com/questions/11053099/how-can-you-tell-if-a-homography-matrix-is-acceptable-or-not在我看來是我見過的最合理的解決方案爲這個題目。 – user3085931 2017-01-25 10:46:05