]> rtime.felk.cvut.cz Git - hercules2020/kcf.git/blob - src/complexmat.hpp
ComplexMat: Add CUDA stream synchronization before accessing host memory
[hercules2020/kcf.git] / src / complexmat.hpp
1 #ifndef COMPLEX_MAT_HPP_213123048309482094
2 #define COMPLEX_MAT_HPP_213123048309482094
3
4 #include <opencv2/opencv.hpp>
5 #include <vector>
6 #include <algorithm>
7 #include <functional>
8 #include "dynmem.hpp"
9 #include "pragmas.h"
10
11 #ifdef CUFFT
12 #include <cufft.h>
13 #endif
14
15 class ComplexMat_ {
16   public:
17     typedef float T;
18
19     uint cols;
20     uint rows;
21     uint n_channels;
22     uint n_scales;
23
24     ComplexMat_(uint _rows, uint _cols, uint _n_channels, uint _n_scales = 1)
25         : cols(_cols), rows(_rows), n_channels(_n_channels * _n_scales), n_scales(_n_scales),
26           p_data(n_channels * cols * rows) {}
27     ComplexMat_(cv::Size size, uint _n_channels, uint _n_scales = 1)
28         : cols(size.width), rows(size.height), n_channels(_n_channels * _n_scales), n_scales(_n_scales)
29         , p_data(n_channels * cols * rows) {}
30
31     // assuming that mat has 2 channels (real, img)
32     ComplexMat_(const cv::Mat &mat) : cols(uint(mat.cols)), rows(uint(mat.rows)), n_channels(1), n_scales(1)
33                                     , p_data(n_channels * cols * rows)
34     {
35         cudaSync();
36         memcpy(p_data.hostMem(), mat.ptr<std::complex<T>>(), mat.total() * mat.elemSize());
37     }
38
39     static ComplexMat_ same_size(const ComplexMat_ &o)
40     {
41         return ComplexMat_(o.rows, o.cols, o.n_channels / o.n_scales, o.n_scales);
42     }
43
44     // cv::Mat API compatibility
45     cv::Size size() const { return cv::Size(cols, rows); }
46     uint channels() const { return n_channels; }
47
48     // assuming that mat has 2 channels (real, imag)
49     void set_channel(uint idx, const cv::Mat &mat)
50     {
51         assert(idx < n_channels);
52         cudaSync();
53         for (uint i = 0; i < rows; ++i) {
54             const std::complex<T> *row = mat.ptr<std::complex<T>>(i);
55             for (uint j = 0; j < cols; ++j)
56                 p_data.hostMem()[idx * rows * cols + i * cols + j] = row[j];
57         }
58     }
59
60     T sqr_norm() const;
61
62     void sqr_norm(DynMem_<T> &result) const;
63
64     ComplexMat_ sqr_mag() const;
65
66     ComplexMat_ conj() const;
67
68     ComplexMat_ sum_over_channels() const;
69
70     // return 2 channels (real, imag) for first complex channel
71     cv::Mat to_cv_mat() const
72     {
73         assert(p_data.num_elem >= 1);
74         return channel_to_cv_mat(0);
75     }
76     // return a vector of 2 channels (real, imag) per one complex channel
77     std::vector<cv::Mat> to_cv_mat_vector() const
78     {
79         std::vector<cv::Mat> result;
80         result.reserve(n_channels);
81
82         for (uint i = 0; i < n_channels; ++i)
83             result.push_back(channel_to_cv_mat(i));
84
85         return result;
86     }
87
88     std::complex<T> *get_p_data() {
89         cudaSync();
90         return p_data.hostMem();
91     }
92     const std::complex<T> *get_p_data() const {
93         cudaSync();
94         return p_data.hostMem();
95     }
96
97 #ifdef CUFFT
98     cufftComplex *get_dev_data() { return (cufftComplex*)p_data.deviceMem(); }
99     const cufftComplex *get_dev_data() const { return (cufftComplex*)p_data.deviceMem(); }
100 #endif
101
102     // element-wise per channel multiplication, division and addition
103     ComplexMat_ operator*(const ComplexMat_ &rhs) const;
104     ComplexMat_ operator/(const ComplexMat_ &rhs) const;
105     ComplexMat_ operator+(const ComplexMat_ &rhs) const;
106
107     // multiplying or adding constant
108     ComplexMat_ operator*(const T &rhs) const;
109     ComplexMat_ operator+(const T &rhs) const;
110
111     // multiplying element-wise multichannel by one channel mats (rhs mat is with one channel)
112     ComplexMat_ mul(const ComplexMat_ &rhs) const;
113
114     // multiplying element-wise multichannel mats - same as operator*(ComplexMat), but without allocating memory for the result
115     ComplexMat_ muln(const ComplexMat_ &rhs) const
116     {
117         return mat_mat_operator([](std::complex<T> &c_lhs, const std::complex<T> &c_rhs) { c_lhs *= c_rhs; }, rhs);
118     }
119
120     // text output
121     friend std::ostream &operator<<(std::ostream &os, const ComplexMat_ &mat)
122     {
123         // for (int i = 0; i < mat.n_channels; ++i){
124         for (int i = 0; i < 1; ++i) {
125             os << "Channel " << i << std::endl;
126             for (uint j = 0; j < mat.rows; ++j) {
127                 for (uint k = 0; k < mat.cols - 1; ++k)
128                     os << mat.p_data[j * mat.cols + k] << ", ";
129                 os << mat.p_data[j * mat.cols + mat.cols - 1] << std::endl;
130             }
131         }
132         return os;
133     }
134
135   private:
136     DynMem_<std::complex<T>> p_data;
137
138     // convert 2 channel mat (real, imag) to vector row-by-row
139     std::vector<std::complex<T>> convert(const cv::Mat &mat)
140     {
141         std::vector<std::complex<T>> result;
142         result.reserve(mat.cols * mat.rows);
143         for (int y = 0; y < mat.rows; ++y) {
144             const T *row_ptr = mat.ptr<T>(y);
145             for (int x = 0; x < 2 * mat.cols; x += 2) {
146                 result.push_back(std::complex<T>(row_ptr[x], row_ptr[x + 1]));
147             }
148         }
149         return result;
150     }
151
152     ComplexMat_ mat_mat_operator(void (*op)(std::complex<T> &c_lhs, const std::complex<T> &c_rhs),
153                                  const ComplexMat_ &mat_rhs) const;
154     ComplexMat_ matn_mat1_operator(void (*op)(std::complex<T> &c_lhs, const std::complex<T> &c_rhs),
155                                    const ComplexMat_ &mat_rhs) const;
156     ComplexMat_ matn_mat2_operator(void (*op)(std::complex<T> &c_lhs, const std::complex<T> &c_rhs),
157                                    const ComplexMat_ &mat_rhs) const;
158     ComplexMat_ mat_const_operator(const std::function<void(std::complex<T> &c_rhs)> &op) const;
159
160     cv::Mat channel_to_cv_mat(int channel_id) const
161     {
162         cv::Mat result(rows, cols, CV_32FC2);
163         for (uint y = 0; y < rows; ++y) {
164             std::complex<T> *row_ptr = result.ptr<std::complex<T>>(y);
165             for (uint x = 0; x < cols; ++x) {
166                 row_ptr[x] = p_data[channel_id * rows * cols + y * cols + x];
167             }
168         }
169         return result;
170     }
171
172 #ifdef CUFFT
173     void cudaSync() const;
174 #else
175     void cudaSync() const {}
176 #endif
177 };
178
179 typedef ComplexMat_ ComplexMat;
180
181 #endif // COMPLEX_MAT_HPP_213123048309482094