0

Let's say i have found a contour on an image. What is the best approach to finding the position of this contour on image 2?

I see two options: Either i draw the contour with a white line and match that image on image 2 or i somehow (is this even possible?) match the contour on image 2 directly.

The contents within the contour is completely random, but the contour from image 1 drawn with a white 1px line would be an exact match, assuming i could template match an image with transparency.

Here are example images of a found, drawn and saved contour (image 1) and an image in which i need to locate image 1 (image 2). https://i.stack.imgur.com/4IxOp.jpg

Finding the contour without having to draw and save it first would be preferred, but i assume matching the drawn contour is more straight forward.

Thanks

Edit:

This is my full code. It takes a full_image and a piece, which it will match on the full image. Lastly it exports some results.

full_image = cv2.imread('puzzle_1.jpg')    
piece = cv2.imread('piece_1.png', cv2.IMREAD_UNCHANGED)
partial_image = cv2.cvtColor(piece,cv2.COLOR_BGR2GRAY)

contours, hierarchy = cv2.findContours(partial_image.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
   
template = np.zeros((55, 55, 4), dtype=np.uint8)

cv2.drawContours(template, contours, -1, (255, 255, 255, 255),1)
hh, ww = template.shape[:2]

puzzleP = template[:,:,0:3]
alpha = template[:,:,3]
alpha = cv2.merge([alpha,alpha,alpha])

correlation = cv2.matchTemplate(full_image, puzzleP, cv2.TM_CCORR_NORMED, mask=alpha)

threshhold = 0.98
loc = np.where(correlation >= threshhold)

result = full_image.copy()
for pt in zip(*loc[::-1]):
    cv2.rectangle(result, pt, (pt[0]+ww, pt[1]+hh), (0,0,255), 1)
    print(pt)
    
cv2.imwrite('puzzle_piece.png', puzzleP)
cv2.imwrite('full_image_alpha.png', alpha)
cv2.imwrite('full_image_matches.jpg', result)  

Here is a well working result and an invalid result https://i.stack.imgur.com/zQxnp.jpg

Any tips on improvement would be greatly appreciated!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
ole
  • 159
  • 2
  • 13
  • Sorry, I do not understand your question. The template contour has no matching shape in the second image. So how do you know where to place it? If you have some coordinate for placing it. You can save the contour as a white line on a black image and then overlay it onto the second image at some desired offset coordinate. Please clarify your question further. – fmw42 Aug 04 '20 at 19:52
  • I will attempt to clarify it more. I literally just need to find the position of image 1 on image 2, regardless of what content is within the shape on image 2. I might be confusing terms here. In other words: The line drawn on image 1 is present within image 2, but on image 1 the content within this line is transparent, where as it has some picture within the line on image 2. How would i find the position of a bounding box of this white line (drawn contour) on image 2? – ole Aug 04 '20 at 20:07
  • I am not trying to draw it a any specific position (I already drew it on image 1). I'm just curious if it's easier to match the drawn contour (image 1) on image 2. Or if there's a way to skip drawing and saving it, in order to find the bounding box on image 2. – ole Aug 04 '20 at 20:10
  • 1
    You can use matchTemplate with a mask image to ignore regions of the template. So if you have a transparent template, then extract the alpha channel and use that as a mask using the template BGR channels as the template image in matchTemplate. See https://docs.opencv.org/4.1.1/df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be and https://stackoverflow.com/questions/61779288/how-to-template-match-a-simple-2d-shape-in-opencv/61780200#61780200 and https://stackoverflow.com/questions/59759374/cv2-matchtemplate-finds-wrong-template-in-image/59779209#59779209 – fmw42 Aug 04 '20 at 20:54
  • Thank you, i will give that a try! – ole Aug 04 '20 at 21:36
  • You can make this an answer and i'll mark as the right one. I got much closer to my goal, now i just need to figure out why i'm getting too many matches and why higher threshold sometimes hides the "best"/ideal match. Might make another question about that. https://imgur.com/a/YE34vEx Thanks again. – ole Aug 05 '20 at 00:30
  • Post your examples and code. Perhaps we can make other suggestions. – fmw42 Aug 05 '20 at 02:23
  • Will do later today, thanks! – ole Aug 05 '20 at 12:47

1 Answers1

1

You can use matchTemplate in Python/OpenCV with a mask image to ignore regions of the template. So if you have a transparent template, then extract the alpha channel and use that as a mask using the template BGR channels as the template image in matchTemplate. See

https://docs.opencv.org/4.1.1/df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be

cv2.matchTemplate finds wrong template in image

How to template match a simple 2D shape in OpenCV?

fmw42
  • 46,825
  • 10
  • 62
  • 80
  • I've edited my question with information regarding optimization of my solution. It might be a better idea to write an entirely new queustion? – ole Aug 06 '20 at 12:55