def evaluateFrame(self, frame):
        """Update statistics by evaluating a new frame."""

        timestamp = frame["timestamp"]
        groundtruths = frame["annotations"]
        hypotheses = self.get_hypotheses_frame(timestamp)["hypotheses"]

        visualDebugAnnotations = []

        # Save occuring ground truth ids
        for g in groundtruths:
            self.groundtruth_ids_.add(g["id"])
            # Added for Mostly Tracked calculation
            temp_id = g["id"]
            # If gt already seen increment counter for gt_id
            if temp_id in self.mostly_tracked_list.keys():            
                if not g.get("dco",False):
                    self.mostly_tracked_list[temp_id]["gt_count"] += 1
            # For new gt track initialize a new dict
            else :
                self.mostly_tracked_list[temp_id] = {'gt_count': 1, 'hyp_count': 0}
                
                 
            

        # Save occuring hypothesis ids
        for h in hypotheses:
            self.hypothesis_ids_.add(h["id"])
        
        rospy.logdebug("")
        rospy.logdebug("Timestamp: %s" % timestamp)
        
        rospy.logdebug("DIFF")
        rospy.logdebug("DIFF Time %.2f" % timestamp)
        
        logstr = ["DIFF Mappings:"]
        for gt_id in sorted(self.mappings_.keys()):
            logstr.append("%s-%s" % (gt_id, self.mappings_[gt_id]))
        rospy.logdebug(" ".join(logstr))

        # No need to evaluate this frame.
        if len(groundtruths) == 0 and len(hypotheses) == 0:
            rospy.logdebug("No gt and hypos for this frame.")
            return

        rospy.logdebug("GTs:")
        for groundtruth in groundtruths:
            rospy.logdebug(Rect(groundtruth))

        rospy.logdebug("Hypos:")
        for hypothesis in hypotheses:
            rospy.logdebug(Rect(hypothesis))
            

        # PAPER STEP 1
        # Valid mappings skip Munkres algorithm, if both ground truth and hypo are found in this frame
        # We call these pairs correspondences and fill the list each frame.
        correspondences = {} # truth id -> hypothesis id
        
        listofprints = []
        rospy.logdebug("")
        rospy.logdebug("STEP 1: KEEP CORRESPONDENCE")
#            print "DIFF Keep correspondence"
            
        for gt_id in self.mappings_.keys():
            groundtruth = filter(lambda g: g["id"] == gt_id, groundtruths) # Get ground truths with given ground truth id in current frame
            if len(groundtruth) > 1:
                rospy.logwarn("found %d > 1 ground truth tracks for id %s", len(groundtruth), gt_id)
            elif len(groundtruth) < 1:
                continue
            
            hypothesis = filter(lambda h: h["id"] == self.mappings_[gt_id], hypotheses) # Get hypothesis with hypothesis id according to mapping
            assert len(hypothesis) <= 1, "Multiple track hypotheses found with the same ID (#%s) at cycle no. %d! Make sure the tracker is outputting unique track IDs!" % (hypothesis[0]["id"] , int(timestamp))
            if len(hypothesis) != 1:
                continue
            
            # Hypothesis found for known mapping
            # Check hypothesis for overlap
            distance = numpy.linalg.norm(Rect(groundtruth[0]).asNumpyArray() - Rect(hypothesis[0]).asNumpyArray() )
            if distance <= self.matching_threshold_ and not groundtruth[0].get("dco",False):
                rospy.logdebug("Keeping correspondence between %s and %s" % (groundtruth[0]["id"], hypothesis[0]["id"]))
