Reputation: 48956
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
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
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.
Upvotes: 4