votchallenge / integration

Integration examples and utilities for VOT toolkit
10 stars 13 forks source link

vot test works but evaluate does not on VOTS23 #6

Closed imadtoubal closed 1 year ago

imadtoubal commented 1 year ago

Here is the error I get after running

$ vot evaluate NCCPython
A newer version of the VOT toolkit is available (0.6.3), please update.
 Loading dataset      |█████████████████████████████████████████████████████████████████| 100% [00:00<00:00]
 NCCPython/baseline   |▍                                                                |   1% [00:00<02:15]Tracker NCCPython encountered an error: Only supports single object tracking
Evaluation interrupted by tracker error: ('Experiment interrupted', TrackerException('Only supports single object tracking'))
 NCCPython/baseline   |▍                                                                |   1% [00:01<02:29]

I am using NCC tracker:

#!/usr/bin/python

import sys

import cv2
import numpy as np

import vot

class NCCTracker(object):

    def __init__(self, image, mask):
        region = self._rect_from_mask(mask)
        region = vot.Rectangle(region[0], region[1], region[2], region[3])
        self.window = max(region.width, region.height) * 2

        left = max(region.x, 0)
        top = max(region.y, 0)

        right = min(region.x + region.width, image.shape[1] - 1)
        bottom = min(region.y + region.height, image.shape[0] - 1)

        self.template = image[int(top):int(bottom), int(left):int(right)]
        self.position = (region.x + region.width / 2, region.y + region.height / 2)
        self.size = (region.width, region.height)

    def track(self, image):

        left = max(round(self.position[0] - float(self.window) / 2), 0)
        top = max(round(self.position[1] - float(self.window) / 2), 0)

        right = min(round(self.position[0] + float(self.window) / 2), image.shape[1] - 1)
        bottom = min(round(self.position[1] + float(self.window) / 2), image.shape[0] - 1)

        if right - left < self.template.shape[1] or bottom - top < self.template.shape[0]:
            return vot.Rectangle(self.position[0] + self.size[0] / 2, self.position[1] + self.size[1] / 2, self.size[0], self.size[1])

        cut = image[int(top):int(bottom), int(left):int(right)]

        matches = cv2.matchTemplate(cut, self.template, cv2.TM_CCOEFF_NORMED)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(matches)

        self.position = (left + max_loc[0] + float(self.size[0]) / 2, top + max_loc[1] + float(self.size[1]) / 2)

        return self._mask_from_rect([left + max_loc[0], top + max_loc[1], self.size[0], self.size[1]], (image.shape[1], image.shape[0])), max_val

    def _rect_from_mask(self, mask):
        '''
        create an axis-aligned rectangle from a given binary mask
        mask in created as a minimal rectangle containing all non-zero pixels
        '''
        x_ = np.sum(mask, axis=0)
        y_ = np.sum(mask, axis=1)
        x0 = np.min(np.nonzero(x_))
        x1 = np.max(np.nonzero(x_))
        y0 = np.min(np.nonzero(y_))
        y1 = np.max(np.nonzero(y_))
        return [x0, y0, x1 - x0 + 1, y1 - y0 + 1]

    def _mask_from_rect(self, rect, output_sz):
        '''
        create a binary mask from a given rectangle
        rect: axis-aligned rectangle [x0, y0, width, height]
        output_sz: size of the output [width, height]
        '''
        mask = np.zeros((output_sz[1], output_sz[0]), dtype=np.uint8)
        x0 = max(int(round(rect[0])), 0)
        y0 = max(int(round(rect[1])), 0)
        x1 = min(int(round(rect[0] + rect[2])), output_sz[0])
        y1 = min(int(round(rect[1] + rect[3])), output_sz[1])
        mask[y0:y1, x0:x1] = 1
        return mask

def make_full_size(x, output_sz):
    '''
    zero-pad input x (right and down) to match output_sz
    x: numpy array e.g., binary mask
    output_sz: size of the output [width, height]
    '''
    if x.shape[0] == output_sz[1] and x.shape[1] == output_sz[0]:
        return x
    pad_x = output_sz[0] - x.shape[1]
    if pad_x < 0:
        x = x[:, :x.shape[1] + pad_x]
        # padding has to be set to zero, otherwise pad function fails
        pad_x = 0
    pad_y = output_sz[1] - x.shape[0]
    if pad_y < 0:
        x = x[:x.shape[0] + pad_y, :]
        # padding has to be set to zero, otherwise pad function fails
        pad_y = 0
    return np.pad(x, ((0, pad_y), (0, pad_x)), 'constant', constant_values=0)

handle = vot.VOT("mask", multiobject=True)
objects = handle.objects()

imagefile = handle.frame()

image = cv2.imread(imagefile, cv2.IMREAD_GRAYSCALE)

trackers = [NCCTracker(image, object) for object in objects]

while True:
    imagefile = handle.frame()
    if not imagefile:
        break
    image = cv2.imread(imagefile, cv2.IMREAD_GRAYSCALE)
    handle.report([tracker.track(image) for tracker in trackers])

and the vot.py file recommended.

lukacu commented 1 year ago

Your case is very strange, can you run with debug enabled because it is not clear where is the problem, the tracker or the toolkit.

imadtoubal commented 1 year ago

@lukacu what do you mean by debug mode? There is no log file generated from the above and I do not see a debug mode in the CLI.

$ vot evaluate --help
usage: vot evaluate [-h] [--force] [--persist] [--workspace WORKSPACE] trackers [trackers ...]
lukacu commented 1 year ago

Argparse produces strange help, It is a global flag that is described if you run "vot -h"

lukacu commented 1 year ago

I assume this issue is now solved, closing.