def watch_for_card(camera): has_moved = False been_to_base = False global captures global font captures = [] font = cv.InitFont(cv.CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0) img = cv.QueryFrame(camera) size = cv.GetSize(img) n_pixels = size[0] * size[1] grey = cv.CreateImage(size, 8, 1) recent_frames = [cv.CloneImage(grey)] base = cv.CloneImage(grey) cv.CvtColor(img, base, cv.CV_RGB2GRAY) # cv.ShowImage('card', base) tmp = cv.CloneImage(grey) while True: img = cv.QueryFrame(camera) cv.CvtColor(img, grey, cv.CV_RGB2GRAY) biggest_diff = max(sum_squared(grey, frame) / n_pixels for frame in recent_frames) # display the cam view cv.PutText(img, "%s" % biggest_diff, (1, 24), font, (255, 255, 255)) cv.ShowImage('win', img) recent_frames.append(cv.CloneImage(grey)) if len(recent_frames) > 3: del recent_frames[0] # check for keystroke c = cv.WaitKey(10) # if there was a keystroke, reset the last capture if c == 27: return captures elif c == 32: has_moved = True been_to_base = True elif c == 114: base = cv.CloneImage(grey) # if we're stable-ish if biggest_diff < 10: # if we're similar to base, update base # else, check for card # base_diff = max(sum_squared(base, frame) / n_pixels for frame in recent_frames) base_corr = 0 try: base_corr = min(ccoeff_normed(base, frame) for frame in recent_frames) except: print ("Unable to calculate the base_corr") pass # cv.ShowImage('debug', base) """for i, frame in enumerate(recent_frames): tmp = cv.CloneImage(base) cv.Sub(base, frame, tmp) cv.Pow(tmp, tmp, 2.0) cv.PutText(tmp, "%s" % (i+1), (1,24), font, (255, 255, 255)) #my_diff = sum_squared(base, frame) / n_pixels my_diff = ccoeff_normed(base, frame) #score(base, frame, cv.CV_TM_CCOEFF_NORMED) cv.PutText(tmp, "%s" % my_diff, (40, 24), font, (255, 255, 255)) cv.ShowImage('dbg%s' % (i+1), tmp)""" # print "stable. corr = %s. moved = %s. been_to_base = %s" % (base_corr, has_moved, been_to_base) if base_corr > 0.75 and not been_to_base: base = cv.CloneImage(grey) # cv.ShowImage('debug', base) has_moved = False been_to_base = True print "STATE: been to base. waiting for move" elif has_moved and been_to_base: corners = detect_card(grey, base) if corners is not None: card = get_card(grey, corners) cv.Flip(card, card, -1) captures.append(card) update_windows() # cv.ShowImage('card', card) has_moved = False been_to_base = False print "STATE: detected. waiting for go to base" else: if not has_moved: print "STATE: has moved. waiting for stable" has_moved = True
def watch_for_card(camera): has_moved = False been_to_base = False global captures global font captures = [] font = cv.InitFont(cv.CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0) img = cv.QueryFrame(camera) size = cv.GetSize(img) n_pixels = size[0] * size[1] grey = cv.CreateImage(size, 8, 1) recent_frames = [cv.CloneImage(grey)] base = cv.CloneImage(grey) cv.CvtColor(img, base, cv.CV_RGB2GRAY) #cv.ShowImage('card', base) tmp = cv.CloneImage(grey) while True: img = cv.QueryFrame(camera) cv.CvtColor(img, grey, cv.CV_RGB2GRAY) biggest_diff = max( sum_squared(grey, frame) / n_pixels for frame in recent_frames) #display the cam view cv.PutText(img, "%s" % biggest_diff, (1, 24), font, (255, 255, 255)) cv.ShowImage('win', img) recent_frames.append(cv.CloneImage(grey)) if len(recent_frames) > 3: del recent_frames[0] #check for keystroke c = cv.WaitKey(10) #if there was a keystroke, reset the last capture if c == 27: return captures elif c == 32: has_moved = True been_to_base = True elif c == 114: base = cv.CloneImage(grey) #if we're stable-ish if biggest_diff < 10: #if we're similar to base, update base #else, check for card #base_diff = max(sum_squared(base, frame) / n_pixels for frame in recent_frames) base_corr = min( ccoeff_normed(base, frame) for frame in recent_frames) #cv.ShowImage('debug', base) """for i, frame in enumerate(recent_frames): tmp = cv.CloneImage(base) cv.Sub(base, frame, tmp) cv.Pow(tmp, tmp, 2.0) cv.PutText(tmp, "%s" % (i+1), (1,24), font, (255, 255, 255)) #my_diff = sum_squared(base, frame) / n_pixels my_diff = ccoeff_normed(base, frame) #score(base, frame, cv.CV_TM_CCOEFF_NORMED) cv.PutText(tmp, "%s" % my_diff, (40, 24), font, (255, 255, 255)) cv.ShowImage('dbg%s' % (i+1), tmp)""" #print "stable. corr = %s. moved = %s. been_to_base = %s" % (base_corr, has_moved, been_to_base) if base_corr > 0.75 and not been_to_base: base = cv.CloneImage(grey) # cv.ShowImage('debug', base) has_moved = False been_to_base = True print "STATE: been to base. waiting for move" elif has_moved and been_to_base: corners = detect_card(grey, base) if corners is not None: card = get_card(grey, corners) cv.Flip(card, card, -1) captures.append(card) update_windows() #cv.ShowImage('card', card) has_moved = False been_to_base = False print "STATE: detected. waiting for go to base" else: if not has_moved: print "STATE: has moved. waiting for stable" has_moved = True
def calc_background_similarity(self): return min(ccoeff_normed(self.background_gray, frame) for frame in self.recent_frames_gray)
def match_card(card, known_set, cache): mag, grad = gradient(card) phash = dct_hash(card) #fetch the twenty candidates with the lowest hamming distance on the phash #there's a 99% chance that the matching card is one of the first 20 candidate_matches = sorted([ (name, set_name, hamming_dist(h, phash)) for name, set_name, h in known_set ], key = lambda (n,s,dist): dist) #we want the first 20 candidate_matches = candidate_matches[:20] #calculate the correlation score, #and also find the 'place' of each phash score #(multiple candidates can tie a phash score, so we rank by count of #distances < our distance) candidate_scores= [ ( name, set_name, dist, len([d for _,_,d in candidate_matches if d < dist]), ccoeff_normed(grad, cache.getCard(set_name, name)) ) for name,set_name,dist in candidate_matches ] #sort by score, and add a rank candidate_scores = sorted(candidate_scores, key = lambda (n,s,d,hr,ccoeff): ccoeff, reverse = True) norm_factor = 0 - candidate_scores[-1][4] total_score = sum([ccoeff + norm_factor for n,s,d,hr,ccoeff in candidate_scores]) #for each score, compute the normaized features (- mean, / std_median) #for correlation, we want the share of normalized score features = [ ( name, set_name, (corr_rank - 9.5) / 5.766, (h_rank - 6.759942) / 4.522550, (dist - 17.374153) / 3.014411, (((corr + norm_factor) / total_score)- 0.050000) / 0.040183, ) for corr_rank, (name, set_name, dist, h_rank, corr) in enumerate(candidate_scores) ] #compute the score (based on fancy machine learning.) #todo: make more automatic and configurable scores = [ ( name, set_name, 1.0 / (1 + math.e ** -(-6.48728 + 0.53659 * cr + -0.11304 * hr + -3.06121 * d + 2.94122 * corr)) ) for name, set_name, cr, hr, d, corr in features ] #consider the scores in order scores = sorted(scores, key=lambda (n,s,score): score, reverse=True) #each score is a probability 0.0-1.0 of how likely it is that #that name, set_name is the correct card. we'll consider <= 0.50 a no # >= 0.60 a yes, and 0.5..0.6 a maybe (todo: adjust?) yes_cards = [(n, s) for n, s, score in scores if score >= 0.6] maybe_cards = [(n, s) for n, s, score in scores if 0.6 > score > 0.5] #if we have one or more 'yes' cards if len(yes_cards) > 0: #if they're all the same card... if len(set([n for n,s in yes_cards])) == 1: #then we're sure it's that card (unsure on set, but it's the same art, so hard to tell return (yes_cards[0], True) elif len(maybe_cards) > 0: #we have no 'yes' cards at all. if we have any maybe cards... #if they're all the same card if len(set([n for n,s in maybe_cards])) == 1: #it *could* be this card, but we're not confidant return (maybe_cards[0], False) #we can't really say what it is with any sort of confidence return (('',''),False)
def match_card(card, known_set, cache): mag, grad = gradient(card) phash = dct_hash(card) #fetch the twenty candidates with the lowest hamming distance on the phash #there's a 99% chance that the matching card is one of the first 20 candidate_matches = sorted([ (name, set_name, hamming_dist(h, phash)) for name, set_name, h in known_set ], key = lambda (n,s,dist): dist) # Not even a chance, return if len(candidate_matches) is 0: return (('',''),False) #we want the first 20 candidate_matches = candidate_matches[:20] #calculate the correlation score, #and also find the 'place' of each phash score #(multiple candidates can tie a phash score, so we rank by count of #distances < our distance) candidate_scores= [ ( name, set_name, dist, len([d for _,_,d in candidate_matches if d < dist]), ccoeff_normed(grad, cache.getCard(set_name, name)) ) for name,set_name,dist in candidate_matches ] ''' print "candidate_scores" for name, set_name, dist, length, coef_norm in candidate_scores: print "\tname %s set_name %s dist %d length %d coef_nrom %d" % (name, set_name, dist, length, coef_norm) ''' #sort by score, and add a rank candidate_scores = sorted(candidate_scores, key = lambda (n,s,d,hr,ccoeff): ccoeff, reverse = True) norm_factor = 0 - candidate_scores[-1][4] total_score = sum([ccoeff + norm_factor for n,s,d,hr,ccoeff in candidate_scores]) #for each score, compute the normaized features (- mean, / std_median) #for correlation, we want the share of normalized score features = [ ( name, set_name, (corr_rank - 9.5) / 5.766, (h_rank - 6.759942) / 4.522550, (dist - 17.374153) / 3.014411, (((corr + norm_factor) / total_score)- 0.050000) / 0.040183, ) for corr_rank, (name, set_name, dist, h_rank, corr) in enumerate(candidate_scores) ] #compute the score (based on fancy machine learning.) #todo: make more automatic and configurable scores = [ ( name, set_name, 1.0 / (1 + math.e ** -(-6.48728 + 0.53659 * cr + -0.11304 * hr + -3.06121 * d + 2.94122 * corr)) ) for name, set_name, cr, hr, d, corr in features ] #consider the scores in order scores = sorted(scores, key=lambda (n,s,score): score, reverse=True) ''' print "score" for name, set_name, score in scores: print "\tname %s set_name %s score %d" % (name, set_name, score) ''' #each score is a probability 0.0-1.0 of how likely it is that #that name, set_name is the correct card. we'll consider <= 0.50 a no # >= 0.60 a yes, and 0.5..0.6 a maybe (todo: adjust?) yes_cards = [(n, s) for n, s, score in scores if score >= 0.6] maybe_cards = [(n, s) for n, s, score in scores if 0.6 > score > 0.5] ''' print "maybe cards" for name, set_name in maybe_cards: print "\tname %s set_name %s" % (name, set_name) print "Done maybe" print "yes cards" for name, set_name in yes_cards: print "\tname %s set_name %s" % (name, set_name) print "Done maybe" ''' #if we have one or more 'yes' cards if len(yes_cards) > 0: #if they're all the same card... if len(set([n for n,s in yes_cards])) == 1: #then we're sure it's that card (unsure on set, but it's the same art, so hard to tell return (yes_cards[0], True) elif len(maybe_cards) > 0: #we have no 'yes' cards at all. if we have any maybe cards... #if they're all the same card if len(set([n for n,s in maybe_cards])) == 1: #it *could* be this card, but we're not confidant return (maybe_cards[0], False) #we can't really say what it is with any sort of confidence return (('',''),False)