12

How can I draw a bounding box on best matches in BF MATCHER using Python?

halfer
  • 19,824
  • 17
  • 99
  • 186
Ali110
  • 151
  • 1
  • 1
  • 7
  • 1
    Please read [Under what circumstances may I add “urgent” or other similar phrases to my question, in order to obtain faster answers?](//meta.stackoverflow.com/q/326569) - the summary is that this is not an ideal way to address volunteers, and is probably counterproductive to obtaining answers. Please refrain from adding this to your questions. – halfer Jul 31 '18 at 07:27

1 Answers1

23

Here is a summary of the approach it should be a proper solution:

  1. Detect keypoints and descriptors on the query image (img1)
  2. Detect keypoints and descriptors on the target image (img2)
  3. Find the matches or correspondences between the two sets of descriptors
  4. Use the best 10 matches to form a transformation matrix
  5. Transform the rectangle around img1 based on the transformation matrix
  6. Add offset to put the bounding box at the correct position
  7. Display the result image (as below).

BF Matching Result Image (Preview)

Here is the code:

import numpy as np
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('box.png', 0)          # query Image
img2 = cv2.imread('box_in_scene.png',0)  # target Image

# Initiate SIFT detector
orb = cv2.ORB_create()

# find the keypoints and descriptors with ORB
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# create BFMatcher object
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

# Match descriptors.
matches = bf.match(des1,des2)

# Sort them in the order of their distance.
matches = sorted(matches, key = lambda x:x.distance)

good_matches = matches[:10]

src_pts = np.float32([ kp1[m.queryIdx].pt for m in good_matches     ]).reshape(-1,1,2)
dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good_matches ]).reshape(-1,1,2)
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
matchesMask = mask.ravel().tolist()
h,w = img1.shape[:2]
pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)

dst = cv2.perspectiveTransform(pts,M)
dst += (w, 0)  # adding offset

draw_params = dict(matchColor = (0,255,0), # draw matches in green color
               singlePointColor = None,
               matchesMask = matchesMask, # draw only inliers
               flags = 2)

img3 = cv2.drawMatches(img1,kp1,img2,kp2,good_matches, None,**draw_params)

# Draw bounding box in Red
img3 = cv2.polylines(img3, [np.int32(dst)], True, (0,0,255),3, cv2.LINE_AA)

cv2.imshow("result", img3)
cv2.waitKey()
# or another option for display output
#plt.imshow(img3, 'result'), plt.show()
Howard GENG
  • 1,075
  • 7
  • 16
  • 4
    Please add further descriptions to your answer that will enable people to understand it and know why it is a good solution. Code only dumps do not make good answers (worthy of being voted up)! – Brian Tompsett - 汤莱恩 Jul 31 '18 at 07:11
  • 1
    I have added comments in the code. Is it not enough? – Howard GENG Jul 31 '18 at 07:17
  • The comments explain the individual statements but not why your solution should be chosen over another. – Brian Tompsett - 汤莱恩 Jul 31 '18 at 07:20
  • 1
    I would not suggest putting much more effort into this answer anyway - the question is too vague and is likely to close. – halfer Jul 31 '18 at 07:27
  • 1
    Please do not add complaints about voting into posts - voting is anonymous and broadly, people are to be allowed to vote how they will. We try to resist urgent begging anyway - if you see a zero-effort question that asks to jump the queue, you can answer it if you want, but I'd advise you not to if you can. Stack Overflow has a non-trivial help vampire problem, and the downvote you received may have been in that vein. – halfer Jul 31 '18 at 09:49
  • OK, I am sorry, Thank you for the suggestion, I will edit the answer. – Howard GENG Jul 31 '18 at 09:52
  • I want to draw bounding box/rectangle only on matches not draw the matches. – Ali110 Jul 31 '18 at 11:58
  • You can delete these two lines if you don't want to draw the matches: "draw_params = dict(matchColor = (0,255,0), # draw matches in green color singlePointColor = None, matchesMask = matchesMask, # draw only inliers flags = 2)" "img3 = cv2.drawMatches(img1,kp1,img2,kp2,good_matches, None,**draw_params)" – Howard GENG Jul 31 '18 at 12:03
  • okay i removed these lines but how to draw bounding box around matches?? – Ali110 Aug 01 '18 at 05:16
  • "draw bounding box around matches", do you mean draw a rectangle around the green lines? or draw a rectangle around the two sets of matched keypoints? – Howard GENG Aug 01 '18 at 05:35