#                    print "DIFF Keep corr %s %s %.2f" % (groundtruth[0]["id"], hypothesis[0]["id"], Rect(groundtruth[0]).overlap(Rect(hypothesis[0])))
                #listofprints.append("DIFF Keep corr %s %s %.2f" % (groundtruth[0]["id"], hypothesis[0]["id"], Rect(groundtruth[0]).overlap(Rect(hypothesis[0]))))
                correspondences[gt_id] = hypothesis[0]["id"]
                self.total_distance_ += distance
            elif groundtruth[0].get("dco",False):
                correspondences[gt_id] = hypothesis[0]["id"]
            elif hypothesis[0].get("dco",False) and not groundtruth[0].get("dco",False) and distance <= 2*self.matching_threshold_:
                self.misses_ += 1 
                correspondences[gt_id] = hypothesis[0]["id"]
                self.total_distance_ += distance
                self.evalMisses.append([frame["num"], correspondences[gt_id]])

        munk_hypotheses = filter(lambda h: h['id'] not in correspondences.values(), hypotheses)         
        munk_gts = filter(lambda g: g['id'] not in correspondences.keys(), groundtruths) 
        for p in sorted(listofprints):
            rospy.logdebug(p)

        # PAPER STEP 2
        rospy.logdebug("")
        rospy.logdebug("STEP 2: FIND CORRESPONDENCE")
        
        # Fill hungarian matrix with +inf
        munkres_matrix = [ [ self.munkres_inf_ for i in range(max(len(munk_hypotheses), len(munk_gts))) ] for j in range(max(len(munk_hypotheses), len(munk_gts))) ] # TODO make square matrix
        valid_counter = 0
        

        # Find correspondences
        for i in range(len(munk_gts)):
            groundtruth = munk_gts[i]
            
            # Skip groundtruth with correspondence from mapping
            if groundtruth["id"] in correspondences.keys():
                rospy.logdebug("Groundtruth %s already in correspondence" % groundtruth["id"])
                continue
            
            # Fill hungarian matrix with distance between gts and hypos
            for j in range(len(munk_hypotheses)):
                hypothesis = munk_hypotheses[j]
                
                # Skip hypotheses with correspondence from mapping
                if hypothesis["id"] in correspondences.values():
                    rospy.logdebug("Hypothesis %s already in correspondence" % hypothesis["id"])
                    continue
                
                rect_groundtruth = Rect(groundtruth)
                rect_hypothesis = Rect(hypothesis)
                distance = numpy.linalg.norm(rect_groundtruth.asNumpyArray() - rect_hypothesis.asNumpyArray())
                
                if distance <= self.matching_threshold_:
#                        print "Fill Hungarian", rect_groundtruth, rect_hypothesis, overlap
                    munkres_matrix[i][j] = distance
                    valid_counter += 1
                    rospy.logdebug("DIFF candidate %s %s %.2f" % (groundtruth["id"], hypothesis["id"], distance))
        
        # Do the Munkres / LAPJV        
        # Only run munkres on non-empty matrix
        if valid_counter > 1:
            # t = time.time()   
            if self.use_lapjv:
                np_array = numpy.array(munkres_matrix, dtype=numpy.float32 )
                lap_result = self.lapjv.lap(np_array)
                indices = zip(range(max(len(munk_hypotheses),len(munk_gts))), lap_result[1])
#               elapsed = time.time() - t
#               rospy.loginfo("LAPJV needed {}s".format(elapsed))
            else:
                m = Munkres()
                indices = m.compute(munkres_matrix)
#               elapsed = time.time() - t
#               rospy.loginfo("Munkres needed {}s".format(elapsed))                       
        elif valid_counter == 1:
            np_array = numpy.array(munkres_matrix, dtype=numpy.float32  )
            idx = numpy.unravel_index(np_array.argmin(), np_array.shape)
            indices = [idx]            
        else:
            rospy.logdebug("No need to run Hungarian with %d ground truths and %d hypothesis." % (len(groundtruths), len(hypotheses)))
            indices = []
        rospy.logdebug(indices)
        
        correspondencelist = []
        mismatcheslist = []
        
        for gt_index, hypo_index in indices:
            
            # Skip invalid self.mappings_
            # Check for max float distance matches (since Hungarian returns complete mapping)
            if (munkres_matrix[gt_index][hypo_index] >= self.munkres_inf_): # NO correspondence <=> overlap >= thresh
                continue
            
            gt_id   = munk_gts[gt_index]["id"]
            hypo_id = munk_hypotheses[hypo_index]["id"]
            
            # Assert no known mappings have been added to hungarian, since keep correspondence should have considered this case.
            if gt_id in self.mappings_:
                assert self.mappings_[gt_id] != hypo_id 
            
            
            # Add to correspondences
            rospy.logdebug("Correspondence found: %s and %s (distance: %f)" % (gt_id, hypo_id, munkres_matrix[gt_index][hypo_index]))
