2016-02-26 17 views
5

OpenCV 3.0.0 đã thêm khả năng chỉ định mặt nạ khi thực hiện templateMatch. Khi tôi chỉ định một mặt nạ tôi nhận được lỗi này: error: (-215) (depth == CV_8U || depth == CV_32F) && type == _templ.type() && _img.dims() <= 2 in function matchTemplateMaskpython opencv cv2 matchTemplate với độ trong suốt

ảnh Template (PNG với tính minh bạch):

enter image description here

ảnh Nguồn:

enter image description here

# read the template emoji with the alpha channel 
template = cv2.imread(imagePath, cv2.IMREAD_UNCHANGED) 
channels = cv2.split(template) 
zero_channel = np.zeros_like(channels[0]) 
mask = np.array(channels[3]) 

# all elements in alpha_channel that have value 0 are set to 1 in the mask matrix 
mask[channels[3] == 0] = 1 

# all elements in alpha_channel that have value 100 are set to 0 in the mask matrix 
mask[channels[3] == 100] = 0 

transparent_mask = cv2.merge([zero_channel, zero_channel, zero_channel, mask]) 

print image.shape, image.dtype # (72, 232, 3) uint8 
print template.shape, template.dtype # (40, 40, 4) uint8 
print transparent_mask.shape, transparent_mask.dtype # (40, 40, 4) uint8 

# find the matches 
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED, mask=transparent_mask) 

Có vấn đề gì với loại hình ảnh? Tôi không thể tìm thấy bất kỳ ví dụ nào (bằng Python) bằng cách sử dụng tham số mặt nạ mới của phương thức matchTemplate. Có ai biết cách tạo mặt nạ không?

+0

Bạn đã tải 'hình ảnh' chưa? – Miki

+0

có. tất cả các hình ảnh được tải đúng cách. tôi nghĩ rằng các định dạng hình ảnh là sai dựa trên lỗi ném? – jaredrada

+0

có thể. Hãy thử tải với 'IMREAD_COLOR' để xem đó có phải là vấn đề không? – Miki

Trả lời

1

Môi trường của tôi đang sử dụng opencv 3.1.0 và python 2.7.11.

Đây là mã đang tìm kiếm hình ảnh trong một hình ảnh khác mà mẫu đang sử dụng độ trong suốt (kênh alpha). Tôi hy vọng điều này có thể giúp bạn.

def getMultiFullInfo(all_matches,w,h): 
    #This function will rearrange the data and calculate the tuple 
    # for the square and the center and the tolerance for each point 
    result = [] 
    for match in all_matches: 
     tlx = match[0] 
     tly = match[1] 
     top_left = (tlx,tly) 
     brx = match[0] + w 
     bry = match[1] + h 
     bottom_right = (brx,bry)  
     centerx = match[0] + w/2 
     centery = match[1] + h/2 
     center = [centerx,centery] 
     result.append({'top_left':top_left,'bottom_right':bottom_right,'center':center,'tolerance':match[2]}) 
    return result 

