├── .idea
├── Visual_Tracking_api.iml
├── misc.xml
├── modules.xml
└── vcs.xml
├── DSSTtracker.py
├── HCFtracker.py
├── KCFtracker.py
├── README.md
├── Sequence.py
├── example.jpg
├── examples.py
├── image
└── files.png
├── pyhog
├── COPYING
├── Makefile
├── README.rst
├── __init__.py
├── features_pedro_py.cc
├── features_pedro_py.o
├── features_pedro_py.so
├── numpymacros.h
├── pyhog.py
└── pyhog_example.ipynb
├── tools.py
├── tutorials
├── DeepDCF.ipynb
├── Discriminative Scale Space Tracker.ipynb
├── Kernelized Correlation Filters.ipynb
├── Visualize_deep_features.ipynb
├── img_ScaleChange
│ ├── 0001.jpg
│ ├── 0002.jpg
│ ├── 0003.jpg
│ ├── 0004.jpg
│ └── groundtruth.txt
└── img_common
│ ├── 0001.jpg
│ ├── 0002.jpg
│ └── groundtruth.txt
├── utils.py
├── vgg.py
├── vot.py
└── vot_demo_tracker.py
/.idea/Visual_Tracking_api.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/DSSTtracker.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import cv2
3 | import numpy as np
4 | import utils
5 | import vot
6 | from pyhog import pyhog
7 |
8 | class padding:
9 | def __init__(self):
10 | self.generic = 1.8
11 | self.large = 1
12 | self.height = 0.4
13 |
14 |
15 | class DSSTtracker:
16 | def __init__(self, image, region):
17 | output_sigma_factor = 1 / float(16)
18 | scale_sigma_factor = 1 / float(4)
19 | self.lamda = 1e-2
20 | self.lamda_scale = 1e-2
21 | self.interp_factor = 0.025
22 | nScales = 33 # number of scale levels
23 | scale_model_factor = 1.0
24 | scale_step = 1.02 # step of one scale level
25 | scale_model_max_area = 32 * 16
26 | self.currentScaleFactor = 1.0
27 |
28 | self.target_size = np.array([region.height, region.width])
29 | self.pos = [region.y + region.height / 2, region.x + region.width / 2]
30 | init_target_size = self.target_size
31 | self.base_target_size = self.target_size / self.currentScaleFactor
32 | self.sz = utils.get_window_size(self.target_size, image.shape[:2],padding())
33 |
34 | output_sigma = np.sqrt(np.prod(self.target_size)) * output_sigma_factor
35 | scale_sigma = np.sqrt(nScales) * scale_sigma_factor
36 | grid_y = np.arange(np.floor(self.sz[0])) - np.floor(self.sz[0] / 2)
37 | grid_x = np.arange(np.floor(self.sz[1])) - np.floor(self.sz[1] / 2)
38 | rs, cs = np.meshgrid(grid_x, grid_y)
39 | y = np.exp(-0.5 / output_sigma ** 2 * (rs ** 2 + cs ** 2))
40 |
41 | # Gaussian shaped label for scale estimation
42 | ss = np.arange(nScales) - np.ceil(nScales / 2)
43 | ys = np.exp(-0.5 * (ss ** 2) / scale_sigma ** 2)
44 | self.scaleFactors = np.power(scale_step, -ss)
45 | self.yf = np.fft.fft2(y, axes=(0, 1))
46 | self.ysf = np.fft.fft(ys)
47 |
48 | feature_map = utils.get_subwindow(image, self.pos, self.sz, feature='hog')
49 |
50 | self.cos_window = np.outer(np.hanning(y.shape[0]), np.hanning(y.shape[1]))
51 | x_hog = np.multiply(feature_map, self.cos_window[:, :, None])
52 | xf = np.fft.fft2(x_hog, axes=(0, 1))
53 |
54 | # scale search preprocess
55 | if nScales % 2 == 0:
56 | self.scale_window = np.hanning(nScales + 1)
57 | self.scale_window = self.scale_window[1:]
58 | else:
59 | self.scale_window = np.hanning(nScales)
60 |
61 | self.scaleSizeFactors = self.scaleFactors
62 | self.min_scale_factor = np.power(scale_step,
63 | np.ceil(np.log(5. / np.min(self.sz)) / np.log(scale_step)))
64 |
65 | self.max_scale_factor = np.power(scale_step,
66 | np.floor(np.log(np.min(np.divide(image.shape[:2],
67 | self.base_target_size)))
68 | / np.log(scale_step)))
69 |
70 | if scale_model_factor * scale_model_factor * np.prod(init_target_size) > scale_model_max_area:
71 | scale_model_factor = np.sqrt(scale_model_max_area / np.prod(init_target_size))
72 |
73 | self.scale_model_sz = np.floor(init_target_size * scale_model_factor)
74 |
75 | s = utils.get_scale_subwindow(image, self.pos, self.base_target_size,
76 | self.currentScaleFactor * self.scaleSizeFactors, self.scale_window,
77 | self.scale_model_sz)
78 |
79 | sf = np.fft.fftn(s, axes=[0])
80 |
81 | self.x_num = np.multiply(self.yf[:, :, None], np.conj(xf))
82 | self.x_den = np.real(np.sum(np.multiply(xf, np.conj(xf)), axis=2))
83 |
84 | self.s_num = np.multiply(self.ysf[:, None], np.conj(sf))
85 | self.s_den = np.real(np.sum(np.multiply(sf, np.conj(sf)), axis=1))
86 |
87 | def track(self, image):
88 | test_patch = utils.get_subwindow(image, self.pos, self.sz, scale_factor=self.currentScaleFactor)
89 | hog_feature_t = pyhog.features_pedro(test_patch / 255., 1)
90 | hog_feature_t = np.lib.pad(hog_feature_t, ((1, 1), (1, 1), (0, 0)), 'edge')
91 | xt = np.multiply(hog_feature_t, self.cos_window[:, :, None])
92 | xtf = np.fft.fft2(xt, axes=(0, 1))
93 | response = np.real(np.fft.ifft2(np.divide(np.sum(np.multiply(self.x_num, xtf),
94 | axis=2), (self.x_den + self.lamda))))
95 |
96 | v_centre, h_centre = np.unravel_index(response.argmax(), response.shape)
97 | vert_delta, horiz_delta = \
98 | [(v_centre - response.shape[0] / 2) * self.currentScaleFactor,
99 | (h_centre - response.shape[1] / 2) * self.currentScaleFactor]
100 |
101 | self.pos = [self.pos[0] + vert_delta, self.pos[1] + horiz_delta]
102 |
103 | st = utils.get_scale_subwindow(image, self.pos, self.base_target_size,
104 | self.currentScaleFactor * self.scaleSizeFactors, self.scale_window,
105 | self.scale_model_sz)
106 | stf = np.fft.fftn(st, axes=[0])
107 |
108 | scale_reponse = np.real(np.fft.ifftn(np.sum(np.divide(np.multiply(self.s_num, stf),
109 | (self.s_den[:, None] + self.lamda_scale)), axis=1)))
110 | recovered_scale = np.argmax(scale_reponse)
111 | self.currentScaleFactor = self.currentScaleFactor * self.scaleFactors[recovered_scale]
112 |
113 | if self.currentScaleFactor < self.min_scale_factor:
114 | self.currentScaleFactor = self.min_scale_factor
115 | elif self.currentScaleFactor > self.max_scale_factor:
116 | self.currentScaleFactor = self.max_scale_factor
117 |
118 | # update
119 | update_patch = utils.get_subwindow(image, self.pos, self.sz, scale_factor=self.currentScaleFactor)
120 | hog_feature_l = pyhog.features_pedro(update_patch / 255., 1)
121 | hog_feature_l = np.lib.pad(hog_feature_l, ((1, 1), (1, 1), (0, 0)), 'edge')
122 | xl = np.multiply(hog_feature_l, self.cos_window[:, :, None])
123 | xlf = np.fft.fft2(xl, axes=(0, 1))
124 | new_x_num = np.multiply(self.yf[:, :, None], np.conj(xlf))
125 | new_x_den = np.real(np.sum(np.multiply(xlf, np.conj(xlf)), axis=2))
126 |
127 | sl = utils.get_scale_subwindow(image, self.pos, self.base_target_size,
128 | self.currentScaleFactor * self.scaleSizeFactors, self.scale_window,
129 | self.scale_model_sz)
130 | slf = np.fft.fftn(sl, axes=[0])
131 | new_s_num = np.multiply(self.ysf[:, None], np.conj(slf))
132 | new_s_den = np.real(np.sum(np.multiply(slf, np.conj(slf)), axis=1))
133 |
134 | self.x_num = (1 - self.interp_factor) * self.x_num + self.interp_factor * new_x_num
135 | self.x_den = (1 - self.interp_factor) * self.x_den + self.interp_factor * new_x_den
136 | self.s_num = (1 - self.interp_factor) * self.s_num + self.interp_factor * new_s_num
137 | self.s_den = (1 - self.interp_factor) * self.s_den + self.interp_factor * new_s_den
138 |
139 | self.target_size = self.base_target_size * self.currentScaleFactor
140 |
141 | return vot.Rectangle(self.pos[1] - self.target_size[1] / 2,
142 | self.pos[0] - self.target_size[0] / 2,
143 | self.target_size[1],
144 | self.target_size[0]
145 | )
146 |
147 | handle = vot.VOT("rectangle")
148 | selection = handle.region()
149 |
150 | imagefile = handle.frame()
151 | if not imagefile:
152 | sys.exit(0)
153 |
154 | image = cv2.imread(imagefile)
155 | tracker = DSSTtracker(image, selection)
156 | while True:
157 | imagefile = handle.frame()
158 | if not imagefile:
159 | break
160 | image = cv2.imread(imagefile)
161 | region = tracker.track(image)
162 | handle.report(region)
163 | handle.quit()
164 |
165 |
166 |
--------------------------------------------------------------------------------
/HCFtracker.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import cv2
3 | import numpy as np
4 | import torch
5 | from scipy import ndimage
6 | from skimage import transform
7 | from torch.autograd import Variable
8 | import utils
9 | import vgg
10 | import vot
11 |
12 | class padding:
13 | def __init__(self):
14 | self.generic = 1.8
15 | self.large = 1
16 | self.height = 0.4
17 |
18 | outputlayer = [17,26,35]
19 | numlayers = len(outputlayer)
20 | layerweights = [0.25,0.5,1]
21 | assert (numlayers == len(layerweights))
22 |
23 | # network init
24 |
25 | model = vgg.VGG_19(outputlayer=outputlayer)
26 |
27 | # load partial weights
28 | model_dict = model.state_dict()
29 |
30 | # absolute path
31 | params = torch.load('/media/maoxiaofeng/project/GameProject/Visual_Tracking_api/vgg19.pth')
32 | load_dict = {k: v for k, v in params.items() if 'features' in k}
33 | model_dict.update(load_dict)
34 | model.load_state_dict(model_dict)
35 | model.cuda()
36 |
37 | # extract features
38 | imgMean = np.array([0.485, 0.456, 0.406], np.float)
39 | imgStd = np.array([0.229, 0.224, 0.225])
40 |
41 |
42 | class HCFtracker:
43 | def __init__(self, image, region):
44 |
45 | self.target_size = np.array([region.height, region.width])
46 | self.pos = [region.y + region.height / 2, region.x + region.width / 2]
47 | self.sz = utils.get_window_size(self.target_size, image.shape[:2], padding())
48 |
49 | # position prediction params
50 | self.lamda = 1e-4
51 | output_sigma_factor = 0.1
52 | self.cell_size = 4
53 | self.interp_factor = 0.01
54 | self.x_num = []
55 | self.x_den = []
56 |
57 | # scale estimation params
58 | self.current_scale_factor = 1.0
59 | nScales = 33
60 | scale_step = 1.02 # step of one scale level
61 | scale_sigma_factor = 1 / float(4)
62 | self.interp_factor_scale = 0.01
63 | scale_model_max_area = 32 * 16
64 | scale_model_factor = 1.0
65 | self.min_scale_factor = np.power(scale_step,
66 | np.ceil(np.log(5. / np.min(self.sz)) / np.log(scale_step)))
67 |
68 | self.max_scale_factor = np.power(scale_step,
69 | np.floor(np.log(np.min(np.divide(image.shape[:2],
70 | self.target_size)))
71 | / np.log(scale_step)))
72 |
73 | if scale_model_factor * scale_model_factor * np.prod(self.target_size) > scale_model_max_area:
74 | scale_model_factor = np.sqrt(scale_model_max_area / np.prod(self.target_size))
75 |
76 | self.scale_model_sz = np.floor(self.target_size * scale_model_factor)
77 |
78 | # Gaussian shaped label for position perdiction
79 | l1_patch_num = np.floor(self.sz / self.cell_size)
80 | output_sigma = np.sqrt(np.prod(self.target_size)) * output_sigma_factor / self.cell_size
81 | grid_y = np.arange(np.floor(l1_patch_num[0])) - np.floor(l1_patch_num[0] / 2)
82 | grid_x = np.arange(np.floor(l1_patch_num[1])) - np.floor(l1_patch_num[1] / 2)
83 | rs, cs = np.meshgrid(grid_x, grid_y)
84 | y = np.exp(-0.5 / output_sigma ** 2 * (rs ** 2 + cs ** 2))
85 | self.yf = np.fft.fft2(y, axes=(0, 1))
86 | self.cos_window = np.outer(np.hanning(self.yf.shape[0]), np.hanning(self.yf.shape[1]))
87 |
88 | # Gaussian shaped label for scale estimation
89 | ss = np.arange(nScales) - np.ceil(nScales / 2)
90 | scale_sigma = np.sqrt(nScales) * scale_sigma_factor
91 | ys = np.exp(-0.5 * (ss ** 2) / scale_sigma ** 2)
92 | self.scaleFactors = np.power(scale_step, -ss)
93 | self.ysf = np.fft.fft(ys)
94 | if nScales % 2 == 0:
95 | self.scale_window = np.hanning(nScales + 1)
96 | self.scale_window = self.scale_window[1:]
97 | else:
98 | self.scale_window = np.hanning(nScales)
99 |
100 | # Extracting hierarchical convolutional features and training
101 | img = utils.get_subwindow(image, self.pos, self.sz)
102 | img = transform.resize(img, (224, 224))
103 | img = (img - imgMean) / imgStd
104 | img = np.transpose(img, (2, 0, 1))
105 | feature_ensemble = model(Variable(torch.from_numpy(img[None, :, :, :]).float()).cuda())
106 |
107 | for i in range(numlayers):
108 |
109 | feature = feature_ensemble[i].data[0].cpu().numpy().transpose((1, 2, 0))
110 | x = ndimage.zoom(feature, (float(self.cos_window.shape[0]) / feature.shape[0],
111 | float(self.cos_window.shape[1]) / feature.shape[1], 1), order=1)
112 | x = np.multiply(x, self.cos_window[:, :, None])
113 | xf = np.fft.fft2(x, axes=(0, 1))
114 |
115 | self.x_num.append(np.multiply(self.yf[:, :, None], np.conj(xf)))
116 | self.x_den.append(np.real(np.sum(np.multiply(xf, np.conj(xf)), axis=2)))
117 |
118 | # Extracting the sample feature map for the scale filter and training
119 | s = utils.get_scale_subwindow(image, self.pos, self.target_size,
120 | self.current_scale_factor * self.scaleFactors, self.scale_window,
121 | self.scale_model_sz)
122 |
123 | sf = np.fft.fftn(s, axes=[0])
124 | self.s_num = np.multiply(self.ysf[:, None], np.conj(sf))
125 | self.s_den = np.real(np.sum(np.multiply(sf, np.conj(sf)), axis=1))
126 |
127 |
128 |
129 | def track(self, image):
130 | test = utils.get_subwindow(image, self.pos, self.sz, self.current_scale_factor)
131 | test = transform.resize(test, (224, 224))
132 | test = (test - imgMean) / imgStd
133 | test = np.transpose(test, (2, 0, 1))
134 | feature_ensemble = model(Variable(torch.from_numpy(test[None, :, :, :]).float()).cuda())
135 |
136 | for i in range(numlayers):
137 |
138 | feature = feature_ensemble[i].data[0].cpu().numpy().transpose((1, 2, 0))
139 | xt = ndimage.zoom(feature, (float(self.cos_window.shape[0]) / feature.shape[0],
140 | float(self.cos_window.shape[1]) / feature.shape[1], 1), order=1)
141 | xt = np.multiply(xt, self.cos_window[:, :, None])
142 | xtf = np.fft.fft2(xt, axes=(0, 1))
143 | response = np.real(np.fft.ifft2(np.divide(np.sum(np.multiply(self.x_num[i], xtf),
144 | axis=2), (self.x_den[i] + self.lamda)))) * layerweights[i]
145 | if i == 0:
146 | response_final = response
147 | else:
148 | response_final = np.add(response_final, response)
149 |
150 | v_centre, h_centre = np.unravel_index(response_final.argmax(), response_final.shape)
151 | vert_delta, horiz_delta = \
152 | [(v_centre - response_final.shape[0] / 2) * self.current_scale_factor * self.cell_size,
153 | (h_centre - response_final.shape[1] / 2) * self.current_scale_factor * self.cell_size]
154 |
155 | self.pos = [self.pos[0] + vert_delta, self.pos[1] + horiz_delta]
156 |
157 | st = utils.get_scale_subwindow(image, self.pos, self.target_size,
158 | self.current_scale_factor * self.scaleFactors, self.scale_window,
159 | self.scale_model_sz)
160 | stf = np.fft.fftn(st, axes=[0])
161 |
162 | scale_reponse = np.real(np.fft.ifftn(np.sum(np.divide(np.multiply(self.s_num, stf),
163 | (self.s_den[:, None] + self.lamda)), axis=1)))
164 | recovered_scale = np.argmax(scale_reponse)
165 | self.current_scale_factor = self.current_scale_factor * self.scaleFactors[recovered_scale]
166 |
167 | if self.current_scale_factor < self.min_scale_factor:
168 | self.current_scale_factor = self.min_scale_factor
169 | elif self.current_scale_factor > self.max_scale_factor:
170 | self.current_scale_factor = self.max_scale_factor
171 |
172 | # update
173 |
174 | update_patch = utils.get_subwindow(image, self.pos, self.sz, scale_factor=self.current_scale_factor)
175 |
176 | update_patch = transform.resize(update_patch, (224, 224))
177 | update_patch = (update_patch - imgMean) / imgStd
178 | update_patch = np.transpose(update_patch, (2, 0, 1))
179 | feature_ensemble = model(Variable(torch.from_numpy(update_patch[None, :, :, :]).float()).cuda())
180 |
181 | for i in range(numlayers):
182 | feature = feature_ensemble[i].data[0].cpu().numpy().transpose((1, 2, 0))
183 | xl = ndimage.zoom(feature, (float(self.cos_window.shape[0]) / feature.shape[0],
184 | float(self.cos_window.shape[1]) / feature.shape[1], 1), order=1)
185 | xl = np.multiply(xl, self.cos_window[:, :, None])
186 | xlf = np.fft.fft2(xl, axes=(0, 1))
187 | self.x_num[i] = (1 - self.interp_factor) * self.x_num[i] + self.interp_factor * np.multiply(self.yf[:, :, None], np.conj(xlf))
188 | self.x_den[i] = (1 - self.interp_factor) * self.x_den[i] + self.interp_factor * np.real(np.sum(np.multiply(xlf, np.conj(xlf)), axis=2))
189 |
190 | sl = utils.get_scale_subwindow(image, self.pos, self.target_size,
191 | self.current_scale_factor * self.scaleFactors, self.scale_window,
192 | self.scale_model_sz)
193 | slf = np.fft.fftn(sl, axes=[0])
194 | new_s_num = np.multiply(self.ysf[:, None], np.conj(slf))
195 | new_s_den = np.real(np.sum(np.multiply(slf, np.conj(slf)), axis=1))
196 | self.s_num = (1 - self.interp_factor) * self.s_num + self.interp_factor * new_s_num
197 | self.s_den = (1 - self.interp_factor) * self.s_den + self.interp_factor * new_s_den
198 |
199 | self.final_size = self.target_size * self.current_scale_factor
200 |
201 | return vot.Rectangle(self.pos[1] - self.final_size[1] / 2,
202 | self.pos[0] - self.final_size[0] / 2,
203 | self.final_size[1],
204 | self.final_size[0]
205 | )
206 |
207 |
208 |
209 |
210 | handle = vot.VOT("rectangle")
211 | selection = handle.region()
212 |
213 | imagefile = handle.frame()
214 | if not imagefile:
215 | sys.exit(0)
216 |
217 | image = cv2.imread(imagefile)
218 | tracker = HCFtracker(image, selection)
219 | while True:
220 | imagefile = handle.frame()
221 | if not imagefile:
222 | break
223 | image = cv2.imread(imagefile)
224 | region = tracker.track(image)
225 | handle.report(region)
226 | handle.quit()
227 |
228 |
--------------------------------------------------------------------------------
/KCFtracker.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import cv2
3 | import numpy as np
4 | import utils
5 | import vot
6 |
7 |
8 | class KCFtracker:
9 | def __init__(self, image, region):
10 | self.target_size = np.array([region.height, region.width])
11 | self.pos = [region.y + region.height / 2, region.x + region.width / 2]
12 | padding = 2.5 # extra area surrounding the target
13 | self.patch_size = np.floor(self.target_size * (1 + padding))
14 | img_crop = utils.get_subwindow(image, self.pos, self.patch_size)
15 |
16 | spatial_bandwidth_sigma_factor = 1 / float(16)
17 | output_sigma = np.sqrt(np.prod(self.target_size)) * spatial_bandwidth_sigma_factor
18 | grid_y = np.arange(np.floor(self.patch_size[0])) - np.floor(self.patch_size[0] / 2)
19 | grid_x = np.arange(np.floor(self.patch_size[1])) - np.floor(self.patch_size[1] / 2)
20 | rs, cs = np.meshgrid(grid_x, grid_y)
21 | y = np.exp(-0.5 / output_sigma ** 2 * (rs ** 2 + cs ** 2))
22 |
23 | self.cos_window = np.outer(np.hanning(y.shape[0]), np.hanning(y.shape[1]))
24 | img_colour = img_crop - img_crop.mean()
25 | # Get training image patch x
26 | self.x = np.multiply(img_colour, self.cos_window[:, :, None])
27 |
28 | # FFT Transformation
29 | # First transform y
30 | yf = np.fft.fft2(y, axes=(0, 1))
31 |
32 | # Then transfrom x
33 | self.xf = np.fft.fft2(self.x, axes=(0, 1))
34 | self.feature_bandwidth_sigma = 0.2
35 | k = utils.dense_gauss_kernel(self.feature_bandwidth_sigma, self.xf, self.x)
36 |
37 | lambda_value = 1e-4
38 | self.alphaf = np.divide(yf, np.fft.fft2(k, axes=(0, 1)) + lambda_value)
39 |
40 | def track(self, image):
41 |
42 | test_crop = utils.get_subwindow(image, self.pos, self.patch_size)
43 | z = np.multiply(test_crop - test_crop.mean(), self.cos_window[:, :, None])
44 | zf = np.fft.fft2(z, axes=(0, 1))
45 | k_test = utils.dense_gauss_kernel(self.feature_bandwidth_sigma, self.xf, self.x, zf, z)
46 | kf_test = np.fft.fft2(k_test, axes=(0, 1))
47 | response = np.real(np.fft.ifft2(np.multiply(self.alphaf, kf_test)))
48 |
49 | # Max position in response map
50 | v_centre, h_centre = np.unravel_index(response.argmax(), response.shape)
51 | vert_delta, horiz_delta = [v_centre - response.shape[0] / 2,
52 | h_centre - response.shape[1] / 2]
53 |
54 | # Predicted position
55 | self.pos = [self.pos[0] + vert_delta, self.pos[1] + horiz_delta]
56 | return vot.Rectangle(self.pos[1] - self.target_size[1] / 2,
57 | self.pos[0] - self.target_size[0] / 2,
58 | self.target_size[1],
59 | self.target_size[0]
60 | )
61 |
62 | handle = vot.VOT("rectangle")
63 | selection = handle.region()
64 |
65 | imagefile = handle.frame()
66 | if not imagefile:
67 | sys.exit(0)
68 |
69 | image = cv2.imread(imagefile)/255.
70 | tracker = KCFtracker(image, selection)
71 | while True:
72 | imagefile = handle.frame()
73 | if not imagefile:
74 | break
75 | image = cv2.imread(imagefile)/255.
76 | region = tracker.track(image)
77 | handle.report(region)
78 | handle.quit()
79 |
80 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Visual_Tracking_api
2 |
3 |
4 | This is a simple visual tracking interface coding by Python2.7
5 |
6 | ## Introduction
7 |
8 | This repository contains the following contents:
9 |
10 | `tutorials` folder contains the implementation and tutorial of various famous tracking algorithms written with ipython-notebook. Learning these notebooks helps you understand the details of the algorithms.
11 |
12 | `pyhog` folder includes a implementation of HOG feature. We copied this implementation from https://github.com/dimatura/pyhog
13 |
14 | python wrapper script file named `XXXtracker.py`,such as `KCFtracker.py`. These trackers can be integrated into the VOT evaluation process. There is a demo file `vot_demo_tracker.py` representing how to write the wrapper script file.
15 | You can refer to < Usage > for getting more information.
16 |
17 | ## Trackers
18 |
19 | Trackers that have been implemented are as follows:
20 |
21 | - `KCFtracker.py` High-Speed Tracking with Kernelized Correlation Filters (KCF) [[PDF]](http://home.isr.uc.pt/~henriques/publications/henriques_tpami2015.pdf)
22 |
23 | - `DSSTtracker.py` Accurate Scale Estimation for Robust Visual Tracking (DSST) [[PDF]](http://www.cvl.isy.liu.se/en/research/objrec/visualtracking/scalvistrack/ScaleTracking_BMVC14.pdf)
24 |
25 | - `HCFtracker.py` Hierarchical Convolutional Features for Visual Tracking (HCF) [[PDF]](https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/Ma_Hierarchical_Convolutional_Features_ICCV_2015_paper.pdf)
26 |
27 | ## Environment
28 |
29 | Python 2.7.12
30 |
31 | scikit-image 0.13.0
32 |
33 | scipy 0.19.1
34 |
35 | matplotlib 1.5.3
36 |
37 | numpy 1.13.1
38 |
39 | pytorch 0.1.12
40 |
41 | opencv 2.4.11
42 |
43 | ## Usage
44 |
45 | ### Prepare
46 |
47 | Before using the tracking interface, you must do some preparation.
48 |
49 | First of all, install the necessary library (mentioned in < Environment >)
50 |
51 | Then, if the algorithm requires hog features, you must move the folder `pyhog` to Python site-packages by:
52 |
53 | ```buildoutcfg
54 | sudo cp -r .../Visual_Tracking_api/pyhog /usr/local/lib/python2.7/site-packages
55 | ```
56 |
57 | Or the algorithm requires deep features (we use pretrained vgg19 in general), you need to download model file 'vgg19.pth' by url:
58 |
59 | https://download.pytorch.org/models/vgg19-dcbb9e9d.pth
60 |
61 | and place it in project directory.
62 |
63 | ### Tracking on you own sequence
64 |
65 | You can use this tool to track on you own sequence:
66 |
67 | Make sure that your video has been decomposed into image sequences and each image is named with a number
68 | (if the current image corresponds to the ith frame in the video, then the name is i.jpg or 0000i.jpg, adding 0 in front of the i is OK). For example:
69 |
70 | 
71 |
72 | Except for the image sequence, you need to provide `groundtruth.txt` file which represents the boundingbox infromation.
73 | The boundingbox of the first frame must be give, so there are at least one line in the `groundtruth.txt` file.
74 | For example:
75 | ```
76 | 20.0,30.0,50.0,100.0
77 | ```
78 | Represents the boundingbox at (20.0, 30.0) position, width and height are respectively 50.0, 100.0.
79 | Of course, if there are other frames of boundingbox information, it can also be written in `groundtruth.txt`.
80 |
81 | We provide tools to run algorithms on custom sequences.
82 | `example.py` is an demo for understanding how to use. First, you need to configure the sequence by
83 |
84 | ```python
85 | sequence = Sequence(path='/YOUR_ROOT_DIR/YOUR_DATASET_NAME', name='THE_NAME_OF_SEQUENCE', region_format='rectangle')
86 |
87 | ```
88 |
89 | For example, configure a sequence of vot2016:
90 |
91 | ```python
92 | sequence = Sequence(path='/media/maoxiaofeng/project/GameProject/dataset/vot2016', name='bag',
93 | region_format='rectangle')
94 |
95 | ```
96 |
97 | Then, run tracking algorithms on the configured sequence by
98 | (If you want to visualize the result, modify `visualize` to True)
99 |
100 | ```python
101 | Tracking(sequence,tracker_list=['KCFtracker','DSSTtracker'],visualize = False)
102 |
103 | ```
104 |
105 | Also you can visulize results directly by ( `visualize_gt` controls whether to visualize the groundtruth. If `tracker_list` is None, this function will only visualize the groundtruth. )
106 |
107 | ```python
108 | visulize_result(sequence,tracker_list=['KCFtracker','DSSTtracker'],visualize_gt = True)
109 | ```
110 |
111 |
112 | ### Evaluate on VOT dataset
113 |
114 | Now the interface is compatible with VOT dataset, use [vot-toolkit](https://github.com/votchallenge/vot-toolkit) to evaluate the tracking algorithm on VOT datasets.
115 |
116 | You can download Visual Object Tracking (VOT) challenge datasets through the following links:
117 |
118 | [VOT2015](http://data.votchallenge.net/vot2015/vot2015.zip), [VOT2016](http://data.votchallenge.net/vot2016/vot2016.zip), [VOT2014](http://data.votchallenge.net/vot2014/vot2014.zip), [VOT2013](http://data.votchallenge.net/vot2013/vot2013.zip)
119 |
120 | Then set up VOT workspace (http://www.votchallenge.net/howto/workspace.html) and integrate trackers into the VOT toolkit (http://www.votchallenge.net/howto/integration.html)
121 |
122 | For detail information, please visit VOT official website:http://www.votchallenge.net/
123 |
124 |
--------------------------------------------------------------------------------
/Sequence.py:
--------------------------------------------------------------------------------
1 | """
2 | \file Sequence.py
3 |
4 | @author Xiaofeng Mao
5 |
6 | @date 2017.9.27
7 |
8 | """
9 |
10 | import sys
11 | import copy
12 | import collections
13 | import os
14 |
15 |
16 | Rectangle = collections.namedtuple('Rectangle', ['x', 'y', 'width', 'height'])
17 | Point = collections.namedtuple('Point', ['x', 'y'])
18 | Polygon = collections.namedtuple('Polygon', ['points'])
19 |
20 | def parse_region(string):
21 | tokens = map(float, string.split(','))
22 | if len(tokens) == 4:
23 | return Rectangle(tokens[0], tokens[1], tokens[2], tokens[3])
24 | elif len(tokens) % 2 == 0 and len(tokens) > 4:
25 | return Polygon([Point(tokens[i],tokens[i+1]) for i in xrange(0,len(tokens),2)])
26 | return None
27 |
28 | def encode_region(region):
29 | if isinstance(region, Polygon):
30 | return ','.join(['{},{}'.format(p.x,p.y) for p in region.points])
31 | elif isinstance(region, Rectangle):
32 | return '{},{},{},{}'.format(region.x, region.y, region.width, region.height)
33 | else:
34 | return ""
35 |
36 | def convert_region(region, to):
37 |
38 | if to == 'rectangle':
39 |
40 | if isinstance(region, Rectangle):
41 | return copy.copy(region)
42 | elif isinstance(region, Polygon):
43 | top = sys.float_info.max
44 | bottom = sys.float_info.min
45 | left = sys.float_info.max
46 | right = sys.float_info.min
47 |
48 | for point in region.points:
49 | top = min(top, point.y)
50 | bottom = max(bottom, point.y)
51 | left = min(left, point.x)
52 | right = max(right, point.x)
53 |
54 | return Rectangle(left, top, right - left, bottom - top)
55 |
56 | else:
57 | return None
58 | if to == 'polygon':
59 |
60 | if isinstance(region, Rectangle):
61 | points = []
62 | points.append((region.x, region.y))
63 | points.append((region.x + region.width, region.y))
64 | points.append((region.x + region.width, region.y + region.height))
65 | points.append((region.x, region.y + region.height))
66 | return Polygon(points)
67 |
68 | elif isinstance(region, Polygon):
69 | return copy.copy(region)
70 | else:
71 | return None
72 |
73 | return None
74 |
75 | class Sequence(object):
76 | """ Base class for Python VOT integration """
77 | def __init__(self, path, name, region_format = 'rectangle'):
78 | self.name = name
79 | """ Constructor
80 |
81 | Args:
82 | region_format: Region format options
83 | """
84 | assert(region_format in ['rectangle', 'polygon'])
85 |
86 | if len(name) == 0:
87 | self.seqdir = path
88 | else:
89 | self.seqdir = os.path.join(path, name)
90 |
91 | self._images=[]
92 | for _, _, files in os.walk(self.seqdir):
93 | for file in files:
94 | if file.endswith('jpg') or file.endswith('png'):
95 | self._images.append(file)
96 | self._images.sort(key= lambda x:int(x[:-4]))
97 |
98 | self.groundtruth = []
99 | for x in open(os.path.join(self.seqdir, 'groundtruth.txt'), 'r').readlines():
100 | self.groundtruth.append(convert_region(parse_region(x), region_format))
101 |
102 | self._frame = 0
103 | self._region = convert_region(parse_region(open(os.path.join(self.seqdir, 'groundtruth.txt'), 'r').readline()), region_format)
104 | self._result = []
105 | self._region_format = region_format
106 |
107 | def region(self):
108 | """
109 | Send configuration message to the client and receive the initialization
110 | region and the path of the first image
111 |
112 | Returns:
113 | initialization region
114 | """
115 |
116 | return self._region
117 |
118 | def report(self, region):
119 | """
120 | Report the tracking results to the client
121 |
122 | Arguments:
123 | region: region for the frame
124 | """
125 | assert(isinstance(region, Rectangle) or isinstance(region, Polygon))
126 |
127 | self._result.append(region)
128 | self._frame += 1
129 |
130 | def frame(self):
131 | """
132 | Get a frame (image path) from client
133 |
134 | Returns:
135 | absolute path of the image
136 | """
137 |
138 | if self._frame >= len(self._images):
139 | return None
140 | return os.path.join(self.seqdir, self._images[self._frame])
141 |
142 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/example.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtddggg/Visual_Tracking_api/d5cf7934861950ca1eedede198382fc468dab941/example.jpg
--------------------------------------------------------------------------------
/examples.py:
--------------------------------------------------------------------------------
1 | from Sequence import Sequence
2 | from tools import Tracking,visulize_result,precision_plot,overlap_plot
3 |
4 | sequence = Sequence(path='/media/maoxiaofeng/project/GameProject/dataset/vot-tir2016', name='birds', region_format='rectangle')
5 |
6 | #Tracking(sequence,tracker_list=['HCFtracker'],visualize=False)
7 | #visulize_result(sequence,tracker_list=['HCFtracker'],visualize_gt = True)
8 | #precision_plot(sequence, tracker_list=['HCFtracker'])
9 | #overlap_plot(sequence, tracker_list=['HCFtracker'])
--------------------------------------------------------------------------------
/image/files.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtddggg/Visual_Tracking_api/d5cf7934861950ca1eedede198382fc468dab941/image/files.png
--------------------------------------------------------------------------------
/pyhog/COPYING:
--------------------------------------------------------------------------------
1 | Copyright (C) 2008, 2009, 2010 Pedro Felzenszwalb, Ross Girshick
2 | Copyright (C) 2007 Pedro Felzenszwalb, Deva Ramanan
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining
5 | a copy of this software and associated documentation files (the
6 | "Software"), to deal in the Software without restriction, including
7 | without limitation the rights to use, copy, modify, merge, publish,
8 | distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so, subject to
10 | the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/pyhog/Makefile:
--------------------------------------------------------------------------------
1 | NUMPY=`python -c 'import numpy; print numpy.get_include()'`
2 | PYROOT=`python -c 'import sys; print sys.prefix'`
3 | VER=`python -c "import sys; print('%s.%s'%(sys.version_info[0],sys.version_info[1]))"`
4 | CC=g++
5 | LIBS=
6 | #FLAGS= -Wall -DNUMPYCHECK -fPIC
7 | #FLAGS = -Wall -DNDEBUG -O2 -ffast-math -pipe -msse -msse2 -mmmx -mfpmath=sse -fomit-frame-pointer
8 | #FLAGS = -Wall -DNDEBUG -O2 -ffast-math -fPIC
9 | FLAGS = -DNUMPYCHECK -DNDEBUG -O2 -ffast-math -msse2 -fPIC
10 |
11 | .PHONY: all
12 | all: features_pedro_py.so
13 |
14 | features_pedro_py.so: features_pedro_py.o
15 | g++ $^ -shared -o $@ $(LIBS)
16 |
17 | features_pedro_py.o: features_pedro_py.cc numpymacros.h
18 | g++ -c $< $(FLAGS) -I$(NUMPY) -I$(PYROOT)/include/python$(VER) -I../src/ -o $@
19 |
20 | .PHONY: clean
21 | clean:
22 | rm -f *.o *.so
23 |
--------------------------------------------------------------------------------
/pyhog/README.rst:
--------------------------------------------------------------------------------
1 |
2 | pyhog
3 | ----------
4 |
5 | The Pascal VOC Toolkit comes with a Matlab/C implementation of HOG features by
6 | Pedro Felzenszwalb, Deva Ramanan and presumably others. Since I'm not very fond
7 | of Matlab I replaced the Matlab-specific parts for their Numpy equivalents. It
8 | works, but it's not very efficient because it copies the array into a
9 | Fortran-ordered version. That should be easy to fix.
10 |
11 | See an example of here: http://nbviewer.ipython.org/github/dimatura/pyhog/blob/master/pyhog_example.ipynb
12 |
13 | Daniel Maturana - dimatura@cmu.edu
14 | 2012
15 |
--------------------------------------------------------------------------------
/pyhog/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtddggg/Visual_Tracking_api/d5cf7934861950ca1eedede198382fc468dab941/pyhog/__init__.py
--------------------------------------------------------------------------------
/pyhog/features_pedro_py.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
3 | #include
4 |
5 | #include
6 | #include
7 |
8 | #include "numpymacros.h"
9 |
10 | // small value, used to avoid division by zero
11 | #define eps 0.0001
12 |
13 | // unit vectors used to compute gradient orientation
14 | double uu[9] = {1.0000,
15 | 0.9397,
16 | 0.7660,
17 | 0.500,
18 | 0.1736,
19 | -0.1736,
20 | -0.5000,
21 | -0.7660,
22 | -0.9397};
23 | double vv[9] = {0.0000,
24 | 0.3420,
25 | 0.6428,
26 | 0.8660,
27 | 0.9848,
28 | 0.9848,
29 | 0.8660,
30 | 0.6428,
31 | 0.3420};
32 |
33 | static inline double min(double x, double y) { return (x <= y ? x : y); }
34 | static inline double max(double x, double y) { return (x <= y ? y : x); }
35 |
36 | static inline int min(int x, int y) { return (x <= y ? x : y); }
37 | static inline int max(int x, int y) { return (x <= y ? y : x); }
38 |
39 | // main function:
40 | // takes a double color image and a bin size
41 | // returns HOG features
42 | static PyObject *process(PyObject *self, PyObject *args) {
43 | // in
44 | PyArrayObject *mximage;
45 | int sbin;
46 |
47 | // out
48 | PyArrayObject *mxfeat;
49 |
50 | if (!PyArg_ParseTuple(args, "O!i",
51 | &PyArray_Type, &mximage,
52 | &sbin
53 | )) {
54 | return NULL;
55 | }
56 |
57 | //TODO fix warnings
58 | FARRAY_CHECK(mximage);
59 | NDIM_CHECK(mximage, 3);
60 | DIM_CHECK(mximage, 2, 3);
61 | TYPE_CHECK(mximage, NPY_FLOAT64);
62 |
63 | double *im = (double *)PyArray_DATA(mximage);
64 | npy_intp dims[3];
65 | dims[0] = PyArray_DIM(mximage, 0);
66 | dims[1] = PyArray_DIM(mximage, 1);
67 | dims[2] = PyArray_DIM(mximage, 2);
68 | //printf("%d %d %d\n",(int)dims[0],(int)dims[1],(int)dims[2]);
69 |
70 | // memory for caching orientation histograms & their norms
71 | int blocks[2];
72 | blocks[0] = (int)round((double)dims[0]/(double)sbin);
73 | blocks[1] = (int)round((double)dims[1]/(double)sbin);
74 |
75 | double *hist = (double *)calloc(blocks[0]*blocks[1]*18, sizeof(double));
76 | double *norm = (double *)calloc(blocks[0]*blocks[1], sizeof(double));
77 |
78 | // memory for HOG features
79 | // TODO there's a way to do this in one call
80 | npy_intp out[3];
81 | out[0] = max(blocks[0]-2, 0);
82 | out[1] = max(blocks[1]-2, 0);
83 | out[2] = 27+4;
84 |
85 | //mxfeat = mxCreateNumericArray(3, out, mxDOUBLE_CLASS, mxREAL);
86 | mxfeat = (PyArrayObject*) PyArray_NewFromDescr(
87 | &PyArray_Type, PyArray_DescrFromType(NPY_FLOAT64),
88 | 3, out, NULL, NULL, NPY_ARRAY_F_CONTIGUOUS, NULL);
89 | //(PyArrayObject *)PyArray_SimpleNew(3, out, NPY_FLOAT64);
90 |
91 | double *feat = (double *)PyArray_DATA(mxfeat);
92 |
93 | int visible[2];
94 | visible[0] = blocks[0]*sbin;
95 | visible[1] = blocks[1]*sbin;
96 |
97 | for (int x = 1; x < visible[1]-1; x++) {
98 | for (int y = 1; y < visible[0]-1; y++) {
99 | // first color channel
100 | double *s = im + min(x, dims[1]-2)*dims[0] + min(y, dims[0]-2);
101 | double dy = *(s+1) - *(s-1);
102 | double dx = *(s+dims[0]) - *(s-dims[0]);
103 | double v = dx*dx + dy*dy;
104 |
105 | // second color channel
106 | s += dims[0]*dims[1];
107 | double dy2 = *(s+1) - *(s-1);
108 | double dx2 = *(s+dims[0]) - *(s-dims[0]);
109 | double v2 = dx2*dx2 + dy2*dy2;
110 |
111 | // third color channel
112 | s += dims[0]*dims[1];
113 | double dy3 = *(s+1) - *(s-1);
114 | double dx3 = *(s+dims[0]) - *(s-dims[0]);
115 | double v3 = dx3*dx3 + dy3*dy3;
116 |
117 | // pick channel with strongest gradient
118 | if (v2 > v) {
119 | v = v2;
120 | dx = dx2;
121 | dy = dy2;
122 | }
123 | if (v3 > v) {
124 | v = v3;
125 | dx = dx3;
126 | dy = dy3;
127 | }
128 |
129 | // snap to one of 18 orientations
130 | double best_dot = 0;
131 | int best_o = 0;
132 | for (int o = 0; o < 9; o++) {
133 | double dot = uu[o]*dx + vv[o]*dy;
134 | if (dot > best_dot) {
135 | best_dot = dot;
136 | best_o = o;
137 | } else if (-dot > best_dot) {
138 | best_dot = -dot;
139 | best_o = o+9;
140 | }
141 | }
142 |
143 | // add to 4 histograms around pixel using linear interpolation
144 | double xp = ((double)x+0.5)/(double)sbin - 0.5;
145 | double yp = ((double)y+0.5)/(double)sbin - 0.5;
146 | int ixp = (int)floor(xp);
147 | int iyp = (int)floor(yp);
148 | double vx0 = xp-ixp;
149 | double vy0 = yp-iyp;
150 | double vx1 = 1.0-vx0;
151 | double vy1 = 1.0-vy0;
152 | v = sqrt(v);
153 |
154 | if (ixp >= 0 && iyp >= 0) {
155 | *(hist + ixp*blocks[0] + iyp + best_o*blocks[0]*blocks[1]) +=
156 | vx1*vy1*v;
157 | }
158 |
159 | if (ixp+1 < blocks[1] && iyp >= 0) {
160 | *(hist + (ixp+1)*blocks[0] + iyp + best_o*blocks[0]*blocks[1]) +=
161 | vx0*vy1*v;
162 | }
163 |
164 | if (ixp >= 0 && iyp+1 < blocks[0]) {
165 | *(hist + ixp*blocks[0] + (iyp+1) + best_o*blocks[0]*blocks[1]) +=
166 | vx1*vy0*v;
167 | }
168 |
169 | if (ixp+1 < blocks[1] && iyp+1 < blocks[0]) {
170 | *(hist + (ixp+1)*blocks[0] + (iyp+1) + best_o*blocks[0]*blocks[1]) +=
171 | vx0*vy0*v;
172 | }
173 | }
174 | }
175 |
176 | // compute energy in each block by summing over orientations
177 | for (int o = 0; o < 9; o++) {
178 | double *src1 = hist + o*blocks[0]*blocks[1];
179 | double *src2 = hist + (o+9)*blocks[0]*blocks[1];
180 | double *dst = norm;
181 | double *end = norm + blocks[1]*blocks[0];
182 | while (dst < end) {
183 | *(dst++) += (*src1 + *src2) * (*src1 + *src2);
184 | src1++;
185 | src2++;
186 | }
187 | }
188 |
189 | // compute features
190 | for (int x = 0; x < out[1]; x++) {
191 | for (int y = 0; y < out[0]; y++) {
192 | double *dst = feat + x*out[0] + y;
193 | double *src, *p, n1, n2, n3, n4;
194 |
195 | p = norm + (x+1)*blocks[0] + y+1;
196 | n1 = 1.0 / sqrt(*p + *(p+1) + *(p+blocks[0]) + *(p+blocks[0]+1) + eps);
197 | p = norm + (x+1)*blocks[0] + y;
198 | n2 = 1.0 / sqrt(*p + *(p+1) + *(p+blocks[0]) + *(p+blocks[0]+1) + eps);
199 | p = norm + x*blocks[0] + y+1;
200 | n3 = 1.0 / sqrt(*p + *(p+1) + *(p+blocks[0]) + *(p+blocks[0]+1) + eps);
201 | p = norm + x*blocks[0] + y;
202 | n4 = 1.0 / sqrt(*p + *(p+1) + *(p+blocks[0]) + *(p+blocks[0]+1) + eps);
203 |
204 | double t1 = 0;
205 | double t2 = 0;
206 | double t3 = 0;
207 | double t4 = 0;
208 |
209 | // contrast-sensitive features
210 | src = hist + (x+1)*blocks[0] + (y+1);
211 | for (int o = 0; o < 18; o++) {
212 | double h1 = min(*src * n1, 0.2);
213 | double h2 = min(*src * n2, 0.2);
214 | double h3 = min(*src * n3, 0.2);
215 | double h4 = min(*src * n4, 0.2);
216 | *dst = 0.5 * (h1 + h2 + h3 + h4);
217 | t1 += h1;
218 | t2 += h2;
219 | t3 += h3;
220 | t4 += h4;
221 | dst += out[0]*out[1];
222 | src += blocks[0]*blocks[1];
223 | }
224 |
225 | // contrast-insensitive features
226 | src = hist + (x+1)*blocks[0] + (y+1);
227 | for (int o = 0; o < 9; o++) {
228 | double sum = *src + *(src + 9*blocks[0]*blocks[1]);
229 | double h1 = min(sum * n1, 0.2);
230 | double h2 = min(sum * n2, 0.2);
231 | double h3 = min(sum * n3, 0.2);
232 | double h4 = min(sum * n4, 0.2);
233 | *dst = 0.5 * (h1 + h2 + h3 + h4);
234 | dst += out[0]*out[1];
235 | src += blocks[0]*blocks[1];
236 | }
237 |
238 | // texture features
239 | *dst = 0.2357 * t1;
240 | dst += out[0]*out[1];
241 | *dst = 0.2357 * t2;
242 | dst += out[0]*out[1];
243 | *dst = 0.2357 * t3;
244 | dst += out[0]*out[1];
245 | *dst = 0.2357 * t4;
246 | }
247 | }
248 |
249 | // hack
250 | //PyArray_FLAGS(mxfeat) |= NPY_F_CONTIGUOUS;
251 | //PyArray_FLAGS(mxfeat) &= ~NPY_C_CONTIGUOUS;
252 |
253 | free(hist);
254 | free(norm);
255 |
256 | return PyArray_Return(mxfeat);//Py_BuildValue("N", mxfeat);
257 | }
258 |
259 | static PyMethodDef features_pedro_py_methods[] = {
260 | {"process",
261 | process,
262 | METH_VARARGS,
263 | "process"},
264 | {NULL, NULL, 0, NULL} /* sentinel*/
265 | };
266 |
267 | PyMODINIT_FUNC initfeatures_pedro_py() {
268 | Py_InitModule("features_pedro_py", features_pedro_py_methods);
269 | import_array();
270 | }
271 |
272 |
--------------------------------------------------------------------------------
/pyhog/features_pedro_py.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtddggg/Visual_Tracking_api/d5cf7934861950ca1eedede198382fc468dab941/pyhog/features_pedro_py.o
--------------------------------------------------------------------------------
/pyhog/features_pedro_py.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtddggg/Visual_Tracking_api/d5cf7934861950ca1eedede198382fc468dab941/pyhog/features_pedro_py.so
--------------------------------------------------------------------------------
/pyhog/numpymacros.h:
--------------------------------------------------------------------------------
1 | #ifndef NUMPY_MACROS__H
2 | #define NUMPY_MACROS__H
3 |
4 | /*
5 | This is from the book 'Python Scripting for Computational Science'
6 | by Hans Petter Langtangen, with some modifications.
7 | */
8 |
9 | #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
10 | #include
11 |
12 | /* define some macros for array dimension/type check
13 | and subscripting */
14 | #define QUOTE(s) # s /* turn s into string "s" */
15 | #define NDIM_CHECK(a, expected_ndim) \
16 | if (PyArray_NDIM(a) != expected_ndim) { \
17 | PyErr_Format(PyExc_ValueError, \
18 | "%s array is %d-dimensional, but expected to be %d-dimensional",\
19 | QUOTE(a), PyArray_NDIM(a), expected_ndim); \
20 | return NULL; \
21 | }
22 | #define DIM_CHECK(a, dim, expected_length) \
23 | if (dim > PyArray_NDIM(a)) { \
24 | PyErr_Format(PyExc_ValueError, \
25 | "%s array has no %d dimension (max dim. is %d)", \
26 | QUOTE(a), dim, PyArray_NDIM(a)); \
27 | return NULL; \
28 | } \
29 | if (PyArray_DIM(a, dim) != expected_length) { \
30 | PyErr_Format(PyExc_ValueError, \
31 | "%s array has wrong %d-dimension=%ld (expected %d)", \
32 | QUOTE(a), dim, PyArray_DIM(a, dim), expected_length); \
33 | return NULL; \
34 | }
35 | #define TYPE_CHECK(a, tp) \
36 | if (PyArray_TYPE(a) != tp) { \
37 | PyErr_Format(PyExc_TypeError, \
38 | "%s array is not of correct type (%d)", QUOTE(a), tp); \
39 | return NULL; \
40 | }
41 | #define CALLABLE_CHECK(func) \
42 | if (!PyCallable_Check(func)) { \
43 | PyErr_Format(PyExc_TypeError, \
44 | "%s is not a callable function", QUOTE(func)); \
45 | return NULL; \
46 | }
47 | #define CARRAY_CHECK(a) \
48 | if (!(PyArray_ISCONTIGUOUS(a) && PyArray_ISCARRAY(a))) { \
49 | PyErr_Format(PyExc_TypeError, \
50 | "%s is not a contiguous c-array", QUOTE(a)); \
51 | return NULL; \
52 | }
53 | #define FARRAY_CHECK(a) \
54 | if (!(PyArray_ISFARRAY(a))) { \
55 | PyErr_Format(PyExc_TypeError, \
56 | "%s is not a contiguous f-array", QUOTE(a)); \
57 | return NULL; \
58 | }
59 | #define CHECK(assertion, message) \
60 | if (!(assertion)) { \
61 | PyErr_Format(PyExc_ValueError, message); \
62 | return NULL; \
63 | }
64 |
65 | #define DIND1(a, i) *((npy_float64 *) PyArray_GETPTR1(a, i))
66 | #define DIND2(a, i, j) \
67 | *((npy_float64 *) PyArray_GETPTR2(a, i, j))
68 | #define DIND3(a, i, j, k) \
69 | *((npy_float64 *) Py_Array_GETPTR3(a, i, j, k))
70 |
71 | #define FIND1(a, i) *((npy_float32 *) PyArray_GETPTR1(a, i))
72 | #define FIND2(a, i, j) \
73 | *((npy_float32 *) PyArray_GETPTR2(a, i, j))
74 | #define FIND3(a, i, j, k) \
75 | *((npy_float32 *) Py_Array_GETPTR3(a, i, j, k))
76 |
77 | #define IIND1(a, i) *((npy_int *) PyArray_GETPTR1(a, i))
78 | #define IIND2(a, i, j) \
79 | *((npy_int *) PyArray_GETPTR2(a, i, j))
80 | #define IIND3(a, i, j, k) \
81 | *((npy_int *) Py_Array_GETPTR3(a, i, j, k))
82 |
83 | #define U8IND2(a, i, j) \
84 | *((npy_uint8 *) PyArray_GETPTR2(a, i, j))
85 |
86 | #define U8IND3(a, i, j, k) \
87 | *((npy_uint8 *) PyArray_GETPTR3(a, i, j, k))
88 |
89 | #endif
90 |
--------------------------------------------------------------------------------
/pyhog/pyhog.py:
--------------------------------------------------------------------------------
1 |
2 | import numpy as np
3 | import features_pedro_py
4 |
5 | try:
6 | from scipy.misc import imrotate
7 | imrotate_available = True
8 | except ImportError:
9 | imrotate_available = False
10 |
11 | def features_pedro(img, sbin):
12 | imgf = img.copy('F')
13 | hogf = features_pedro_py.process(imgf, sbin)
14 | return hogf
15 |
16 | def hog_picture(w, bs=20):
17 | """ Visualize positive HOG weights.
18 | ported to numpy from https://github.com/CSAILVision/ihog/blob/master/showHOG.m
19 | """
20 | if not imrotate_available:
21 | raise RuntimeError('This function requires scipy')
22 | bim1 = np.zeros((bs, bs))
23 | bim1[:,np.round(bs/2)-1:np.round(bs/2)] = 1
24 | bim = np.zeros((9,)+bim1.shape)
25 | for i in xrange(9):
26 | bim[i] = imrotate(bim1, -i*20)/255.0
27 | s = w.shape
28 | w = w.copy()
29 | w[w < 0] = 0
30 | im = np.zeros((bs*s[0], bs*s[1]))
31 | for i in xrange(s[0]):
32 | iis = slice( i*bs, (i+1)*bs )
33 | for j in xrange(s[1]):
34 | jjs = slice( j*bs, (j+1)*bs )
35 | for k in xrange(9):
36 | im[iis,jjs] += bim[k] * w[i,j,k+18]
37 | return im/np.max(w)
38 |
--------------------------------------------------------------------------------
/tools.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import os
3 | import shutil
4 | import matplotlib.pyplot as plt
5 | from matplotlib.patches import Rectangle, Polygon
6 | import numpy as np
7 | from mpl_toolkits.axes_grid1 import ImageGrid
8 | from importlib import import_module
9 | import vot
10 | from matplotlib import cm
11 | from numpy import linspace
12 |
13 | def Tracking(Sequence, tracker_list, visualize = True):
14 |
15 | if not os.path.exists('results/'):
16 | os.mkdir("results")
17 |
18 | print 'generate images.txt and region.txt files...'
19 | with open("images.txt","w") as f:
20 | while Sequence._frame < len(Sequence._images):
21 | f.write(Sequence.frame()+'\n')
22 | Sequence._frame+=1
23 | Sequence._frame = 0
24 | with open("region.txt", "w") as f:
25 | f.write(open(os.path.join(Sequence.seqdir, 'groundtruth.txt'), 'r').readline())
26 |
27 | print 'start tracking...'
28 |
29 | for str in tracker_list:
30 | print 'tracking using: '+str
31 | import_module(str)
32 |
33 | if not os.path.exists('results/'+str+'/'+Sequence.name):
34 | os.makedirs('results/'+str+'/'+Sequence.name)
35 | shutil.move("output.txt", 'results/'+str+'/'+Sequence.name+'/output.txt')
36 | os.remove("images.txt")
37 | os.remove("region.txt")
38 |
39 | print 'Done!!'
40 |
41 |
42 | if visualize:
43 | visulize_result(Sequence, tracker_list)
44 |
45 |
46 | def visulize_result(Sequence, tracker_list = None, visualize_gt = True):
47 | fig = plt.figure(1)
48 | if tracker_list:
49 | assert (type(tracker_list) == list)
50 | result = {}
51 | start = 0.0
52 | stop = 1.0
53 | number_of_lines = 1000
54 | cm_subsection = linspace(start, stop, number_of_lines)
55 |
56 | colors = [cm.jet(x) for x in cm_subsection]
57 | for str in tracker_list:
58 | result[str] = open('results/' + str + '/' + Sequence.name+'/output.txt').readlines()
59 | while Sequence._frame < len(Sequence._images):
60 | img_rgb = cv2.imread(Sequence.frame())
61 | plt.clf()
62 | gt_data = Sequence.groundtruth[Sequence._frame]
63 | if tracker_list == None:
64 | pass
65 |
66 | else:
67 | for str in tracker_list:
68 | tr_data = vot.convert_region(vot.parse_region(result[str][Sequence._frame]), Sequence._region_format)
69 | if Sequence._region_format == 'rectangle':
70 |
71 | tracking_figure_axes = plt.axes()
72 | tracking_figure_axes.add_patch(Rectangle(
73 | xy=(tr_data.x, tr_data.y),
74 | width=tr_data.width,
75 | height=tr_data.height,
76 | facecolor='none',
77 | edgecolor=colors[tracker_list.index(str)*number_of_lines / len(tracker_list)],
78 | ))
79 | tracking_figure_axes.text(100, 20*(tracker_list.index(str)+1), str,
80 | verticalalignment='bottom', horizontalalignment='right',
81 | color=colors[tracker_list.index(str)*number_of_lines / len(tracker_list)], fontsize=15)
82 |
83 | else:
84 | a = []
85 | for point in tr_data.points:
86 | a.append([point.x, point.y])
87 | tr_rect = Polygon(
88 | xy=np.array(a),
89 | facecolor='none',
90 | edgecolor=colors[tracker_list.index(str)*number_of_lines / len(tracker_list)],
91 | )
92 | tracking_figure_axes = plt.axes()
93 | tracking_figure_axes.add_patch(tr_rect)
94 |
95 |
96 | if visualize_gt:
97 | if Sequence._region_format == 'rectangle':
98 | gt_rect = Rectangle(
99 | xy=(gt_data.x, gt_data.y),
100 | width=gt_data.width,
101 | height=gt_data.height,
102 | facecolor='none',
103 | edgecolor='r',
104 | )
105 |
106 | tracking_figure_axes = plt.axes()
107 | tracking_figure_axes.add_patch(gt_rect)
108 |
109 | else:
110 | a = []
111 | for point in gt_data.points:
112 | a.append([point.x, point.y])
113 | gt_rect = Polygon(
114 | xy=np.array(a),
115 | facecolor='none',
116 | edgecolor='r',
117 | )
118 | tracking_figure_axes = plt.axes()
119 | tracking_figure_axes.add_patch(gt_rect)
120 |
121 | plt.imshow(img_rgb)
122 | plt.draw()
123 | plt.waitforbuttonpress()
124 | Sequence._frame += 1
125 |
126 | def precision_plot(Sequence, tracker_list):
127 | start = 0.0
128 | stop = 1.0
129 | number_of_lines = 1000
130 | cm_subsection = linspace(start, stop, number_of_lines)
131 |
132 | colors = [cm.jet(x) for x in cm_subsection]
133 | fig = plt.Figure()
134 | plt.xlabel('Threshold')
135 | plt.ylabel('Precision')
136 | plt.ylim(0, 1)
137 | max_threshold = 50
138 | gt = [[data.y + data.height / 2, data.x + data.width / 2] for data in Sequence.groundtruth]
139 | gt = np.array(gt)
140 | for str in tracker_list:
141 | precisions = np.zeros(shape = [max_threshold])
142 | result = np.loadtxt('results/' + str + '/' + Sequence.name + '/output.txt',delimiter=',')
143 | positions = result[:,[1,0]]+result[:,[3,2]]/2
144 | distance = np.sqrt(np.sum(np.power(positions-gt,2),1))
145 | for p in range(max_threshold):
146 | precisions[p] = float(np.count_nonzero(distance<(p+1)))/distance.shape[0]
147 | plt.plot(precisions,color =colors[tracker_list.index(str)*number_of_lines / len(tracker_list)], label =str)
148 | plt.legend()
149 | plt.show()
150 |
151 | def overlap_plot(Sequence, tracker_list):
152 | start = 0.0
153 | stop = 1.0
154 | number_of_lines = 1000
155 | cm_subsection = linspace(start, stop, number_of_lines)
156 |
157 | colors = [cm.jet(x) for x in cm_subsection]
158 | fig = plt.Figure()
159 | plt.xlabel('Threshold')
160 | plt.ylabel('Overlap')
161 | plt.ylim(0, 1)
162 | plt.xlim(0, 1)
163 | inter_p = 100
164 | gt = [[data.x, data.y, data.width, data.height] for data in Sequence.groundtruth]
165 | gt = np.array(gt)
166 | for str in tracker_list:
167 | Thresholds = np.arange(0,1,1.0/inter_p)+1.0/inter_p
168 | overlap_precision = np.zeros(shape=[inter_p])
169 |
170 | result = np.loadtxt('results/' + str + '/' + Sequence.name + '/output.txt', delimiter=',')
171 | endX = np.max(np.vstack((result[:,0]+result[:,2],gt[:,0]+gt[:,2])),axis=0)
172 | startX = np.min(np.vstack((result[:,0], gt[:,0])),axis=0)
173 | width = result[:,2]+gt[:,2]-(endX-startX)
174 | width[width < 0] = 0
175 |
176 | endY = np.max(np.vstack((result[:, 1] + result[:, 3], gt[:, 1] + gt[:, 3])), axis=0)
177 | startY = np.min(np.vstack((result[:, 1], gt[:, 1])), axis=0)
178 | height = result[:, 3] + gt[:, 3] - (endY - startY)
179 | height[height < 0] = 0
180 |
181 | Area = np.multiply(width,height)
182 | Area1 = np.multiply(result[:,2],result[:,3])
183 | Area2 = np.multiply(gt[:,2],gt[:,3])
184 | overlap_ratio = np.divide(Area,Area1+Area2-Area)
185 |
186 | for p in range(inter_p):
187 | overlap_precision[p] = float(np.count_nonzero(overlap_ratio > Thresholds[p])) / overlap_ratio.shape[0]
188 | plt.plot(overlap_precision, Thresholds, color=colors[tracker_list.index(str)*number_of_lines / len(tracker_list)], label=str)
189 | plt.legend()
190 | plt.show()
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 | def imshow_grid(images, shape=[3, 10]):
199 | """Plot images in a grid of a given shape."""
200 | fig = plt.figure(1)
201 | grid = ImageGrid(fig, 111, nrows_ncols=shape, axes_pad=0.05)
202 |
203 | size = shape[0] * shape[1]
204 | for i in range(size):
205 | grid[i].axis('off')
206 | grid[i].imshow(images[i]/np.max(images[i]),cmap=plt.cm.gray) # The AxesGrid object work as a list of axes.
207 |
208 | plt.show()
--------------------------------------------------------------------------------
/tutorials/Visualize_deep_features.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {
7 | "collapsed": true
8 | },
9 | "outputs": [],
10 | "source": [
11 | "# This notebook is used for visualizing and understanding deep feaures\n",
12 | "\n",
13 | "%matplotlib inline\n",
14 | "\n",
15 | "import matplotlib.pyplot as plt\n",
16 | "import numpy as np\n",
17 | "from matplotlib.patches import Rectangle\n",
18 | "import torch\n",
19 | "from torch.autograd import Variable\n",
20 | "import vgg\n",
21 | "\n",
22 | "import utils\n",
23 | "from scipy import misc,ndimage\n",
24 | "import tools"
25 | ]
26 | },
27 | {
28 | "cell_type": "code",
29 | "execution_count": 2,
30 | "metadata": {},
31 | "outputs": [
32 | {
33 | "data": {
34 | "text/plain": [
35 | ""
36 | ]
37 | },
38 | "execution_count": 2,
39 | "metadata": {},
40 | "output_type": "execute_result"
41 | },
42 | {
43 | "data": {
44 | "image/png": "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\n",
45 | "text/plain": [
46 | ""
47 | ]
48 | },
49 | "metadata": {},
50 | "output_type": "display_data"
51 | }
52 | ],
53 | "source": [
54 | "img = misc.imread('example.jpg')\n",
55 | "\n",
56 | "img_m = utils.get_subwindow(img,pos=[212.,212.],sz=np.array([100,100]))\n",
57 | "img_s = utils.get_subwindow(img,pos=[212.,212.],sz=np.array([100,100]),\n",
58 | " scale_factor=0.9)\n",
59 | "img_l = utils.get_subwindow(img,pos=[212.,212.],sz=np.array([100,100]),\n",
60 | " scale_factor=1.1)\n",
61 | "plt.subplot(131)\n",
62 | "plt.imshow(img_m)\n",
63 | "plt.subplot(132)\n",
64 | "plt.imshow(img_s)\n",
65 | "plt.subplot(133)\n",
66 | "plt.imshow(img_l)"
67 | ]
68 | },
69 | {
70 | "cell_type": "code",
71 | "execution_count": 4,
72 | "metadata": {},
73 | "outputs": [
74 | {
75 | "data": {
76 | "image/png": "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\n",
77 | "text/plain": [
78 | ""
79 | ]
80 | },
81 | "metadata": {},
82 | "output_type": "display_data"
83 | }
84 | ],
85 | "source": [
86 | "# network init\n",
87 | "\n",
88 | "model = vgg.VGG_19(outputlayer=[3])\n",
89 | "\n",
90 | "# load partial weights\n",
91 | "model_dict = model.state_dict()\n",
92 | "params = torch.load('vgg19.pth')\n",
93 | "load_dict = {k:v for k,v in params.items() if 'features' in k}\n",
94 | "model_dict.update(load_dict)\n",
95 | "model.load_state_dict(model_dict)\n",
96 | "\n",
97 | "# extract features\n",
98 | "\n",
99 | "imgMean = np.array([0.485, 0.456, 0.406], np.float)\n",
100 | "imgStd = np.array([0.229,0.224,0.225])\n",
101 | "img_m = misc.imresize(img_m,(224,224))/255.\n",
102 | "img_m = (img_m-imgMean)/imgStd\n",
103 | "img_m = np.transpose(img_m, (2,0,1))\n",
104 | "feature2 = model(Variable(torch.from_numpy(img_m[None,:,:,:]).float()))\n",
105 | "feature = feature2[0].data[0].numpy()\n",
106 | "x = ndimage.zoom(feature, (1, float(100)/feature.shape[1],\n",
107 | " float(100)/feature.shape[2]), order=1)\n",
108 | "tools.imshow_grid(x,shape=[8,8])"
109 | ]
110 | },
111 | {
112 | "cell_type": "code",
113 | "execution_count": null,
114 | "metadata": {},
115 | "outputs": [],
116 | "source": [
117 | ""
118 | ]
119 | }
120 | ],
121 | "metadata": {
122 | "kernelspec": {
123 | "display_name": "Python 2",
124 | "language": "python",
125 | "name": "python2"
126 | },
127 | "language_info": {
128 | "codemirror_mode": {
129 | "name": "ipython",
130 | "version": 2.0
131 | },
132 | "file_extension": ".py",
133 | "mimetype": "text/x-python",
134 | "name": "python",
135 | "nbconvert_exporter": "python",
136 | "pygments_lexer": "ipython2",
137 | "version": "2.7.6"
138 | }
139 | },
140 | "nbformat": 4,
141 | "nbformat_minor": 0
142 | }
--------------------------------------------------------------------------------
/tutorials/img_ScaleChange/0001.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtddggg/Visual_Tracking_api/d5cf7934861950ca1eedede198382fc468dab941/tutorials/img_ScaleChange/0001.jpg
--------------------------------------------------------------------------------
/tutorials/img_ScaleChange/0002.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtddggg/Visual_Tracking_api/d5cf7934861950ca1eedede198382fc468dab941/tutorials/img_ScaleChange/0002.jpg
--------------------------------------------------------------------------------
/tutorials/img_ScaleChange/0003.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtddggg/Visual_Tracking_api/d5cf7934861950ca1eedede198382fc468dab941/tutorials/img_ScaleChange/0003.jpg
--------------------------------------------------------------------------------
/tutorials/img_ScaleChange/0004.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtddggg/Visual_Tracking_api/d5cf7934861950ca1eedede198382fc468dab941/tutorials/img_ScaleChange/0004.jpg
--------------------------------------------------------------------------------
/tutorials/img_ScaleChange/groundtruth.txt:
--------------------------------------------------------------------------------
1 | 130,132,31,115
2 | 123,119,32,105
3 | 117,109,35,99
4 | 118,100,27,95
5 |
--------------------------------------------------------------------------------
/tutorials/img_common/0001.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtddggg/Visual_Tracking_api/d5cf7934861950ca1eedede198382fc468dab941/tutorials/img_common/0001.jpg
--------------------------------------------------------------------------------
/tutorials/img_common/0002.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vtddggg/Visual_Tracking_api/d5cf7934861950ca1eedede198382fc468dab941/tutorials/img_common/0002.jpg
--------------------------------------------------------------------------------
/tutorials/img_common/groundtruth.txt:
--------------------------------------------------------------------------------
1 | 478,143,80,111
2 | 457,121,83,116
3 |
--------------------------------------------------------------------------------
/utils.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from scipy import misc
3 | from skimage import transform
4 |
5 | def get_window_size(target_sz, im_sz, padding):
6 |
7 | if (target_sz[0] / target_sz[1] > 2):
8 | # For objects with large height, we restrict the search window with padding.height
9 | window_sz = np.floor(np.multiply(target_sz, [1 + padding.height, 1 + padding.generic]))
10 |
11 | elif np.prod(target_sz)/np.prod(im_sz) > 0.05:
12 | # For objects with large height and width and accounting for at least 10 percent of the whole image,
13 | # we only search 2xheight and width
14 | window_sz = np.floor(target_sz * (1 + padding.large))
15 |
16 | else:
17 | window_sz = np.floor(target_sz * (1 + padding.generic))
18 |
19 | return window_sz
20 |
21 |
22 |
23 |
24 | def get_subwindow(im, pos, sz, scale_factor = None, feature='raw'):
25 | """
26 | Obtain sub-window from image, with replication-padding.
27 | Returns sub-window of image IM centered at POS ([y, x] coordinates),
28 | with size SZ ([height, width]). If any pixels are outside of the image,
29 | they will replicate the values at the borders.
30 |
31 | The subwindow is also normalized to range -0.5 .. 0.5, and the given
32 | cosine window COS_WINDOW is applied
33 | (though this part could be omitted to make the function more general).
34 | """
35 |
36 | if np.isscalar(sz): # square sub-window
37 | sz = [sz, sz]
38 |
39 | sz_ori = sz
40 |
41 | if scale_factor != None:
42 | sz = np.floor(sz*scale_factor)
43 |
44 | ys = np.floor(pos[0]) + np.arange(sz[0], dtype=int) - np.floor(sz[0] / 2)
45 | xs = np.floor(pos[1]) + np.arange(sz[1], dtype=int) - np.floor(sz[1] / 2)
46 |
47 | ys = ys.astype(int)
48 | xs = xs.astype(int)
49 |
50 | # check for out-of-bounds coordinates and set them to the values at the borders
51 | ys[ys < 0] = 0
52 | ys[ys >= im.shape[0]] = im.shape[0] - 1
53 |
54 | xs[xs < 0] = 0
55 | xs[xs >= im.shape[1]] = im.shape[1] - 1
56 |
57 | out = im[np.ix_(ys, xs)]
58 | if scale_factor != None:
59 | out = misc.imresize(out, sz_ori.astype(int))
60 |
61 |
62 | if feature == 'hog':
63 | from pyhog import pyhog
64 | hog_feature = pyhog.features_pedro(out / 255., 1)
65 | out = np.lib.pad(hog_feature, ((1, 1), (1, 1), (0, 0)), 'edge')
66 |
67 | return out
68 |
69 | def merge_features(features):
70 | num, h, w = features.shape
71 | row = int(np.sqrt(num))
72 | merged = np.zeros([row * h, row * w])
73 |
74 | for idx, s in enumerate(features):
75 | i = idx // row
76 | j = idx % row
77 | merged[i * h:(i + 1) * h, j * w:(j + 1) * w] = s
78 |
79 |
80 | return merged
81 |
82 | def dense_gauss_kernel(sigma, xf, x, zf=None, z=None):
83 | """
84 | Gaussian Kernel with dense sampling.
85 | Evaluates a gaussian kernel with bandwidth SIGMA for all displacements
86 | between input images X and Y, which must both be MxN. They must also
87 | be periodic (ie., pre-processed with a cosine window). The result is
88 | an MxN map of responses.
89 |
90 | If X and Y are the same, ommit the third parameter to re-use some
91 | values, which is faster.
92 | :param sigma: feature bandwidth sigma
93 | :param x:
94 | :param y: if y is None, then we calculate the auto-correlation
95 | :return:
96 | """
97 | N = xf.shape[0] * xf.shape[1]
98 | xx = np.dot(x.flatten().transpose(), x.flatten()) # squared norm of x
99 |
100 | if zf is None:
101 | # auto-correlation of x
102 | zf = xf
103 | zz = xx
104 | else:
105 | zz = np.dot(z.flatten().transpose(), z.flatten()) # squared norm of y
106 |
107 | xyf = np.multiply(zf, np.conj(xf))
108 | if len(xyf.shape) == 3:
109 | xyf_ifft = np.fft.ifft2(np.sum(xyf, axis=2))
110 | elif len(xyf.shape) == 2:
111 | xyf_ifft = np.fft.ifft2(xyf)
112 | # elif len(xyf.shape) == 4:
113 | # xyf_ifft = np.fft.ifft2(np.sum(xyf, axis=3))
114 |
115 | #row_shift, col_shift = np.floor(np.array(xyf_ifft.shape) / 2).astype(int)
116 | #xy_complex = np.roll(xyf_ifft, row_shift, axis=0)
117 | #xy_complex = np.roll(xy_complex, col_shift, axis=1)
118 | c = np.real(xyf_ifft)
119 | d = np.real(xx) + np.real(zz) - 2 * c
120 | k = np.exp(-1. / sigma ** 2 * np.abs(d) / N)
121 |
122 | return k
123 |
124 | def get_scale_subwindow(im,pos,base_target_size, scaleFactors,
125 | scale_window, scale_model_sz):
126 | from pyhog import pyhog
127 | nScales = len(scaleFactors)
128 | out = []
129 | for i in range(nScales):
130 | patch_sz = np.floor(base_target_size * scaleFactors[i])
131 | scale_patch = get_subwindow(im, pos, patch_sz)
132 | im_patch_resized = transform.resize(scale_patch, scale_model_sz,mode='reflect')
133 | temp_hog = pyhog.features_pedro(im_patch_resized, 4)
134 | out.append(np.multiply(temp_hog.flatten(), scale_window[i]))
135 |
136 | return np.asarray(out)
--------------------------------------------------------------------------------
/vgg.py:
--------------------------------------------------------------------------------
1 | from torch import nn
2 |
3 | cfg = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M']
4 | class VGG_19(nn.Module):
5 | def __init__(self, outputlayer=[26]):
6 | assert (type(outputlayer)==list)
7 | super(VGG_19, self).__init__()
8 | layers = []
9 | in_channels = 3
10 | self.outputlayer = outputlayer
11 | for v in cfg:
12 | if v == 'M':
13 |
14 | layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
15 | else:
16 | conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
17 | layers += [conv2d, nn.ReLU(inplace=True)]
18 | in_channels = v
19 |
20 | self.features = nn.Sequential(*layers)
21 |
22 |
23 | def forward(self, x):
24 | output = []
25 | for module in self.features._modules.values():
26 | x = module(x)
27 |
28 | if self.features._modules.values().index(module) in self.outputlayer:
29 | output.append(x)
30 |
31 | return output
--------------------------------------------------------------------------------
/vot.py:
--------------------------------------------------------------------------------
1 | """
2 | \file vot.py
3 |
4 | @brief Python utility functions for VOT integration
5 |
6 | @author Luka Cehovin, Alessio Dore
7 |
8 | @date 2016
9 |
10 | """
11 |
12 | import sys
13 | import copy
14 | import collections
15 |
16 | try:
17 | import trax
18 | import trax.server
19 | TRAX = True
20 | except ImportError:
21 | TRAX = False
22 |
23 | Rectangle = collections.namedtuple('Rectangle', ['x', 'y', 'width', 'height'])
24 | Point = collections.namedtuple('Point', ['x', 'y'])
25 | Polygon = collections.namedtuple('Polygon', ['points'])
26 |
27 | def parse_region(string):
28 | tokens = map(float, string.split(','))
29 | if len(tokens) == 4:
30 | return Rectangle(tokens[0], tokens[1], tokens[2], tokens[3])
31 | elif len(tokens) % 2 == 0 and len(tokens) > 4:
32 | return Polygon([Point(tokens[i],tokens[i+1]) for i in xrange(0,len(tokens),2)])
33 | return None
34 |
35 | def encode_region(region):
36 | if isinstance(region, Polygon):
37 | return ','.join(['{},{}'.format(p.x,p.y) for p in region.points])
38 | elif isinstance(region, Rectangle):
39 | return '{},{},{},{}'.format(region.x, region.y, region.width, region.height)
40 | else:
41 | return ""
42 |
43 | def convert_region(region, to):
44 |
45 | if to == 'rectangle':
46 |
47 | if isinstance(region, Rectangle):
48 | return copy.copy(region)
49 | elif isinstance(region, Polygon):
50 | top = sys.float_info.max
51 | bottom = sys.float_info.min
52 | left = sys.float_info.max
53 | right = sys.float_info.min
54 |
55 | for point in region.points:
56 | top = min(top, point.y)
57 | bottom = max(bottom, point.y)
58 | left = min(left, point.x)
59 | right = max(right, point.x)
60 |
61 | return Rectangle(left, top, right - left, bottom - top)
62 |
63 | else:
64 | return None
65 | if to == 'polygon':
66 |
67 | if isinstance(region, Rectangle):
68 | points = []
69 | points.append((region.x, region.y))
70 | points.append((region.x + region.width, region.y))
71 | points.append((region.x + region.width, region.y + region.height))
72 | points.append((region.x, region.y + region.height))
73 | return Polygon(points)
74 |
75 | elif isinstance(region, Polygon):
76 | return copy.copy(region)
77 | else:
78 | return None
79 |
80 | return None
81 |
82 | class VOT(object):
83 | """ Base class for Python VOT integration """
84 | def __init__(self, region_format):
85 | """ Constructor
86 |
87 | Args:
88 | region_format: Region format options
89 | """
90 | assert(region_format in ['rectangle', 'polygon'])
91 | if TRAX:
92 | options = trax.server.ServerOptions(region_format, trax.image.PATH)
93 | self._trax = trax.server.Server(options)
94 |
95 | request = self._trax.wait()
96 | assert(request.type == 'initialize')
97 | if request.region.type == 'polygon':
98 | self._region = Polygon([Point(x[0], x[1]) for x in request.region.points])
99 | else:
100 | self._region = Rectangle(request.region.x, request.region.y, request.region.width, request.region.height)
101 | self._image = str(request.image)
102 | self._trax.status(request.region)
103 | else:
104 | self._files = [x.strip('\n') for x in open('images.txt', 'r').readlines()]
105 | self._frame = 0
106 | self._region = convert_region(parse_region(open('region.txt', 'r').readline()), region_format)
107 | self._result = []
108 |
109 | def region(self):
110 | """
111 | Send configuration message to the client and receive the initialization
112 | region and the path of the first image
113 |
114 | Returns:
115 | initialization region
116 | """
117 |
118 | return self._region
119 |
120 | def report(self, region):
121 | """
122 | Report the tracking results to the client
123 |
124 | Arguments:
125 | region: region for the frame
126 | """
127 | assert(isinstance(region, Rectangle) or isinstance(region, Polygon))
128 | if TRAX:
129 | if isinstance(region, Polygon):
130 | tregion = trax.region.Polygon([(x.x, x.y) for x in region.points])
131 | else:
132 | tregion = trax.region.Rectangle(region.x, region.y, region.width, region.height)
133 | self._trax.status(tregion)
134 | else:
135 | self._result.append(region)
136 | self._frame += 1
137 |
138 | def frame(self):
139 | """
140 | Get a frame (image path) from client
141 |
142 | Returns:
143 | absolute path of the image
144 | """
145 | if TRAX:
146 | if hasattr(self, "_image"):
147 | image = str(self._image)
148 | del self._image
149 | return image
150 |
151 | request = self._trax.wait()
152 |
153 | if request.type == 'frame':
154 | return str(request.image)
155 | else:
156 | return None
157 |
158 | else:
159 | if self._frame >= len(self._files):
160 | return None
161 | return self._files[self._frame]
162 |
163 | def quit(self):
164 | if TRAX:
165 | self._trax.quit()
166 | elif hasattr(self, '_result'):
167 | with open('output.txt', 'w') as f:
168 | for r in self._result:
169 | f.write(encode_region(r))
170 | f.write('\n')
171 |
172 |
173 |
--------------------------------------------------------------------------------
/vot_demo_tracker.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import sys
4 |
5 | from scipy import misc
6 |
7 | import vot
8 |
9 |
10 | class Demo_Tracker(object):
11 |
12 | def __init__(self, image, region):
13 |
14 | print 'type of the image:',type(image)
15 | print 'shape of the image:',image.shape
16 | print 'image content:'
17 | print image
18 | self.window = max(region.width, region.height) * 2
19 |
20 | self.template = None
21 | self.position = (region.x + region.width / 2, region.y + region.height / 2)
22 | self.size = (region.width, region.height)
23 |
24 | def track(self, image):
25 |
26 | return vot.Rectangle(self.position[0] - self.size[0] / 2, self.position[1] - self.size[1] / 2, self.size[0], self.size[1])
27 |
28 |
29 | handle = vot.VOT("rectangle")
30 | selection = handle.region()
31 |
32 | imagefile = handle.frame()
33 | if not imagefile:
34 | sys.exit(0)
35 | image = misc.imread(imagefile)
36 | #image = cv2.imread(imagefile)
37 | #image = io.imread(imagefile)
38 | tracker = Demo_Tracker(image, selection)
39 | while True:
40 | imagefile = handle.frame()
41 | if not imagefile:
42 | break
43 | image = misc.imread(imagefile)
44 | # image = cv2.imread(imagefile)
45 | # image = io.imread(imagefile)
46 | region = tracker.track(image)
47 | handle.report(region)
48 |
49 |
--------------------------------------------------------------------------------