#                correspondencelist.append("DIFF correspondence %s %s %.2f" % (gt_id, hypo_id, 1.0 / munkres_matrix[gt_index][hypo_index]))
            correspondencelist.append("DIFF correspondence %s %s" % (gt_id, hypo_id))
            correspondences[gt_id] = hypo_id
            self.total_distance_ += munkres_matrix[gt_index][hypo_index]
            

            # Count "recoverable" and "non-recoverable" mismatches
            # "recoverable" mismatches
            if gt_id in self.gt_map_ and self.gt_map_[gt_id] != hypo_id and not munk_gts[gt_index].get("dco",False):
                rospy.logdebug("Look ma! We got a recoverable mismatch over here! (%s-%s) -> (%s-%s)" % (gt_id, self.gt_map_[gt_id], gt_id, hypo_id))
                self.recoverable_mismatches_ += 1

            # "non-recoverable" mismatches
            if hypo_id in self.hypo_map_ and self.hypo_map_[hypo_id] != gt_id:
                # Do not count non-recoverable mismatch, if both old ground truth and current ground truth are DCO.
                old_gt_id = self.hypo_map_[hypo_id]
                old_gt_dco = filter(lambda g: g["id"] == old_gt_id and g.get("dco",False), groundtruths)

                assert len(old_gt_dco) <= 1;
                if not (munk_gts[gt_index].get("dco",False) and len(old_gt_dco) == 1):
                    rospy.logdebug("Look ma! We got a non-recoverable mismatch over here! (%s-%s) -> (%s-%s)" % (self.hypo_map_[hypo_id], hypo_id, gt_id, hypo_id))
                    self.non_recoverable_mismatches_ += 1

            # Update yin-yang maps                    
            self.gt_map_[gt_id] = hypo_id
            self.hypo_map_[hypo_id] = gt_id

            # Correspondence contradicts previous mapping. Mark and count as mismatch, if ground truth is not a DCO
            # Iterate over all gt-hypo pairs of mapping, since we have to perform a two way check:
            # Correspondence: A-1
            # Mapping: A-2, B-1
            # We have to detect both forms of conflicts
            for mapping_gt_id, mapping_hypo_id in self.mappings_.items():
                
                # CAVE: Other than in perl script:
                # Do not consider for mismatch, if both old gt and new gt are DCO
                gt_with_mapping_gt_id_dco = filter(lambda g: g["id"] == mapping_gt_id and g.get("dco",False), groundtruths)
                if len (gt_with_mapping_gt_id_dco) == 1 and munk_gts[gt_index].get("dco",False):
                    rospy.logdebug("Ground truths %s and %s are DCO. Not considering for mismatch." % (mapping_gt_id, gt_id))
#                    print "DIFF DCO %s" % (gt_id), groundtruths[gt_index]
                    
                else:
                # Look ma, we got a conflict over here!
                # New hypothesis for mapped ground truth found
                    if (mapping_gt_id == gt_id and mapping_hypo_id != hypo_id)\
                    or (mapping_gt_id != gt_id and mapping_hypo_id == hypo_id):
                        rospy.logdebug("Correspondence %s-%s contradicts mapping %s-%s. Counting as mismatch and updating mapping." % (gt_id, hypo_id, mapping_gt_id, mapping_hypo_id))
                        mismatcheslist.append("DIFF Mismatch %s-%s -> %s-%s" % (mapping_gt_id, mapping_hypo_id, gt_id, hypo_id))
                        self.mismatches_ = self.mismatches_ + 1

                        # find groundtruth and hypothesis with given ids
                        g = filter(lambda g: g["id"] == gt_id, groundtruths)
                        h = filter(lambda h: h["id"] == hypo_id, hypotheses)

                        #assert(len(g) == 1)
                        if len(g) != 1:
                            rospy.logwarn('more than one gt: %s', str(g))
                        assert(len(h) == 1)

                        g = g[0]
                        h = h[0]

                        self.evalMismatches.append([frame["num"], h["id"], h["x"], h["y"], h["w"], h["h"]])

                        g["class"] = "mismatch"
                        h["class"] = "mismatch"

                        visualDebugAnnotations.append(g)
                        visualDebugAnnotations.append(h)

                        # mapping will be updated after loop
                        del self.mappings_[mapping_gt_id]
            