def getMulti(res, tolerance,w,h): 
    #We get an opencv image in the form of a numpy array and we need to 
    # find all the occurances in there knowing that 2 squares cannot intersect 
    #This will give us exactly the matches that are unique 

    #First we need to get all the points where value is >= tolerance 
    #This wil get sometimes some squares that vary only from some pixels and that are overlapping 
    all_matches_full = np.where (res >= tolerance) 
    logging.debug('*************Start of getMulti function') 
    logging.debug('All >= tolerance') 
    logging.debug(all_matches_full) 
    #Now we need to arrange it in x,y coordinates 
    all_matches_coords = [] 
    for pt in zip(*all_matches_full[::-1]): 
     all_matches_coords.append([pt[0],pt[1],res[pt[1]][pt[0]]]) 
    logging.debug('In coords form') 
    logging.debug(all_matches_coords) 
    #Let's sort the new array 
    all_matches_coords = sorted(all_matches_coords) 
    logging.debug('Sorted') 
    logging.debug(all_matches_coords) 

    #This function will be called only when there is at least one match so if matchtemplate returns something 
    #This means we have found at least one record so we can prepare the analysis and loop through each records 
    all_matches = [[all_matches_coords[0][0],all_matches_coords[0][1],all_matches_coords[0][2]]] 
    i=1 
    for pt in all_matches_coords: 
     found_in_existing = False 
     logging.debug('%s)',i) 
     for match in all_matches: 
      logging.debug(match) 
      #This is the test to make sure that the square we analyse doesn't overlap with one of the squares already found 
      if pt[0] >= (match[0]-w) and pt[0] <= (match[0]+w) and pt[1] >= (match[1]-h) and pt[1] <= (match[1]+h): 
       found_in_existing = True 
       if pt[2] > match[2]: 
        match[0] = pt[0] 
        match[1] = pt[1] 
        match[2] = res[pt[1]][pt[0]] 
     if not found_in_existing: 
      all_matches.append([pt[0],pt[1],res[pt[1]][pt[0]]]) 
     i += 1 
    logging.debug('Final') 
    logging.debug(all_matches) 
    logging.debug('Final with all info') 
    #Before returning the result, we will arrange it with data easily accessible 
    all_matches = getMultiFullInfo(all_matches,w,h) 
    logging.debug(all_matches) 
    logging.debug('*************End of getMulti function') 
    return all_matches 

def checkPicture(screenshot,templateFile, tolerance, multiple = False): 
    #This is an intermediary function so that the actual function doesn't include too much specific arguments 
    #We open the config file 

    configFile = 'test.cfg' 

    config = SafeConfigParser() 

    config.read(configFile) 
    basepics_dir = config.get('general', 'basepics_dir') 

    debug_dir = config.get('general', 'debug_dir') 

    font = cv2.FONT_HERSHEY_PLAIN 

    #The value -1 means we keep the file as is meaning with color and alpha channel if any 
    # btw, 0 means grayscale and 1 is color 
    template = cv2.imread(basepics_dir+templateFile,-1) 

    #Now we search in the picture 
    result = findPicture(screenshot,template, tolerance, multiple) 
    #If it didn't get any result, we log the best value 

    if not result['res']: 
     logging.debug('Best value found for %s is: %f',templateFile,result['best_val']) 

    elif logging.getLogger().getEffectiveLevel() == 10: 
     screenshot_with_rectangle = screenshot.copy() 
     for pt in result['points']: 
      cv2.rectangle(screenshot_with_rectangle, pt['top_left'], pt['bottom_right'], 255, 2) 
      fileName_top_left = (pt['top_left'][0],pt['top_left'][1]-10) 
      cv2.putText(screenshot_with_rectangle,str(pt['tolerance'])[:4],fileName_top_left, font, 1,(255,255,255),2) 
      #Now we save to the file if needed 
      filename = time.strftime("%Y%m%d-%H%M%S") + '_' + templateFile[:-4] + '.jpg' 
      cv2.imwrite(debug_dir + filename, screenshot_with_rectangle) 

    result['name']=templateFile 

    return result 

def extractAlpha(img, hardedge = True): 
    if img.shape[2]>3: 
     logging.debug('Mask detected') 
     channels = cv2.split(img) 

     mask = np.array(channels[3]) 
     if hardedge: 
      for idx in xrange(len(mask[0])): 
       if mask[0][idx] <=128: 
        mask[0][idx] = 0 
       else: 
        mask[0][idx] = 255 


     mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR) 
     img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR) 


     return {'res':True,'image':img,'mask':mask} 
    else: 
     return {'res':False,'image':img} 


