Simplicity
Simplicity

Reputation: 48956

How to determine the line width in OpenCV's drawMatches

I'm using OpenCV's drawMatches() to draw the matches between keypoints. Is there a way we can specify the width of the lines drawn, as in my case they appear very thin.

Thanks.

Upvotes: 3

Views: 3668

Answers (2)

Ynjxsjmh
Ynjxsjmh

Reputation: 30050

Thankfully, in Jun 2021, gasparitiago proposed a pull request to address this issue. This pr introduced a matchesThickness parameter to customize line thickness. This feature was released in V3.4.15 / V4.5.3.

To use this param in Python, you can try as

img = cv.drawMatches(img1, kp1, img2, kp2, matches, None, matchesThickness=5, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
plt.imshow(img)
plt.show()

If your version is earlier, there is also a solution on gist. However, the numpy random generated color has some problems, the fixed code is as below. The thickness is hard coded in function, you can change it as you like.

# drawMatches cv2 version
def draw_matches(img1, kp1, img2, kp2, matches, color=None): 
    """Draws lines between matching keypoints of two images.  
    Keypoints not in a matching pair are not drawn.
    Places the images side by side in a new image and draws circles 
    around each keypoint, with line segments connecting matching pairs.
    You can tweak the r, thickness, and figsize values as needed.
    Args:
        img1: An openCV image ndarray in a grayscale or color format.
        kp1: A list of cv2.KeyPoint objects for img1.
        img2: An openCV image ndarray of the same format and with the same 
        element type as img1.
        kp2: A list of cv2.KeyPoint objects for img2.
        matches: A list of DMatch objects whose trainIdx attribute refers to 
        img1 keypoints and whose queryIdx attribute refers to img2 keypoints.
        color: The color of the circles and connecting lines drawn on the images.  
        A 3-tuple for color images, a scalar for grayscale images.  If None, these
        values are randomly generated.  
    """
    # We're drawing them side by side.  Get dimensions accordingly.
    # Handle both color and grayscale images.
    if len(img1.shape) == 3:
        new_shape = (max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], img1.shape[2])
    elif len(img1.shape) == 2:
        new_shape = (max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1])
    new_img = np.zeros(new_shape, type(img1.flat[0]))  
    # Place images onto the new image.
    new_img[0:img1.shape[0],0:img1.shape[1]] = img1
    new_img[0:img2.shape[0],img1.shape[1]:img1.shape[1]+img2.shape[1]] = img2
    
    # Draw lines between matches.  Make sure to offset kp coords in second image appropriately.
    r = 15
    thickness = 2
    if color:
        c = color
    for m in matches:
        # Generate random color for RGB/BGR and grayscale images as needed.
        if not color: 
            c = np.random.randint(0,256,3) if len(img1.shape) == 3 else np.random.randint(0,256)
            c = ( int (c[ 0 ]), int (c[ 1 ]), int (c[ 2 ])
        # So the keypoint locs are stored as a tuple of floats.  cv2.line(), like most other things,
        # wants locs as a tuple of ints.
        end1 = tuple(np.round(kp1[m.trainIdx].pt).astype(int))
        end2 = tuple(np.round(kp2[m.queryIdx].pt).astype(int) + np.array([img1.shape[1], 0]))
        cv2.line(new_img, end1, end2, c, thickness)
        cv2.circle(new_img, end1, r, c, thickness)
        cv2.circle(new_img, end2, r, c, thickness)
    
    plt.figure(figsize=(15,15))
    plt.imshow(new_img)
    plt.show()

Rather than the 3 lines in previous example to show the image, this function is much simpler, you can use it like

draw_matches(img1, kp1, img2, kp2, matches, None)

Upvotes: 3

Demplo
Demplo

Reputation: 551

It should not be possible unless you are willing to edit and recompile openCV.

From modules/features2d/src/draw.cpp

line( outImg,
  Point(cvRound(pt1.x*draw_multiplier), cvRound(pt1.y*draw_multiplier)),
  Point(cvRound(dpt2.x*draw_multiplier), cvRound(dpt2.y*draw_multiplier)),
  color, 1, LINE_AA, draw_shift_bits );

This call draws the line between the two keypoints and the 1 in the function call specifies the thickness of the line (see openCV doc). Unfortunately it has been hard-coded inside the draw function.

However it looks quite strange that you are not able to correctly visualize the matches. They are quite fine to me.

some stereo matches

Upvotes: 4

Related Questions