#                print "YIN: %d %d" % (self.recoverable_mismatches_, self.non_recoverable_mismatches_)
#                assert(self.recoverable_mismatches_ + self.non_recoverable_mismatches_ == self.mismatches_)
            if(self.recoverable_mismatches_ + self.non_recoverable_mismatches_ != self.mismatches_):
                rospy.logdebug("Look, mismatches differ: g %d b %d  other %d" % (self.recoverable_mismatches_, self.non_recoverable_mismatches_, self.mismatches_))
                rospy.logdebug(self.gt_map_)
                rospy.logdebug(self.hypo_map_)
        
            # Save (overwrite) mapping even if ground truth is dco
            self.mappings_[gt_id] = hypo_id # Update mapping
        
        # Sorted DIFF output
        for c in sorted(correspondencelist):
            rospy.logdebug(c)
            
        for m in sorted(mismatcheslist):
            rospy.logdebug(m)

        # Visual debug
        for g in groundtruths:
            if g["class"] != "mismatch" and g["id"] in correspondences.keys():
                g["class"] = "correspondence"
                visualDebugAnnotations.append(g)
            
        for h in hypotheses:
            if h["class"] != "mismatch" and h["id"] in correspondences.values():
                h["class"] = "correspondence"
                visualDebugAnnotations.append(h)

        
        # TODO get overlap ratio
        # Print out correspondences
#            for gt_id, hypo_id in correspondences.items():
#                print "Correspondence: %s-%s" % (gt_id, hypo_id)
        
        # PAPER STEP 4
        # Count miss, when groundtruth has no correspondence and is not dco
        for groundtruth in groundtruths:
            rospy.logdebug("DCO:", groundtruth)
            if groundtruth["id"] not in correspondences.keys() and groundtruth.get("dco", False) != True:
                rospy.logdebug("Miss: %s" % groundtruth["id"])
                rospy.logdebug("DEBUGMISS: %.2f" % timestamp)
                rospy.logdebug("DIFF Miss %s" % groundtruth["id"])
                groundtruth["class"] = "miss"
                visualDebugAnnotations.append(groundtruth)
                self.misses_ += 1
                self.evalMisses.append([frame["num"], groundtruth["id"]])

        # Count false positives
        for hypothesis in hypotheses:
            if hypothesis["id"] not in correspondences.values():
                rospy.logdebug("False positive: %s" % hypothesis["id"])
                rospy.logdebug("DIFF False positive %s" % hypothesis["id"])
                self.false_positives_ += 1
                visualDebugAnnotations.append(hypothesis)
                hypothesis["class"] = "false positive"
                self.evalFalsePositives.append([frame["num"], hypothesis["id"], hypothesis["x"], hypothesis["y"], hypothesis["w"], hypothesis["h"]])
        
        self.total_correspondences_ += len(correspondences)

        # For counting matches, do not count groundtruths with "don't care"-flag
        self.total_matches_ += len(correspondences)
        for groundtruth in groundtruths:
            if groundtruth.get("dco", False) and groundtruth["id"] in correspondences.keys():
                self.total_matches_ -= 1

        
        # FIXED: Count only groundtruth objects that don't carry a 'don't care' flag. Otherwise we can get high MOTA scores even if the track recall is 0.0!
        self.total_groundtruths_ += len( filter(lambda groundtruth: not groundtruth.get("dco", False), groundtruths) )
        #self.total_groundtruths_ += len(groundtruths) # Number of objects (ground truths) in current frame

        visualDebugFrame = {
            "timestamp": timestamp,
 #           "class": frame["class"],
            "annotations": visualDebugAnnotations
        }
        if "num" in frame:
            visualDebugFrame["num"] = frame["num"]

        self.visualDebugFrames_.append(visualDebugFrame)
        
        # Added for Mostly tracked support
        # Increment hyp count for each found correspondence
        for gt_id, hyp_id in correspondences.iteritems():
            self.mostly_tracked_list[gt_id]['hyp_count'] += 1
    def evaluateFrame(self, frame):
        """Update statistics by evaluating a new frame."""

        timestamp = frame["timestamp"]
        groundtruths = frame["annotations"]
        hypotheses = self.get_hypotheses_frame(timestamp)["hypotheses"]

        visualDebugAnnotations = []

        # Save occuring ground truth ids
        for g in groundtruths:
            self.groundtruth_ids_.add(g["id"])

        # Save occuring hypothesis ids
        for h in hypotheses:
            self.hypothesis_ids_.add(h["id"])
        
        rospy.logdebug("")
        rospy.logdebug("Timestamp: %s" % timestamp)
        
        rospy.logdebug("DIFF")
        rospy.logdebug("DIFF Time %.2f" % timestamp)
        
        logstr = ["DIFF Mappings:"]
        for gt_id in sorted(self.mappings_.keys()):
            logstr.append("%s-%s" % (gt_id, self.mappings_[gt_id]))
        rospy.logdebug(" ".join(logstr))

        # No need to evaluate this frame.
        if len(groundtruths) == 0 and len(hypotheses) == 0:
            rospy.logdebug("No gt and hypos for this frame.")
            return

        rospy.logdebug("GTs:")
        for groundtruth in groundtruths:
            rospy.logdebug(Rect(groundtruth))

        rospy.logdebug("Hypos:")
        for hypothesis in hypotheses:
            rospy.logdebug(Rect(hypothesis))
            

        # PAPER STEP 1
        # Valid mappings skip Munkres algorithm, if both ground truth and hypo are found in this frame
        # We call these pairs correspondences and fill the list each frame.
        correspondences = {} # truth id -> hypothesis id
        
        listofprints = []
        rospy.logdebug("")
        rospy.logdebug("STEP 1: KEEP CORRESPONDENCE")
