0

im using matchtemplate to detect 2x2 sqaures on dark background. with my code, it detects most of the squares without any problem but it fails detecting when the color of the squares are dark and blackish. i tried normalize in opencv but it didnt work well.. also tried using mask but it didnt work either (maybe i used the mask feature wrong?) since i lack of understanding image preprocessing and opencv. i believe theres so many things im missing but i just cant figure out what im missing. i would really appreciate it if someone could help me out

import cv2
import numpy as np
import time
import win32gui, win32ui, win32con

    
def imagesearch(per):



    img = cv2.imread('target.png', cv2.IMREAD_GRAYSCALE)
    img1 = cv2.imread('target.png')

    template = cv2.imread('./map/monster.png', cv2.IMREAD_GRAYSCALE)
    w, h = template.shape[::-1]

    meth = [cv2.TM_CCOEFF, cv2.TM_CCOEFF_NORMED, cv2.TM_CCORR, cv2.TM_CCORR_NORMED, cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]

    res = cv2.matchTemplate(img, template, meth[3])


    threshold = per 
    loc = np.where(res>=threshold) 


    if loc[0].any():


        for pt in zip(*loc[::-1]):
            cv2.rectangle(img1, pt, (pt[0] + w, pt[1] + h), (0,0,255), 1) 


            
    cv2.imshow("dst", img1)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


imagesearch(0.8)

enter image description here

template

enter image description here

image

enter image description here

result

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
wookidookik123
  • 79
  • 2
  • 10
  • You should be template matching with a mask. Also some metrics have a best match when the score is low rather than high, e.g. TM_SQDIFF looks for best match at low scores so your threshold needs to be low. – fmw42 Oct 22 '22 at 23:11

1 Answers1

1

The problem you are facing is that part of the squares you want to detect does not follow the rule "lighter than background" and are "darker than background". The solution to this problem is to use template image with reversed colors:

inversed template

^-- inversed template

import cv2
import numpy as np
import time
    
def imagesearch(per):

    img  = cv2.imread('openCV_squareDetection.png', cv2.IMREAD_GRAYSCALE)
    img1 = cv2.imread('openCV_squareDetection.png')

    template_inversed = cv2.imread('openCV_squareDetection_template_inversed.png', cv2.IMREAD_GRAYSCALE)
    template          = cv2.imread('openCV_squareDetection_template.png',          cv2.IMREAD_GRAYSCALE)
    w, h = template.shape[::-1]

    meth = [cv2.TM_CCOEFF, cv2.TM_CCOEFF_NORMED, cv2.TM_CCORR, cv2.TM_CCORR_NORMED, cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]

    res          = cv2.matchTemplate(img, template         , meth[1])
    res_inversed = cv2.matchTemplate(img, template_inversed, meth[1])
    threshold = per 

    loc          = np.where(res         >=threshold) 
    loc_inversed = np.where(res_inversed>=threshold) 

    if loc[         0].any():
        for pt in zip(*loc[::-1]):
            cv2.rectangle(img1, pt, (pt[0] + w, pt[1] + h), (0,0,255), 1) 
    if loc_inversed[0].any():
        for pt in zip(*loc_inversed[::-1]):
            cv2.rectangle(img1, pt, (pt[0] + w, pt[1] + h), (0,0,255), 1) 

    cv2.imshow("dst", img1)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

imagesearch(0.95)

result

Claudio
  • 7,474
  • 3
  • 18
  • 48
  • if you dont mind, can you also take a look at this one too please?https://stackoverflow.com/questions/74168148/python-how-do-i-matchtemplate-transparent-image-with-opencv – wookidookik123 Oct 23 '22 at 01:28
  • Notice, that with in the conditions part modified algo from the answer to your question mentioned above you can detect the small squares, too, and if the background image without the rectangles is always the same and known the solution can be optimized for better speed. – Claudio Oct 24 '22 at 10:06