web-dev-qa-db-ja.com

OpenCV 3.0 LineIterator

Pythonを使用するOpenCV3.0で LineIterator を使用したいのですが、Python用に構築されたOpenCV 3.0でも引き続き使用できますか?インターネット上の回答はすべて、cvモジュールの一部であるcv.InitLineIteratorを指しているようです。このモジュールをインポートしようとしましたが、現在のビルドには含まれていないようです。名前が変更されましたか、それとも厳密に削除されましたか?

19
mohikhsan

私は自分の問題を解決しました。ラインイテレータはcv2ライブラリでは使用できないようです。そのため、独自のラインイテレータを作成しました。ループは使用されないため、かなり高速である必要があります。誰かがそれを必要とする場合のコードは次のとおりです。

def createLineIterator(P1, P2, img):
    """
    Produces and array that consists of the coordinates and intensities of each pixel in a line between two points

    Parameters:
        -P1: a numpy array that consists of the coordinate of the first point (x,y)
        -P2: a numpy array that consists of the coordinate of the second point (x,y)
        -img: the image being processed

    Returns:
        -it: a numpy array that consists of the coordinates and intensities of each pixel in the radii (shape: [numPixels, 3], row = [x,y,intensity])     
    """
   #define local variables for readability
   imageH = img.shape[0]
   imageW = img.shape[1]
   P1X = P1[0]
   P1Y = P1[1]
   P2X = P2[0]
   P2Y = P2[1]

   #difference and absolute difference between points
   #used to calculate slope and relative location between points
   dX = P2X - P1X
   dY = P2Y - P1Y
   dXa = np.abs(dX)
   dYa = np.abs(dY)

   #predefine numpy array for output based on distance between points
   itbuffer = np.empty(shape=(np.maximum(dYa,dXa),3),dtype=np.float32)
   itbuffer.fill(np.nan)

   #Obtain coordinates along the line using a form of Bresenham's algorithm
   negY = P1Y > P2Y
   negX = P1X > P2X
   if P1X == P2X: #vertical line segment
       itbuffer[:,0] = P1X
       if negY:
           itbuffer[:,1] = np.arange(P1Y - 1,P1Y - dYa - 1,-1)
       else:
           itbuffer[:,1] = np.arange(P1Y+1,P1Y+dYa+1)              
   Elif P1Y == P2Y: #horizontal line segment
       itbuffer[:,1] = P1Y
       if negX:
           itbuffer[:,0] = np.arange(P1X-1,P1X-dXa-1,-1)
       else:
           itbuffer[:,0] = np.arange(P1X+1,P1X+dXa+1)
   else: #diagonal line segment
       steepSlope = dYa > dXa
       if steepSlope:
           slope = dX.astype(np.float32)/dY.astype(np.float32)
           if negY:
               itbuffer[:,1] = np.arange(P1Y-1,P1Y-dYa-1,-1)
           else:
               itbuffer[:,1] = np.arange(P1Y+1,P1Y+dYa+1)
           itbuffer[:,0] = (slope*(itbuffer[:,1]-P1Y)).astype(np.int) + P1X
       else:
           slope = dY.astype(np.float32)/dX.astype(np.float32)
           if negX:
               itbuffer[:,0] = np.arange(P1X-1,P1X-dXa-1,-1)
           else:
               itbuffer[:,0] = np.arange(P1X+1,P1X+dXa+1)
           itbuffer[:,1] = (slope*(itbuffer[:,0]-P1X)).astype(np.int) + P1Y

   #Remove points outside of image
   colX = itbuffer[:,0]
   colY = itbuffer[:,1]
   itbuffer = itbuffer[(colX >= 0) & (colY >=0) & (colX<imageW) & (colY<imageH)]

   #Get intensities from img ndarray
   itbuffer[:,2] = img[itbuffer[:,1].astype(np.uint),itbuffer[:,0].astype(np.uint)]

   return itbuffer
47
mohikhsan

前の回答が言っているように、それは実装されていないので、あなたはそれを自分でしなければなりません。私は最初からそれをしませんでした。私にとって正しく機能しなかった最も投票された答えとは異なり、すべてのケースを正しく処理する必要がある、より洗練されたより現代的な方法で関数の一部を書き直しただけです。 here から例を取り、クリーンアップとスタイリングを行いました。コメントしてください。また、OpenCv 4.xのソースコードの drawing.cpp にあるソースコードのようなクリップラインテストを追加しました。参照とハードワークに感謝します。

    def bresenham_march(img, p1, p2):
        x1 = p1[0]
        y1 = p1[1]
        x2 = p2[0]
        y2 = p2[1]
        #tests if any coordinate is outside the image
        if ( 
            x1 >= img.shape[0]
            or x2 >= img.shape[0]
            or y1 >= img.shape[1]
            or y2 >= img.shape[1]
        ): #tests if line is in image, necessary because some part of the line must be inside, it respects the case that the two points are outside
            if not cv2.clipLine((0, 0, *img.shape), p1, p2):
                print("not in region")
                return

        steep = math.fabs(y2 - y1) > math.fabs(x2 - x1)
        if steep:
            x1, y1 = y1, x1
            x2, y2 = y2, x2

        # takes left to right
        also_steep = x1 > x2
        if also_steep:
            x1, x2 = x2, x1
            y1, y2 = y2, y1

        dx = x2 - x1
        dy = math.fabs(y2 - y1)
        error = 0.0
        delta_error = 0.0
        # Default if dx is zero
        if dx != 0:
            delta_error = math.fabs(dy / dx)

        y_step = 1 if y1 < y2 else -1

        y = y1
        ret = []
        for x in range(x1, x2):
            p = (y, x) if steep else (x, y)
            if p[0] < img.shape[0] and p[1] < img.shape[1]:
                ret.append((p, img[p]))
            error += delta_error
            if error >= 0.5:
                y += y_step
                error -= 1
        if also_steep:  # because we took the left to right instead
            ret.reverse()
        return ret
1
trenixjetix