#include <cstdlib>
#include <opencv2/opencv.hpp>
#include <cassert>
+#include <numeric>
#if defined(CUFFT) || defined(CUFFTW)
#include "cuda_runtime.h"
{
assert((type & CV_MAT_DEPTH_MASK) == CV_32F);
}
- MatDynMem(std::array<int, 3> size, int type)
- : DynMem(size[0] * size[1] * size[2]), cv::Mat(3, (int*)&size, type, hostMem())
- {}
+ MatDynMem(std::vector<int> size, int type)
+ : DynMem(std::accumulate(size.begin(), size.end(), 1, std::multiplies<int>()))
+ , cv::Mat(size.size(), size.data(), type, hostMem()) {}
MatDynMem(MatDynMem &&other) = default;
MatDynMem(const cv::Mat &other)
: DynMem(other.total()) , cv::Mat(other) {}
static_cast<cv::Mat>(*this) = expr;
}
- cv::Mat plane(uint i) {
- assert(dims == 3);
- assert(int(i) < size[0]);
- return cv::Mat(size[1], size[2], cv::Mat::type(), ptr(i));
- }
private:
static int volume(int ndims, const int *sizes)
{
using cv::Mat::create;
};
+class Mat3d : public MatDynMem
+{
+public:
+ Mat3d(uint dim0, cv::Size size) : MatDynMem({{int(dim0), size.height, size.width}}, CV_32F) {}
+
+ cv::Mat plane(uint idx) {
+ assert(dims == 3);
+ assert(int(idx) < size[0]);
+ return cv::Mat(size[1], size[2], cv::Mat::type(), ptr(idx));
+ }
+};
+
+class MatFeats : public Mat3d
+{
+public:
+ MatFeats(uint num_features, cv::Size size) : Mat3d(num_features, size) {}
+};
+class MatScales : public Mat3d
+{
+public:
+ MatScales(uint num_scales, cv::Size size) : Mat3d(num_scales, size) {}
+};
+
+class MatScaleFeats : public MatDynMem
+{
+public:
+ MatScaleFeats(uint num_scales, uint num_features, cv::Size size)
+ : MatDynMem({{int(num_scales), int(num_features), size.height, size.width}}, CV_32F) {}
+
+ cv::Mat plane(uint scale, uint feature) {
+ assert(dims == 4);
+ assert(int(scale) < size[0]);
+ assert(int(feature) < size[1]);
+ return cv::Mat(size[2], size[3], cv::Mat::type(), ptr(scale, feature));
+ }
+};
+
#endif // DYNMEM_HPP
(void)window;
}
-void Fft::forward(const MatDynMem &real_input, ComplexMat &complex_result)
+void Fft::forward(const MatScales &real_input, ComplexMat &complex_result)
{
- assert(real_input.dims == 2);
- assert(real_input.size().width == int(m_width));
- assert(real_input.size().height == int(m_height));
+ assert(real_input.dims == 3);
+ assert(real_input.size[0] == IF_BIG_BATCH(int(m_num_of_scales), 1));
+ assert(real_input.size[1] == int(m_height));
+ assert(real_input.size[2] == int(m_width));
+
(void)real_input;
(void)complex_result;
}
-void Fft::forward_window(MatDynMem &patch_feats, ComplexMat &complex_result, MatDynMem &tmp)
+void Fft::forward_window(MatFeats &patch_feats, ComplexMat &complex_result, MatFeats &tmp)
{
assert(patch_feats.dims == 3);
-#ifndef BIG_BATCH
assert(patch_feats.size[0] == int(m_num_of_feats));
-#else
- assert(patch_feats.size[0] == int(m_num_of_feats * m_num_of_scales));
-#endif
assert(patch_feats.size[1] == int(m_height));
assert(patch_feats.size[2] == int(m_width));
+ (void)tmp;
+ (void)complex_result;
+ (void)patch_feats;
+}
+
+void Fft::forward_window(MatScaleFeats &patch_feats, ComplexMat &complex_result, MatScaleFeats &tmp)
+{
+ assert(patch_feats.dims == 4);
+ assert(patch_feats.size[0] == IF_BIG_BATCH(int(m_num_of_scales), 1));
+ assert(patch_feats.size[1] == int(m_num_of_feats));
+ assert(patch_feats.size[2] == int(m_height));
+ assert(patch_feats.size[3] == int(m_width));
+
assert(tmp.dims == patch_feats.dims);
assert(tmp.size[0] == patch_feats.size[0]);
assert(tmp.size[1] == patch_feats.size[1]);
assert(tmp.size[2] == patch_feats.size[2]);
+ assert(tmp.size[3] == patch_feats.size[3]);
(void)patch_feats;
(void)complex_result;
void Fft::inverse(ComplexMat &complex_input, MatDynMem &real_result)
{
- assert(real_result.dims == 3);
-#ifndef BIG_BATCH
- assert(real_result.size[0] == int(m_num_of_feats));
-#else
- assert(real_result.size[0] == int(m_num_of_feats * m_num_of_scales));
-#endif
- assert(real_result.size[1] == int(m_height));
- assert(real_result.size[2] == int(m_width));
+ assert(real_result.dims == 4);
+ assert(real_result.size[0] == IF_BIG_BATCH(int(m_num_of_scales), 1));
+ assert(real_result.size[1] == int(m_num_of_feats));
+ assert(real_result.size[2] == int(m_height));
+ assert(real_result.size[3] == int(m_width));
(void)complex_input;
(void)real_result;
public:
virtual void init(unsigned width, unsigned height, unsigned num_of_feats, unsigned num_of_scales);
virtual void set_window(const MatDynMem &window);
- virtual void forward(const MatDynMem &real_input, ComplexMat &complex_result);
- virtual void forward_window(MatDynMem &patch_feats_in, ComplexMat &complex_result, MatDynMem &tmp);
+ virtual void forward(const MatScales &real_input, ComplexMat &complex_result);
+ virtual void forward_window(MatFeats &patch_feats_in, ComplexMat &complex_result, MatFeats &tmp);
+ virtual void forward_window(MatScaleFeats &patch_feats_in, ComplexMat &complex_result, MatScaleFeats &tmp);
virtual void inverse(ComplexMat &complex_input, MatDynMem &real_result);
virtual ~Fft() = 0;
m_window = window;
}
-void cuFFT::forward(const MatDynMem &real_input, ComplexMat &complex_result)
+void cuFFT::forward(const MatScales &real_input, ComplexMat &complex_result)
{
Fft::forward(real_input, complex_result);
- auto in = static_cast<cufftReal *>(const_cast<MatDynMem&>(real_input).deviceMem());
+ auto in = static_cast<cufftReal *>(const_cast<MatScales&>(real_input).deviceMem());
cudaErrorCheck(cufftExecR2C(plan_f, in, complex_result.get_p_data()));
}
-void cuFFT::forward_window(MatDynMem &feat, ComplexMat &complex_result, MatDynMem &temp)
+void cuFFT::forward_window(MatScaleFeats &feat, ComplexMat &complex_result, MatScaleFeats &temp)
{
Fft::forward_window(feat, complex_result, temp);
cufftReal *temp_data = temp.deviceMem();
for (uint i = 0; i < n_channels; ++i) {
- cv::Mat feat_plane = feat.plane(i);
- cv::Mat temp_plane = temp.plane(i);
- temp_plane = feat_plane.mul(m_window);
+ for (uint j = 0; j < uint(feat.size[1]); ++j) {
+ cv::Mat feat_plane = feat.plane(i, j);
+ cv::Mat temp_plane = temp.plane(i, j);
+ temp_plane = feat_plane.mul(m_window);
+ }
}
cudaErrorCheck(cufftExecR2C(plan_fw, temp_data, complex_result.get_p_data()));
}
cuFFT();
void init(unsigned width, unsigned height, unsigned num_of_feats, unsigned num_of_scales) override;
void set_window(const MatDynMem &window) override;
- void forward(const MatDynMem &real_input, ComplexMat &complex_result) override;
- void forward_window(MatDynMem &patch_feats_in, ComplexMat &complex_result, MatDynMem &tmp) override;
+ void forward(const MatScales &real_input, ComplexMat &complex_result) override;
+ void forward_window(MatScaleFeats &patch_feats_in, ComplexMat &complex_result, MatScaleFeats &tmp) override;
void inverse(ComplexMat &complex_input, MatDynMem &real_result) override;
~cuFFT() override;
m_window = window;
}
-void Fftw::forward(const MatDynMem &real_input, ComplexMat &complex_result)
+void Fftw::forward(const MatScales &real_input, ComplexMat &complex_result)
{
Fft::forward(real_input, complex_result);
return;
}
-void Fftw::forward_window(MatDynMem &feat, ComplexMat & complex_result, MatDynMem &temp)
+void Fftw::forward_window(MatScaleFeats &feat, ComplexMat & complex_result, MatScaleFeats &temp)
{
Fft::forward_window(feat, complex_result, temp);
- int n_channels = feat.size[0];
- for (int i = 0; i < n_channels; ++i) {
- cv::Mat feat_plane = feat.plane(i);
- cv::Mat temp_plane = temp.plane(i);
- temp_plane = feat_plane.mul(m_window);
+ uint n_channels = feat.size[0];
+ for (uint i = 0; i < n_channels; ++i) {
+ for (uint j = 0; j < uint(feat.size[1]); ++j) {
+ cv::Mat feat_plane = feat.plane(i, j);
+ cv::Mat temp_plane = temp.plane(i, j);
+ temp_plane = feat_plane.mul(m_window);
+ }
}
float *in = temp.ptr<float>();
fftwf_complex *out = reinterpret_cast<fftwf_complex *>(complex_result.get_p_data());
- if (n_channels <= int(m_num_of_feats))
+ if (n_channels <= m_num_of_feats)
fftwf_execute_dft_r2c(plan_fw, in, out);
else
fftwf_execute_dft_r2c(plan_fw_all_scales, in, out);
Fftw();
void init(unsigned width, unsigned height, unsigned num_of_feats, unsigned num_of_scales) override;
void set_window(const MatDynMem &window) override;
- void forward(const MatDynMem &real_input, ComplexMat &complex_result) override;
- void forward_window(MatDynMem &patch_feats_in, ComplexMat &complex_result, MatDynMem &tmp) override;
+ void forward(const MatScales &real_input, ComplexMat &complex_result) override;
+ void forward_window(MatScaleFeats &patch_feats_in, ComplexMat &complex_result, MatScaleFeats &tmp) override;
void inverse(ComplexMat &complex_input, MatDynMem &real_result) override;
~Fftw() override;
private:
m_window = window;
}
-void FftOpencv::forward(const MatDynMem &real_input, ComplexMat &complex_result)
+void FftOpencv::forward(const MatScales &real_input, ComplexMat &complex_result)
{
Fft::forward(real_input, complex_result);
complex_result = ComplexMat(tmp);
}
-void FftOpencv::forward_window(MatDynMem &feat, ComplexMat &complex_result, MatDynMem &temp)
+void FftOpencv::forward_window(MatScaleFeats &feat, ComplexMat &complex_result, MatScaleFeats &temp)
{
Fft::forward_window(feat, complex_result, temp);
uint n_channels = feat.size[0];
for (uint i = 0; i < n_channels; ++i) {
- cv::Mat complex_res;
- cv::Mat channel = feat.plane(i);
- cv::dft(channel.mul(m_window), complex_res, cv::DFT_COMPLEX_OUTPUT);
- complex_result.set_channel(int(i), complex_res);
+ for (uint j = 0; j < uint(feat.size[1]); ++j) {
+ cv::Mat complex_res;
+ cv::Mat channel = feat.plane(i, j);
+ cv::dft(channel.mul(m_window), complex_res, cv::DFT_COMPLEX_OUTPUT);
+ complex_result.set_channel(int(i), complex_res);
+ }
}
}
public:
void init(unsigned width, unsigned height, unsigned num_of_feats, unsigned num_of_scales) override;
void set_window(const MatDynMem &window) override;
- void forward(const MatDynMem &real_input, ComplexMat &complex_result) override;
- void forward_window(MatDynMem &patch_feats_in, ComplexMat &complex_result, MatDynMem &tmp) override;
+ void forward(const MatScales &real_input, ComplexMat &complex_result) override;
+ void forward_window(MatScaleFeats &patch_feats_in, ComplexMat &complex_result, MatScaleFeats &tmp) override;
void inverse(ComplexMat &complex_input, MatDynMem &real_result) override;
~FftOpencv() override;
private:
#define DEBUG_PRINTM(obj) \
if (kcf_debug) { \
std::cout << #obj << " @" << __LINE__ << " " << (obj).size() << " CH: " << (obj).channels() << std::endl \
- << (obj) << std::endl; \
+ /*<< (obj)*/ << std::endl; \
}
template <typename T>
void KCF_Tracker::train(cv::Mat input_gray, cv::Mat input_rgb, double interp_factor)
{
// obtain a sub-window for training
- int sizes[3] = {p_num_of_feats, p_roi.height, p_roi.width};
- MatDynMem patch_feats(3, sizes, CV_32FC1);
- MatDynMem temp(3, sizes, CV_32FC1);
+ // TODO: Move Mats outside from here
+ MatFeats patch_feats(p_num_of_feats, p_roi);
+ MatFeats temp(p_num_of_feats, p_roi);
get_features(patch_feats, input_rgb, input_gray, p_pose.cx, p_pose.cy,
p_windows_size.width, p_windows_size.height,
p_current_scale);
#ifndef BIG_BATCH
for (auto scale: p_scales)
- d.threadctxs.emplace_back(p_roi, p_num_of_feats, 1, scale);
+ d.threadctxs.emplace_back(p_roi, p_num_of_feats, scale);
#else
- d.threadctxs.emplace_back(p_roi, p_num_of_feats * p_num_scales, p_num_scales);
+ d.threadctxs.emplace_back(p_roi, p_num_of_feats, p_num_scales);
#endif
- gaussian_correlation.reset(new GaussianCorrelation(p_roi, IF_BIG_BATCH(p_num_scales, 1),
- p_num_of_feats * IF_BIG_BATCH(p_num_scales, 1)));
+ gaussian_correlation.reset(
+ new GaussianCorrelation(IF_BIG_BATCH(p_num_scales, 1),
+ p_num_of_feats, p_roi));
p_current_scale = 1.;
fft.set_window(MatDynMem(cosine_window_function(p_roi.width, p_roi.height)));
// window weights, i.e. labels
- fft.forward(gaussian_shaped_labels(p_output_sigma, p_roi.width, p_roi.height), p_yf);
+ MatScales gsl(1, p_roi);
+ gaussian_shaped_labels(p_output_sigma, p_roi.width, p_roi.height).copyTo(gsl.plane(0));
+ fft.forward(gsl, p_yf);
DEBUG_PRINTM(p_yf);
// train initial model
void ThreadCtx::track(const KCF_Tracker &kcf, cv::Mat &input_rgb, cv::Mat &input_gray)
{
// TODO: Move matrices to thread ctx
- int sizes[3] = {kcf.p_num_of_feats, kcf.p_windows_size.height, kcf.p_windows_size.width};
- MatDynMem patch_feats(3, sizes, CV_32FC1);
- MatDynMem temp(3, sizes, CV_32FC1);
+ MatFeats patch_feats(kcf.p_num_of_feats, kcf.p_roi);
+ MatFeats temp(kcf.p_num_of_feats, kcf.p_roi);
#ifdef BIG_BATCH
BIG_BATCH_OMP_PARALLEL_FOR
// ****************************************************************************
-void KCF_Tracker::get_features(MatDynMem &result_3d, cv::Mat &input_rgb, cv::Mat &input_gray, int cx, int cy,
+void KCF_Tracker::get_features(MatFeats &result, cv::Mat &input_rgb, cv::Mat &input_gray, int cx, int cy,
int size_x, int size_y, double scale) const
{
- assert(result_3d.size[0] == p_num_of_feats);
- assert(result_3d.size[1] == size_y / p_cell_size);
- assert(result_3d.size[2] == size_x / p_cell_size);
+ assert(result.size[0] == p_num_of_feats);
+ assert(result.size[1] == size_y / p_cell_size);
+ assert(result.size[2] == size_x / p_cell_size);
int size_x_scaled = floor(size_x * scale);
int size_y_scaled = floor(size_y * scale);
hog_feat.insert(hog_feat.end(), color_feat.begin(), color_feat.end());
- for (uint i = 0; i < hog_feat.size(); ++i) {
- cv::Mat result_plane(result_3d.dims - 1, result_3d.size + 1, result_3d.cv::Mat::type(), result_3d.ptr<void>(i));
- hog_feat[i].copyTo(result_plane);
- }
+ for (uint i = 0; i < hog_feat.size(); ++i)
+ hog_feat[i].copyTo(result.plane(i));
}
-MatDynMem KCF_Tracker::gaussian_shaped_labels(double sigma, int dim1, int dim2)
+cv::Mat KCF_Tracker::gaussian_shaped_labels(double sigma, int dim1, int dim2)
{
- MatDynMem labels(dim2, dim1, CV_32FC1);
+ cv::Mat labels(dim2, dim1, CV_32FC1);
int range_y[2] = {-dim2 / 2, dim2 - dim2 / 2};
int range_x[2] = {-dim1 / 2, dim1 - dim1 / 2};
return rot_labels;
}
-MatDynMem KCF_Tracker::circshift(const cv::Mat &patch, int x_rot, int y_rot)
+cv::Mat KCF_Tracker::circshift(const cv::Mat &patch, int x_rot, int y_rot)
{
- MatDynMem rot_patch(patch.size(), CV_32FC1);
+ cv::Mat rot_patch(patch.size(), CV_32FC1);
cv::Mat tmp_x_rot(patch.size(), CV_32FC1);
// circular rotate x-axis
class GaussianCorrelation {
public:
- GaussianCorrelation(cv::Size size, uint num_scales, uint num_feats)
+ GaussianCorrelation(uint num_scales, uint num_feats, cv::Size size)
: xf_sqr_norm(num_scales)
, xyf(Fft::freq_size(size), num_scales)
- , ifft_res({{int(num_feats * num_scales), size.height, size.width}}, CV_32F)
- , k({{int(num_scales), size.height, size.width}}, CV_32F)
+ , ifft_res(num_scales, num_feats, size)
+ , k(num_scales, size)
{}
void operator()(const KCF_Tracker &kcf, ComplexMat &result, const ComplexMat &xf, const ComplexMat &yf, double sigma, bool auto_correlation = false);
DynMem xf_sqr_norm;
DynMem yf_sqr_norm{1};
ComplexMat xyf;
- MatDynMem ifft_res;
- MatDynMem k;
+ MatScaleFeats ifft_res;
+ MatScales k;
};
//helping functions
void scale_track(ThreadCtx &vars, cv::Mat &input_rgb, cv::Mat &input_gray);
cv::Mat get_subwindow(const cv::Mat &input, int cx, int cy, int size_x, int size_y) const;
- MatDynMem gaussian_shaped_labels(double sigma, int dim1, int dim2);
+ cv::Mat gaussian_shaped_labels(double sigma, int dim1, int dim2);
std::unique_ptr<GaussianCorrelation> gaussian_correlation;
- MatDynMem circshift(const cv::Mat &patch, int x_rot, int y_rot);
+ cv::Mat circshift(const cv::Mat &patch, int x_rot, int y_rot);
cv::Mat cosine_window_function(int dim1, int dim2);
- void get_features(MatDynMem &feat_3d, cv::Mat &input_rgb, cv::Mat &input_gray, int cx, int cy, int size_x, int size_y, double scale) const;
+ void get_features(MatFeats &result, cv::Mat &input_rgb, cv::Mat &input_gray, int cx, int cy, int size_x, int size_y, double scale) const;
cv::Point2f sub_pixel_peak(cv::Point &max_loc, cv::Mat &response) const;
double sub_grid_scale(uint index);
void resizeImgs(cv::Mat &input_rgb, cv::Mat &input_gray);
struct ThreadCtx {
public:
- ThreadCtx(cv::Size roi, uint num_channels, uint num_of_scales
-#ifndef BIG_BATCH
+ ThreadCtx(cv::Size roi, uint num_features
+#ifdef BIG_BATCH
+ , uint num_of_scales
+#else
, double scale
#endif
)
: roi(roi)
- , num_channels(num_channels)
- , num_of_scales(num_of_scales)
+ , num_features(num_features)
+ , num_of_scales(IF_BIG_BATCH(num_of_scales, 1))
#ifndef BIG_BATCH
, scale(scale)
#endif
void track(const KCF_Tracker &kcf, cv::Mat &input_rgb, cv::Mat &input_gray);
private:
cv::Size roi;
- uint num_channels;
+ uint num_features;
uint num_of_scales;
cv::Size freq_size = Fft::freq_size(roi);
- KCF_Tracker::GaussianCorrelation gaussian_correlation{roi, num_of_scales, num_channels};
+ KCF_Tracker::GaussianCorrelation gaussian_correlation{num_of_scales, num_features, roi};
- MatDynMem ifft2_res{roi, CV_32FC(int(num_channels))};
+ MatDynMem ifft2_res{roi, CV_32FC(int(num_features))};
- ComplexMat zf{uint(freq_size.height), uint(freq_size.width), num_channels, num_of_scales};
+ ComplexMat zf{uint(freq_size.height), uint(freq_size.width), num_features, num_of_scales};
ComplexMat kzf{uint(freq_size.height), uint(freq_size.width), num_of_scales};
public:
std::future<void> async_res;
#endif
- MatDynMem response{roi, CV_32FC(int(num_of_scales))};
+ MatScales response{num_of_scales, roi};
struct Max {
cv::Point2i loc;