diff --git a/cv-node/include/ftl/rtcensus.hpp b/cv-node/include/ftl/rtcensus.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a717df9e2d10d96d85fddcdbe11aae09cb523fa4 --- /dev/null +++ b/cv-node/include/ftl/rtcensus.hpp @@ -0,0 +1,12 @@ +#ifndef _FTL_RTCENSUS_HPP_ +#define _FTL_RTCENSUS_HPP_ + +namespace ftl { +class RTCensus { + public: + void disparity(cv::Mat &l, cv::Mat &r, cv::Mat &disp, size_t num_disp=32, float gamma=0.0f, float tau=0.0f); +}; +}; + +#endif // _FTL_RTCENSUS_HPP_ + diff --git a/cv-node/src/rtcensus.cpp b/cv-node/src/rtcensus.cpp new file mode 100644 index 0000000000000000000000000000000000000000..099f827ca06b4c7ec1d37063e532b686f6c1a0b5 --- /dev/null +++ b/cv-node/src/rtcensus.cpp @@ -0,0 +1,135 @@ +#include <ftl/rtcensus.hpp> +#include <vector> + +using ftl::RTCensus; +using std::vector; + +#define XHI(P1,P2) ((P1 <= P2) ? 0 : 1) + +static vector<int64_t> sparse_census_16x16(Mat &arr) { + vector<int64_t> result; + result.resize(arr.cols*arr.rows); + + auto N = [-7,-5,-3,-1,1,3,5,7]; + auto M = [-7,-5,-3,-1,1,3,5,7]; + + for (size_t v=0; v<arr.cols; v++) { + for (size_t u=0; u<arr.rows; u++) { + int64_t r = 0; + + for (auto n : N) { + for (auto m : M) { + auto u_ = u + n; + auto v_ = v + m; + + if (u_ < 0 || v_ < 0 || u_ >= arr.rows || v_ >= arr.cols) continue; + + r << 1; + r |= XHI(arr.at<uint8_t>(v,u), arr.at<uint8_t>(v_,u_)); + } + } + + result[v+u*arr.cols] = r; + } + } + + return result; +} + +static int hamming(int n1, int n2) { + int x = n1 ^ n2; + int setBits = 0; + + while (x > 0) { + setBits += x & 1; + x >>= 1; + } + + return setBits; +} + +static vector<int64_t> dsi_ca(vector<int64_t> census_R, vector<int64_t> census_L, size_t w, size_t h, size_t d_start, size_t d_stop, int sign=1) { + // TODO Add asserts + + auto ds = d_stop - d_start; + vector<int64_t> result; + result.resize(census_R.size()*ds); + + //auto N = [-2,-1,0,1,2]; + //auto M = [-2,-1,0,1,2]; + + for (size_t d=0; d<ds; d++) { + for (size_t v=0; v<w; v++) { + for (size_t u=0; u<h; u++) { + for (int n=-2; n<=2; n++) { + for (int n=-2; n<=2; n++) { + auto u_ = u + n; + auto v_ = v + m; + auto d_ = d * sign; + + if (!(0<=(u_+d_) < h) continue; + if (!(0<=u_<h) || !(0<=v_<w)) continue; + + auto r = census_R[v_+u_*w]; + auto l = census_L[v_+(u_+d_)*w]; + result[v+u*w+d*w*h]; + } + } + + } + } + } + + return result; +} + +int64_t arrmin(vector<int64_t> a, size_t ix, size_t len) { + int64_t m = INT64_MAX; + for (size_t i=ix,i<ix+len; i++) { + if (a[i] < m) m = a[i]; + } + return m; +} + +cv::Mat d_sub(vector<int64_t> dsi, size_t w, size_t h, size_t ds) { + Mat result = Mat::zeros(Size(w,h), CV_64FC1); + + for (size_t v=0; v<w; v++) { + for (size_t u=0; u<h; u++) { + auto d_min = arrmin(dsi, v+u*w, ds); + decltype(d_min) d_sub; + + if (d_min == 0 || d_min == ds-1) d_sub = d_min; + else { + Point p(d_min, dsi[v+u*w+d_min*w*h]); + Point pl(d_min-1, dsi[v+u*w+(d_min-1)*w*h]); + Point pr(d_min+1, dsi[v+u*w+(d_min+1)*w*h]); + + d_sub = fit_parabola(p,pl,pr); + } + + result.at<uint8_t>(v,u) = d_sub; + } + } + + return result; +} + +void RTCensus::disparity(cv::Mat &l, cv::Mat &r, cv::Mat &disp, size_t num_disp, float gamma, float tau) { + size_t d_min = 0; + size_t d_max = num_disp; + + auto census_R = sparse_census_16x16(l); + auto census_L = sparse_census_16x16(r); + + auto dsi_ca_R = dsi_ca(census_R, census_L, l.cols, l.rows, d_min, d_max); + auto dsi_ca_L = dsi_ca(census_L, census_R, l.cols, l.rows, d_min, d_max, -1); + + auto disp_R = d_sub(dsi_ca_R); + auto disp_L = d_sub(dsi_ca_L); + + disp = consistency(disp_R, disp_L); + + // TODO confidence and texture filtering +} +