#            print "DIFF Keep correspondence"
            
        for gt_id in self.mappings_.keys():
            groundtruth = filter(lambda g: g["id"] == gt_id, groundtruths) # Get ground truths with given ground truth id in current frame
            if len(groundtruth) > 1:
                rospy.logwarn("found %d > 1 ground truth tracks for id %s", len(groundtruth), gt_id)
            elif len(groundtruth) < 1:
                continue
            
            hypothesis = filter(lambda h: h["id"] == self.mappings_[gt_id], hypotheses) # Get hypothesis with hypothesis id according to mapping
            assert len(hypothesis) <= 1
            if len(hypothesis) != 1:
                continue
            
            # Hypothesis found for known mapping
            # Check hypothesis for overlap
            distance = numpy.linalg.norm(Rect(groundtruth[0]).asNumpyArray() - Rect(hypothesis[0]).asNumpyArray() )
            if distance <= self.matching_threshold_:
                rospy.logdebug("Keeping correspondence between %s and %s" % (groundtruth[0]["id"], hypothesis[0]["id"]))
#                    print "DIFF Keep corr %s %s %.2f" % (groundtruth[0]["id"], hypothesis[0]["id"], Rect(groundtruth[0]).overlap(Rect(hypothesis[0])))
                #listofprints.append("DIFF Keep corr %s %s %.2f" % (groundtruth[0]["id"], hypothesis[0]["id"], Rect(groundtruth[0]).overlap(Rect(hypothesis[0]))))
                correspondences[gt_id] = hypothesis[0]["id"]
                self.total_distance_ += distance

        
        for p in sorted(listofprints):
            rospy.logdebug(p)

        # PAPER STEP 2
        rospy.logdebug("")
        rospy.logdebug("STEP 2: FIND CORRESPONDENCE")
        
        # Fill hungarian matrix with +inf
        munkres_matrix = [ [ self.munkres_inf_ for i in range(len(hypotheses)) ] for j in range(len(groundtruths)) ] # TODO make square matrix

        # Find correspondences
        for i in range(len(groundtruths)):
            groundtruth = groundtruths[i]
            
            # Skip groundtruth with correspondence from mapping
            if groundtruth["id"] in correspondences.keys():
                rospy.logdebug("Groundtruth %s already in correspondence" % groundtruth["id"])
                continue
            
            # Fill hungarian matrix with distance between gts and hypos
            for j in range(len(hypotheses)):
                hypothesis = hypotheses[j]
                
                # Skip hypotheses with correspondence from mapping
                if hypothesis["id"] in correspondences.values():
                    rospy.logdebug("Hypothesis %s already in correspondence" % hypothesis["id"])
                    continue
                
                rect_groundtruth = Rect(groundtruth)
                rect_hypothesis = Rect(hypothesis)
                distance = numpy.linalg.norm(rect_groundtruth.asNumpyArray() - rect_hypothesis.asNumpyArray())
                
                if distance <= self.matching_threshold_:
