1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 // This functions have been contributed by Jonas Geisters <geistert@nue.tu-berlin.de>
5 
6 #include "../precomp.hpp"
7 
8 #include "geo_interpolation.hpp"
9 #include <string>
10 #include <map>
11 namespace cv {
12 namespace optflow {
13 
14 struct Graph_helper {
15     std::vector<int> mem;
16     int e_size;
Graph_helpercv::optflow::Graph_helper17     Graph_helper(int k, int num_nodes) {
18         e_size = (2 * k + 1);
19         mem.resize(e_size * num_nodes, 0);
20     }
sizecv::optflow::Graph_helper21     inline int size(int id) {
22         int r_addr = id * (e_size);
23         return mem[r_addr];
24     }
datacv::optflow::Graph_helper25     inline int * data(int id) {
26         int r_addr = id * (e_size)+1;
27         return &mem[r_addr];
28     }
addcv::optflow::Graph_helper29     inline void add(int id, std::pair<float, int> data) {
30         int r_addr = id * (e_size);
31         int size = ++mem[r_addr];
32         r_addr += 2 * size - 1;//== 1 + 2*(size-1);
33         *(float*)&mem[r_addr] = data.first;
34         mem[r_addr + 1] = data.second;
35     }
color_in_targetcv::optflow::Graph_helper36     inline bool color_in_target(int id, int color) {
37         int r_addr = id * (e_size);
38         int size = mem[r_addr];
39         r_addr += 2;
40         for (int i = 0; i < size; i++) {
41             if (mem[r_addr] == color) {
42                 return true;
43             }
44             r_addr += 2;
45         }
46         return false;
47     }
48 
49 };
50 
sgeo_dist(const Mat & gra,int y,int x,float max,Mat & prev)51 Mat sgeo_dist(const Mat& gra, int y, int x, float max, Mat &prev)
52 {
53     std::vector <Point2f> points;
54     points.push_back(Point2f(static_cast<float>(x), static_cast<float>(y)));
55     return sgeo_dist(gra, points, max, prev);
56 }
sgeo_dist(const Mat & gra,const std::vector<Point2f> & points,float max,Mat & prev)57 Mat sgeo_dist(const Mat& gra, const std::vector<Point2f> & points, float max, Mat &prev)
58 {
59     int Dx[] = { -1,0,1,-1,1,-1,0,1 };
60     int Dy[] = { -1,-1,-1,0,0,1,1,1 };
61     Mat dm(gra.rows, gra.cols, CV_32F, Scalar(max));
62     prev = Mat(gra.rows, gra.cols, CV_8U, Scalar(255));
63 
64     std::multimap<float, Vec2i > not_visited_with_value;
65 
66     for (auto i = points.begin(); i != points.end(); i++)
67     {
68         int y = static_cast<int>(i->y);
69         int x = static_cast<int>(i->x);
70         not_visited_with_value.insert(std::pair<float, Vec2i >(0.f, Vec2i(y, x)));
71         dm.at<float>(y, x) = 0;
72     }
73 
74     bool done = false;
75     while (!done)
76     {
77         if (not_visited_with_value.begin() == not_visited_with_value.end()) {
78             done = true;
79             break;
80         }
81         std::multimap<float, Vec2i >::iterator current_it = not_visited_with_value.begin();
82         std::pair<float, Vec2i > current_p = *current_it;
83         not_visited_with_value.erase(current_it);
84 
85         int y = current_p.second[0];
86         int x = current_p.second[1];
87         float cur_d = current_p.first;
88 
89         if (dm.at<float>(y, x) != cur_d) {
90             continue;
91         }
92 
93         Vec8f gra_e = gra.at<Vec8f>(y, x);
94 
95         for (int i = 0; i < 8; i++) {
96             if (gra_e[i] < 0) {
97                 continue;
98             }
99             int dx = Dx[i];
100             int dy = Dy[i];
101 
102             if (dm.at<float>(y + dy, x + dx) > cur_d + gra_e[i]) {
103                 dm.at<float>(y + dy, x + dx) = cur_d + gra_e[i];
104                 prev.at<uchar>(y + dy, x + dx) = static_cast<uchar>(7 - i);
105                 not_visited_with_value.insert(std::pair<float, Vec2i >(cur_d + gra_e[i], Vec2i(y + dy, x + dx)));
106             }
107 
108         }
109     }
110 
111 
112 
113 
114     return dm;
115 }
116 
interpolate_irregular_nn_raster(const std::vector<Point2f> & prevPoints,const std::vector<Point2f> & nextPoints,const std::vector<uchar> & status,const Mat & i1)117 Mat interpolate_irregular_nn_raster(const std::vector<Point2f> & prevPoints,
118     const std::vector<Point2f> & nextPoints,
119     const std::vector<uchar> & status,
120     const Mat & i1)
121 {
122     Mat gra = getGraph(i1, 0.1f);
123     int Dx[] = { -1,0,1,-1,1,-1,0,1 };
124     int Dy[] = { -1,-1,-1,0,0,1,1,1 };
125     int max_rounds = 10;
126     Mat dirt = Mat(gra.rows, gra.cols, CV_8U, Scalar(0));
127     Mat quellknoten = Mat(gra.rows, gra.cols, CV_32S, Scalar(-1));
128     Mat dist = Mat(gra.rows, gra.cols, CV_32F, Scalar(std::numeric_limits<float>::max()));
129     /*
130         * assign quellknoten ids.
131         */
132     for (int i = 0; i < static_cast<int>(prevPoints.size()); i++)
133     {
134         int x = (int)prevPoints[i].x;
135         int y = (int)prevPoints[i].y;
136         if (status[i] == 0)
137             continue;
138         dirt.at<uchar>(y, x) = 1;
139         dist.at<float>(y, x) = 0;
140         quellknoten.at<int>(y, x) = i;
141     }
142 
143     bool clean = true;
144     bool done = false;
145     int x = 0;
146     int y = 0;
147     int rounds = 0;
148     while (!done) {
149         /*
150             * Update x and y
151             * on even rounds go rasterscanorder , on odd round inverse rasterscanorder
152             */
153         if (rounds % 2 == 0) {
154             x++;
155             if (x >= gra.cols) {
156                 x = 0;
157                 y++;
158                 if (y >= gra.rows) {
159                     y = 0;
160                     rounds++;
161                     y = gra.rows - 1;
162                     x = gra.cols - 1;
163                     if (rounds >= max_rounds || clean) {
164                         done = true;
165                         break;
166                     }
167                 }
168             }
169         }
170         else {
171             x--;
172             if (x < 0) {
173                 x = gra.cols - 1;
174                 y--;
175                 if (y < 0) {
176                     y = gra.rows - 1;
177                     rounds++;
178                     y = 0;
179                     x = 0;
180                     if (rounds >= max_rounds || clean) {
181                         done = true;
182                         break;
183                     }
184                 }
185             }
186         }
187         if (dirt.at<uchar>(y, x) == 0) {
188             continue;
189         }
190         dirt.at<uchar>(y, x) = 0;
191 
192         float c_dist = dist.at<float>(y, x);
193         Vec8f gra_e = gra.at<Vec8f>(y, x);
194 
195         for (int i = 0; i < 8; i++) {
196             int tx = Dx[i];
197             int ty = Dy[i];
198             if (ty == 0 && tx == 0) {
199                 continue;
200             }
201             if (x + tx < 0 || x + tx >= gra.cols) {
202                 continue;
203             }
204             if (y + ty < 0 || y + ty >= gra.rows) {
205                 continue;
206             }
207             if (c_dist > dist.at<float>(y + ty, x + tx)) {
208                 if (c_dist > dist.at<float>(y + ty, x + tx) + gra_e[i]) {
209                     quellknoten.at<int>(y, x) = quellknoten.at<int>(y + ty, x + tx);
210                     dist.at<float>(y, x) = dist.at<float>(y + ty, x + tx) + gra_e[i];
211                     dirt.at<uchar>(y, x) = 1;
212                     clean = false;
213                 }
214             }
215             else {
216                 if (c_dist + gra_e[i] < dist.at<float>(y + ty, x + tx)) {
217                     quellknoten.at<int>(y + ty, x + tx) = quellknoten.at<int>(y, x);
218                     dist.at<float>(y + ty, x + tx) = dist.at<float>(y, x) + gra_e[i];
219                     dirt.at<uchar>(y + ty, x + tx) = 1;
220                     clean = false;
221                 }
222             }
223         }
224 
225 
226 
227     }
228 
229     Mat nnFlow(i1.rows, i1.cols, CV_32FC2, Scalar(0));
230     for (y = 0; y < i1.rows; y++) {
231         for (x = 0; x < i1.cols; x++) {
232 
233             int id = quellknoten.at<int>(y, x);
234             if (id != -1)
235             {
236                 nnFlow.at<Point2f>(y, x) = nextPoints[id] - prevPoints[id];
237             }
238         }
239     }
240     return nnFlow;
241 }
242 
interpolate_irregular_knn(const std::vector<Point2f> & _prevPoints,const std::vector<Point2f> & _nextPoints,const std::vector<uchar> & status,const Mat & color_img,int k,float pixeldistance)243 Mat interpolate_irregular_knn(
244     const std::vector<Point2f> & _prevPoints,
245     const std::vector<Point2f> & _nextPoints,
246     const std::vector<uchar> & status,
247     const Mat &color_img,
248     int k,
249     float pixeldistance)
250 {
251     Mat in(color_img.rows, color_img.cols, CV_32FC2);
252     Mat mask = Mat::zeros(color_img.rows, color_img.cols, CV_8UC1);
253 
254     for (unsigned n = 0; n < _prevPoints.size(); n++)
255     {
256         if (_prevPoints[n].x >= 0 && _prevPoints[n].y >= 0 && _prevPoints[n].x < color_img.cols && _prevPoints[n].y < color_img.rows)
257         {
258             in.at<Point2f>(_prevPoints[n]) = _nextPoints[n] - _prevPoints[n];
259             mask.at<uchar>(_prevPoints[n]) = status[n];
260         }
261 
262     }
263     int Dx[] = { -1,0,1,-1,1,-1,0,1 };
264     int Dy[] = { -1,-1,-1,0,0,1,1,1 };
265     Mat gra = getGraph(color_img, pixeldistance);
266     Mat nnFlow(in.rows, in.cols, CV_32FC2, Scalar(0));
267 
268     std::multimap<float, Vec2i > my_agents; // <arrivaltim , < target, color >>
269     Graph_helper graph_helper(k, in.rows*in.cols); //< arrivaltime, color>
270 
271 
272     int color = 0;
273     std::vector<Vec2i> flow_point_list;
274     for (int y = 0; y < in.rows; y++) {
275         for (int x = 0; x < in.cols; x++) {
276             if (mask.at<uchar>(y, x) > 0) {
277                 flow_point_list.push_back(Vec2i(y, x));
278                 nnFlow.at<Vec2f>(y, x) = in.at<Vec2f>(y, x);
279 
280                 int v_id = (y * in.cols + x);
281                 graph_helper.add(v_id, std::pair<float, int>(0.f, color));
282 
283 
284                 Vec8f gra_e = gra.at<Vec8f>(y, x);
285                 for (int i = 0; i < 8; i++) {
286                     if (gra_e[i] < 0)
287                         continue;
288                     int dx = Dx[i];
289                     int dy = Dy[i];
290                     int target = (y + dy) * in.cols + (x + dx);
291                     Vec2i agent(target, color);
292                     my_agents.insert(std::pair<float, Vec2i >(gra_e[i], agent));
293 
294                 }
295                 color++;
296             }
297         }
298     }
299 
300     int global_time = 0;
301 
302     bool done = false;
303     while (!done) {
304         if (my_agents.size() == 0) {
305             done = true;
306             break;
307         }
308         global_time++;
309 
310         std::multimap<float, Vec2i >::iterator current_it = my_agents.begin();
311         std::pair<float, Vec2i > current_p = *current_it;
312         my_agents.erase(current_it);
313 
314         int target = current_p.second[0];
315         color = current_p.second[1];
316         float arriv_time = current_p.first;
317 
318         Vec8f gra_e = gra.at<Vec8f>(target);// (y*cols+x)
319         if (graph_helper.size(target) >= k) {
320             continue;
321         }
322 
323         bool color_found_in_target = graph_helper.color_in_target(target, color);
324         if (color_found_in_target) {
325             continue;
326         }
327         graph_helper.add(target, std::pair<float, int>(arriv_time, color));
328 
329 
330         for (int i = 0; i < 8; i++) {
331             if (gra_e[i] < 0)
332                 continue;
333 
334             int dx = Dx[i];
335             int dy = Dy[i];
336             int new_target = target + dx + (dy*in.cols);
337             if (graph_helper.size(new_target) >= k) {
338                 continue;
339             }
340             color_found_in_target = graph_helper.color_in_target(new_target, color);
341             if (color_found_in_target) {
342                 continue;
343             }
344             Vec2i new_agent(new_target, color);
345             my_agents.insert(std::pair<float, Vec2i >(arriv_time + gra_e[i], new_agent));
346 
347         }
348     }
349 
350     Mat ret(in.rows, in.cols*k, CV_32FC2);
351     for (int y = 0; y < in.rows; y++) {
352         for (int x = 0; x < in.cols; x++) {
353             for (int i = 0; i < k; i++) {
354                 float dist = *((float*)(graph_helper.data(y*in.cols + x) + 2 * i));
355                 float id = *((float*)(graph_helper.data(y*in.cols + x) + 2 * i + 1));
356                 ret.at<Vec2f>(y, k*x + i) = Vec2f(dist, id);
357             }
358         }
359     }
360     return ret;
361 }
362 
getGraph(const Mat & image,float edge_length)363 Mat getGraph(const Mat &image, float edge_length)
364 {
365 
366     int Dx[] = { -1,0,1,-1,1,-1,0,1 };
367     int Dy[] = { -1,-1,-1,0,0,1,1,1 };
368     Mat gra(image.rows, image.cols, CV_32FC(8));
369 
370     for (int y = 0; y < gra.rows; y++) {
371         for (int x = 0; x < gra.cols; x++) {
372 
373             for (int i = 0; i < 8; i++) {
374                 int dx = Dx[i];
375                 int dy = Dy[i];
376                 gra.at<Vec8f>(y, x)[i] = -1;
377 
378                 if (x + dx < 0 || y + dy < 0 || x + dx >= gra.cols || y + dy >= gra.rows) {
379                     continue;
380                 }
381 
382                 if (i < 4) {
383                     int si = 7 - i;
384                     gra.at<Vec8f>(y, x)[i] = gra.at<Vec8f>(y + dy, x + dx)[si];
385                 }
386                 else {
387                     float p1 = dx * dx*edge_length*edge_length + dy * dy*edge_length*edge_length;
388                     float p2 = static_cast<float>(image.at<Vec3b>(y, x)[0] - image.at<Vec3b>(y + dy, x + dx)[0]);
389                     float p3 = static_cast<float>(image.at<Vec3b>(y, x)[1] - image.at<Vec3b>(y + dy, x + dx)[1]);
390                     float p4 = static_cast<float>(image.at<Vec3b>(y, x)[2] - image.at<Vec3b>(y + dy, x + dx)[2]);
391                     gra.at<Vec8f>(y, x)[i] = sqrt(p1 + p2 * p2 + p3 * p3 + p4 * p4);
392                 }
393 
394             }
395 
396         }
397     }
398 
399     return gra;
400 }
401 
402 
interpolate_irregular_nn(const std::vector<Point2f> & _prevPoints,const std::vector<Point2f> & _nextPoints,const std::vector<uchar> & status,const Mat & color_img,float pixeldistance)403 Mat interpolate_irregular_nn(
404     const std::vector<Point2f> & _prevPoints,
405     const std::vector<Point2f> & _nextPoints,
406     const std::vector<uchar> & status,
407     const Mat &color_img,
408     float pixeldistance)
409 {
410     int Dx[] = { -1,0,1,-1,1,-1,0,1 };
411     int Dy[] = { -1,-1,-1,0,0,1,1,1 };
412     std::vector<Point2f> prevPoints, nextPoints;
413     std::map<std::pair<float, float>, std::pair<float, float>> flowMap;
414     for (unsigned n = 0; n < _prevPoints.size(); n++)
415     {
416         if (status[n] != 0)
417         {
418             flowMap.insert(std::make_pair(
419                 std::make_pair(_prevPoints[n].x, _prevPoints[n].y),
420                 std::make_pair(_nextPoints[n].x, _nextPoints[n].y)));
421             prevPoints.push_back(_prevPoints[n]);
422             nextPoints.push_back(_nextPoints[n]);
423         }
424 
425     }
426 
427     Mat gra = getGraph(color_img, pixeldistance);
428 
429     Mat prev;
430     Mat geo_dist = sgeo_dist(gra, prevPoints, std::numeric_limits<float>::max(), prev);
431 
432 
433     Mat nnFlow = Mat::zeros(color_img.size(), CV_32FC2);
434     for (int y = 0; y < nnFlow.rows; y++)
435     {
436         for (int x = 0; x < nnFlow.cols; x++)
437         {
438             int cx = x;
439             int cy = y;
440             while (prev.at<uchar>(cy, cx) != 255)
441             {
442                 int i = prev.at<uchar>(cy, cx);
443                 cx += Dx[i];
444                 cy += Dy[i];
445             }
446             auto val = flowMap[std::make_pair(static_cast<float>(cx), static_cast<float>(cy))];
447             nnFlow.at<Vec2f>(y, x) = Vec2f(val.first - cx, val.second - cy);
448         }
449     }
450     return nnFlow;
451 }
452 
453 }} // namespace
454