def findPicture(screenshot,template, tolerance, multiple = False): 

    #This function will work with color images 3 channels minimum 
    #The template can have an alpha channel and we will extract it to have the mask 


    logging.debug('Looking for %s' , template) 

    logging.debug('Tolerance to check is %f' , tolerance) 


    logging.debug('*************Start of checkPicture') 


    h = template.shape[0] 
    w = template.shape[1] 

    #We will now extract the alpha channel 
    tmpl = extractAlpha(template) 

    logging.debug('Image width: %d - Image heigth: %d',w,h) 


    # the method used for comparison, can be ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR','cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED'] 

    meth = 'cv2.TM_CCORR_NORMED' 

    method = eval(meth) 



    # Apply template Matching 
    if tmpl['res']: 

     res = cv2.matchTemplate(screenshot,tmpl['image'],method, mask = tmpl['mask']) 
    else: 
     res = cv2.matchTemplate(screenshot,tmpl['image'],method) 


    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) 



    # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum 

    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]: 

     top_left = min_loc 

     best_val = 1 - min_val 

    else: 

     top_left = max_loc 

     best_val = max_val 
    #We need to ensure we found at least one match otherwise we return false 
    if best_val >= tolerance: 

     if multiple: 
      #We need to find all the time the image is found 
      all_matches = getMulti(res, float(tolerance),int(w),int(h)) 
     else: 
      bottom_right = (top_left[0] + w, top_left[1] + h) 

      center = (top_left[0] + (w/2), top_left[1] + (h/2)) 
      all_matches = [{'top_left':top_left,'bottom_right':bottom_right,'center':center,'tolerance':best_val}] 

     #point will be in the form: [{'tolerance': 0.9889718890190125, 'center': (470, 193), 'bottom_right': (597, 215), 'top_left': (343, 172)}] 
     logging.debug('The points found will be:') 
     logging.debug(all_matches) 
     logging.debug('*************End of checkPicture') 

     return {'res': True,'points':all_matches} 

    else: 
     logging.debug('Could not find a value above tolerance') 
     logging.debug('*************End of checkPicture') 

     return {'res': False,'best_val':best_val} 
+1

Có thực sự phức tạp này chỉ để làm mẫu phù hợp với mặt nạ alpha ? – michaelsnowden

3

tôi đã có thể có được điều này để làm việc sử dụng Python 2.7.13 và opencv-python==3.1.0.4

Đây là mã cho nó.

import cv2 
import numpy as np 
import sys 

if len(sys.argv) < 3: 
    print 'Usage: python match.py <template.png> <image.png>' 
    sys.exit() 

template_path = sys.argv[1] 
template = cv2.imread(template_path, cv2.IMREAD_UNCHANGED) 
channels = cv2.split(template) 
zero_channel = np.zeros_like(channels[0]) 
mask = np.array(channels[3]) 

image_path = sys.argv[2] 
image = cv2.imread(image_path, cv2.IMREAD_UNCHANGED) 

mask[channels[3] == 0] = 1 
mask[channels[3] == 100] = 0 

# transparent_mask = None 
# According to http://www.devsplanet.com/question/35658323, we can only use 
# cv2.TM_SQDIFF or cv2.TM_CCORR_NORMED 
# All methods can be seen here: 
# http://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/template_matching/template_matching.html#which-are-the-matching-methods-available-in-opencv 
method = cv2.TM_SQDIFF # R(x,y) = \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2 (essentially, sum of squared differences) 

transparent_mask = cv2.merge([zero_channel, zero_channel, zero_channel, mask]) 
result = cv2.matchTemplate(image, template, method, mask=transparent_mask) 
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) 
print 'Lowest squared difference WITH mask', min_val 

# Now we'll try it without the mask (should give a much larger error) 
transparent_mask = None 
result = cv2.matchTemplate(image, template, method, mask=transparent_mask) 
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) 
print 'Lowest squared difference WITHOUT mask', min_val 

Here nó là một ý chính.

Về cơ bản, bạn cần đảm bảo bạn đang sử dụng đúng phương pháp đối sánh.

Các vấn đề liên quan