#                        print "Fill Hungarian", rect_groundtruth, rect_hypothesis, overlap
                    munkres_matrix[i][j] = distance
                    rospy.logdebug("DIFF candidate %s %s %.2f" % (groundtruth["id"], hypothesis["id"], distance))
        
        # Do the Munkres
        #rospy.logdebug(munkres_matrix)
        
        # Only run munkres on non-empty matrix
        if len(munkres_matrix) > 0:
            m = Munkres()
            indices = m.compute(munkres_matrix)
        else:
            rospy.logdebug("No need to run Hungarian with %d ground truths and %d hypothesis." % (len(groundtruths), len(hypotheses)))
            indices = []
        rospy.logdebug(indices)
        
        correspondencelist = []
        mismatcheslist = []
        
        for gt_index, hypo_index in indices:
            
            # Skip invalid self.mappings_
            # Check for max float distance matches (since Hungarian returns complete mapping)
            if (munkres_matrix[gt_index][hypo_index] == self.munkres_inf_): # NO correspondence <=> overlap >= thresh
                continue
            
            gt_id   = groundtruths[gt_index]["id"]
            hypo_id = hypotheses[hypo_index]["id"]
            
            # Assert no known mappings have been added to hungarian, since keep correspondence should have considered this case.
            if gt_id in self.mappings_:
                assert self.mappings_[gt_id] != hypo_id 
            
            
            # Add to correspondences
            rospy.logdebug("Correspondence found: %s and %s (distance: %f)" % (gt_id, hypo_id, munkres_matrix[gt_index][hypo_index]))
#                correspondencelist.append("DIFF correspondence %s %s %.2f" % (gt_id, hypo_id, 1.0 / munkres_matrix[gt_index][hypo_index]))
            correspondencelist.append("DIFF correspondence %s %s" % (gt_id, hypo_id))
            correspondences[gt_id] = hypo_id
            self.total_distance_ += munkres_matrix[gt_index][hypo_index]
            

            # Count "recoverable" and "non-recoverable" mismatches
            # "recoverable" mismatches
            if gt_id in self.gt_map_ and self.gt_map_[gt_id] != hypo_id and not groundtruths[gt_index].get("dco",False):
                rospy.logdebug("Look ma! We got a recoverable mismatch over here! (%s-%s) -> (%s-%s)" % (gt_id, self.gt_map_[gt_id], gt_id, hypo_id))
                self.recoverable_mismatches_ += 1

            # "non-recoverable" mismatches
            if hypo_id in self.hypo_map_ and self.hypo_map_[hypo_id] != gt_id:
                # Do not count non-recoverable mismatch, if both old ground truth and current ground truth are DCO.
                old_gt_id = self.hypo_map_[hypo_id]
                old_gt_dco = filter(lambda g: g["id"] == old_gt_id and g.get("dco",False), groundtruths)

                assert len(old_gt_dco) <= 1;
                if not (groundtruths[gt_index].get("dco",False) and len(old_gt_dco) == 1):
                    rospy.logdebug("Look ma! We got a non-recoverable mismatch over here! (%s-%s) -> (%s-%s)" % (self.hypo_map_[hypo_id], hypo_id, gt_id, hypo_id))
                    self.non_recoverable_mismatches_ += 1

            # Update yin-yang maps                    
            self.gt_map_[gt_id] = hypo_id
            self.hypo_map_[hypo_id] = gt_id

            # Correspondence contradicts previous mapping. Mark and count as mismatch, if ground truth is not a DCO
            # Iterate over all gt-hypo pairs of mapping, since we have to perform a two way check:
            # Correspondence: A-1
            # Mapping: A-2, B-1
            # We have to detect both forms of conflicts
            for mapping_gt_id, mapping_hypo_id in self.mappings_.items():
                
                # CAVE: Other than in perl script:
                # Do not consider for mismatch, if both old gt and new gt are DCO
                gt_with_mapping_gt_id_dco = filter(lambda g: g["id"] == mapping_gt_id and g.get("dco",False), groundtruths)
                if len (gt_with_mapping_gt_id_dco) == 1 and groundtruths[gt_index].get("dco",False):
                    rospy.logdebug("Ground truths %s and %s are DCO. Not considering for mismatch." % (mapping_gt_id, gt_id))
