22 if (mask.empty() || factor >= 1.0) {
28 if (mask.type() != CV_8U) {
29 mask.convertTo(binary, CV_8U);
31 binary = mask.clone();
33 cv::threshold(binary, binary, 0, 255, cv::THRESH_BINARY);
35 std::vector<std::vector<cv::Point>> contours;
36 cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
38 if (contours.empty()) {
39 return cv::Mat::zeros(mask.size(), CV_8U);
43 size_t largest_idx = 0;
44 double largest_area = 0;
45 for (
size_t i = 0; i < contours.size(); ++i) {
46 double area = cv::contourArea(contours[i]);
47 if (area > largest_area) {
54 cv::Moments m = cv::moments(contours[largest_idx]);
56 return cv::Mat::zeros(mask.size(), CV_8U);
58 double cx = m.m10 / m.m00;
59 double cy = m.m01 / m.m00;
62 std::vector<cv::Point> scaled_contour;
63 scaled_contour.reserve(contours[largest_idx].size());
64 for (
const auto& pt : contours[largest_idx]) {
65 double sx = cx + factor * (pt.x - cx);
66 double sy = cy + factor * (pt.y - cy);
67 scaled_contour.emplace_back(
68 static_cast<int>(std::round(sx)),
69 static_cast<int>(std::round(sy))
74 cv::Mat result = cv::Mat::zeros(mask.size(), CV_8U);
75 std::vector<std::vector<cv::Point>> scaled_contours = {scaled_contour};
76 cv::fillPoly(result, scaled_contours, cv::Scalar(255));
86 double sigma_temporal) {
91 const int N =
static_cast<int>(volume.size());
92 const int H = volume[0].rows;
93 const int W = volume[0].cols;
97 int ksize_spatial =
static_cast<int>(std::ceil(sigma_spatial * 2.0)) * 2 + 1;
98 if (ksize_spatial < 3) ksize_spatial = 3;
100 std::vector<cv::Mat> spatially_filtered(N);
101 for (
int f = 0; f < N; ++f) {
103 if (volume[f].type() != CV_64F) {
104 volume[f].convertTo(frame, CV_64F);
109 cv::GaussianBlur(frame, spatially_filtered[f],
110 cv::Size(ksize_spatial, ksize_spatial),
111 sigma_spatial, sigma_spatial,
112 cv::BORDER_REPLICATE);
115 if (N == 1 || sigma_temporal < 1e-10) {
116 return spatially_filtered;
121 int ksize_temporal =
static_cast<int>(std::ceil(sigma_temporal * 2.0)) * 2 + 1;
122 if (ksize_temporal < 3) ksize_temporal = 3;
123 int half_k = ksize_temporal / 2;
125 std::vector<double> kernel(ksize_temporal);
126 double kernel_sum = 0;
127 for (
int k = 0; k < ksize_temporal; ++k) {
128 double t =
static_cast<double>(k - half_k);
129 kernel[k] = std::exp(-0.5 * t * t / (sigma_temporal * sigma_temporal));
130 kernel_sum += kernel[k];
132 for (
auto& v : kernel) {
137 std::vector<cv::Mat> result(N);
138 for (
int f = 0; f < N; ++f) {
139 result[f] = cv::Mat::zeros(H, W, CV_64F);
142 for (
int y = 0; y < H; ++y) {
143 for (
int x = 0; x < W; ++x) {
144 for (
int f = 0; f < N; ++f) {
146 for (
int k = 0; k < ksize_temporal; ++k) {
147 int src_f = f + k - half_k;
149 src_f = std::clamp(src_f, 0, N - 1);
150 val += spatially_filtered[src_f].at<
double>(y, x) * kernel[k];
152 result[f].at<
double>(y, x) = val;
164 double level_corr_coef,
165 double sigma_spatial,
166 double sigma_temporal,
167 double shrink_factor) {
168 if (data.disps.empty()) {
172 const int Nframe =
static_cast<int>(data.disps.size());
173 const int H = data.disps[0].data_height();
174 const int W = data.disps[0].data_width();
176 LOG_DEBUG <<
" matlab_replacebadcorr: " << Nframe <<
" frames, "
177 << H <<
"x" << W <<
" grid, cc_threshold=" << level_corr_coef;
180 std::vector<cv::Mat> u_vol(Nframe), v_vol(Nframe), cc_vol(Nframe);
181 for (
int f = 0; f < Nframe; ++f) {
182 u_vol[f] = cv::Mat(H, W, CV_64F, 0.0);
183 v_vol[f] = cv::Mat(H, W, CV_64F, 0.0);
184 cc_vol[f] = cv::Mat(H, W, CV_64F, 0.0);
186 const auto& u_arr = data.disps[f].get_u().get_array();
187 const auto& v_arr = data.disps[f].get_v().get_array();
188 const auto& cc_arr = data.disps[f].get_cc().get_array();
190 for (
int y = 0; y < H; ++y) {
191 for (
int x = 0; x < W; ++x) {
192 u_vol[f].at<
double>(y, x) = u_arr(y, x);
193 v_vol[f].at<
double>(y, x) = v_arr(y, x);
194 cc_vol[f].at<
double>(y, x) = cc_arr(y, x);
201 std::vector<cv::Mat> mask_bad(Nframe);
202 for (
int f = 0; f < Nframe; ++f) {
203 mask_bad[f] = cv::Mat(H, W, CV_8U, cv::Scalar(0));
204 for (
int y = 0; y < H; ++y) {
205 for (
int x = 0; x < W; ++x) {
206 if (cc_vol[f].at<double>(y, x) > level_corr_coef) {
207 mask_bad[f].at<uint8_t>(y, x) = 255;
217 cv::Mat mask_in(H, W, CV_8U, cv::Scalar(0));
218 for (
int y = 0; y < H; ++y) {
219 for (
int x = 0; x < W; ++x) {
220 if (u_vol[Nframe - 1].at<double>(y, x) != 0.0) {
221 mask_in.at<uint8_t>(y, x) = 255;
233 std::vector<cv::Mat> u_modif1(Nframe), v_modif1(Nframe);
234 int total_replaced = 0;
235 for (
int f = 0; f < Nframe; ++f) {
236 u_modif1[f] = u_vol[f].clone();
237 v_modif1[f] = v_vol[f].clone();
238 for (
int y = 0; y < H; ++y) {
239 for (
int x = 0; x < W; ++x) {
240 if (mask_bad[f].at<uint8_t>(y, x) && mask_shrunk.at<uint8_t>(y, x)) {
241 u_modif1[f].at<
double>(y, x) = uf[f].at<double>(y, x);
242 v_modif1[f].at<
double>(y, x) = vf[f].at<double>(y, x);
255 std::vector<cv::Mat> u_modif2(Nframe), v_modif2(Nframe);
256 for (
int f = 0; f < Nframe; ++f) {
257 u_modif2[f] = u_vol[f].clone();
258 v_modif2[f] = v_vol[f].clone();
259 for (
int y = 0; y < H; ++y) {
260 for (
int x = 0; x < W; ++x) {
261 if (mask_bad[f].at<uint8_t>(y, x) && mask_shrunk.at<uint8_t>(y, x)) {
262 u_modif2[f].at<
double>(y, x) = uf[f].at<double>(y, x);
263 v_modif2[f].at<
double>(y, x) = vf[f].at<double>(y, x);
271 for (
int f = 0; f < Nframe; ++f) {
272 const auto& old_disp = data.disps[f];
273 const auto& old_roi = old_disp.get_roi();
274 auto scalefactor = old_disp.get_scalefactor();
277 ncorr::Array2D<double> new_u(H, W);
278 ncorr::Array2D<double> new_v(H, W);
279 ncorr::Array2D<double> new_cc(H, W);
281 const auto& old_cc = old_disp.get_cc().get_array();
282 for (
int y = 0; y < H; ++y) {
283 for (
int x = 0; x < W; ++x) {
284 new_u(y, x) = u_modif2[f].at<
double>(y, x);
285 new_v(y, x) = v_modif2[f].at<
double>(y, x);
286 new_cc(y, x) = old_cc(y, x);
290 data.disps[f] = ncorr::Disp2D(
291 std::move(new_v), std::move(new_u), std::move(new_cc),
296 LOG_DEBUG <<
" matlab_replacebadcorr: replaced " << total_replaced
297 <<
" subsets across " << Nframe <<
" frames";
299 return total_replaced;