#                    print "DIFF DCO %s" % (gt_id), groundtruths[gt_index]
                    
                else:
                # Look ma, we got a conflict over here!
                # New hypothesis for mapped ground truth found
                    if (mapping_gt_id == gt_id and mapping_hypo_id != hypo_id)\
                    or (mapping_gt_id != gt_id and mapping_hypo_id == hypo_id):
                        rospy.logdebug("Correspondence %s-%s contradicts mapping %s-%s. Counting as mismatch and updating mapping." % (gt_id, hypo_id, mapping_gt_id, mapping_hypo_id))
                        mismatcheslist.append("DIFF Mismatch %s-%s -> %s-%s" % (mapping_gt_id, mapping_hypo_id, gt_id, hypo_id))
                        self.mismatches_ = self.mismatches_ + 1

                        # find groundtruth and hypothesis with given ids
                        g = filter(lambda g: g["id"] == gt_id, groundtruths)
                        h = filter(lambda h: h["id"] == hypo_id, hypotheses)

                        #assert(len(g) == 1)
                        if len(g) != 1:
                            rospy.logwarn('more than one gt: %s', str(g))
                        assert(len(h) == 1)

                        g = g[0]
                        h = h[0]

                        g["class"] = "mismatch"
                        h["class"] = "mismatch"

                        visualDebugAnnotations.append(g)
                        visualDebugAnnotations.append(h)

                        # mapping will be updated after loop
                        del self.mappings_[mapping_gt_id]
            
#                print "YIN: %d %d" % (self.recoverable_mismatches_, self.non_recoverable_mismatches_)
#                assert(self.recoverable_mismatches_ + self.non_recoverable_mismatches_ == self.mismatches_)
            if(self.recoverable_mismatches_ + self.non_recoverable_mismatches_ != self.mismatches_):
                rospy.logdebug("Look, mismatches differ: g %d b %d  other %d" % (self.recoverable_mismatches_, self.non_recoverable_mismatches_, self.mismatches_))
                rospy.logdebug(self.gt_map_)
                rospy.logdebug(self.hypo_map_)
        
            # Save (overwrite) mapping even if ground truth is dco
            self.mappings_[gt_id] = hypo_id # Update mapping
        
        # Sorted DIFF output
        for c in sorted(correspondencelist):
            rospy.logdebug(c)
            
        for m in sorted(mismatcheslist):
            rospy.logdebug(m)

        # Visual debug
        for g in groundtruths:
            if g["class"] != "mismatch" and g["id"] in correspondences.keys():
                g["class"] = "correspondence"
                visualDebugAnnotations.append(g)
            
        for h in hypotheses:
            if h["class"] != "mismatch" and h["id"] in correspondences.values():
                h["class"] = "correspondence"
                visualDebugAnnotations.append(h)

        
        # TODO get overlap ratio
        # Print out correspondences
#            for gt_id, hypo_id in correspondences.items():
#                print "Correspondence: %s-%s" % (gt_id, hypo_id)
        
        # PAPER STEP 4
        # Count miss, when groundtruth has no correspondence and is not dco
        for groundtruth in groundtruths:
            rospy.logdebug("DCO:", groundtruth)
            if groundtruth["id"] not in correspondences.keys() and groundtruth.get("dco", False) != True:
                rospy.logdebug("Miss: %s" % groundtruth["id"])
                rospy.logdebug("DEBUGMISS: %.2f" % timestamp)
                rospy.logdebug("DIFF Miss %s" % groundtruth["id"])
                groundtruth["class"] = "miss"
                visualDebugAnnotations.append(groundtruth)
                self.misses_ += 1

        # Count false positives
        for hypothesis in hypotheses:
            if hypothesis["id"] not in correspondences.values():
                rospy.logdebug("False positive: %s" % hypothesis["id"])
                rospy.logdebug("DIFF False positive %s" % hypothesis["id"])
                self.false_positives_ += 1
                visualDebugAnnotations.append(hypothesis)
                hypothesis["class"] = "false positive"
        
        self.total_correspondences_ += len(correspondences)
        
        self.total_groundtruths_ += len(groundtruths) # Number of objects (ground truths) in current frame

        visualDebugFrame = {
            "timestamp": timestamp,
 #           "class": frame["class"],
            "annotations": visualDebugAnnotations
        }
        if "num" in frame:
            visualDebugFrame["num"] = frame["num"]

        self.visualDebugFrames_.append(visualDebugFrame)