Skip to content
Snippets Groups Projects
Commit a695fa87 authored by Sebastian Hahta's avatar Sebastian Hahta
Browse files

fix various StatisticsImage (closes #101) issues.

Statistics image is now reset when GUI mode is changed. Removed
n-samples mode (too slow, requires better algorithm). Resetting
the image mostly addresses this use case.
parent 5ab362f7
No related branches found
No related tags found
No related merge requests found
...@@ -11,118 +11,80 @@ using ftl::gui::PoseWindow; ...@@ -11,118 +11,80 @@ using ftl::gui::PoseWindow;
// TODO(Nick) MOVE // TODO(Nick) MOVE
class StatisticsImage { class StatisticsImage {
private: private:
std::vector<float> data_; cv::Mat data_;
cv::Size size_; cv::Size size_;
int n_; float max_f_;
public: public:
StatisticsImage(cv::Size size) { StatisticsImage(cv::Size size);
size_ = size; StatisticsImage(cv::Size size, float max_f);
data_ = std::vector<float>(size.width * size.height * 2, 0.0f);
n_ = 0;
}
void reset();
void update(const cv::Mat &in); void update(const cv::Mat &in);
void getVariance(cv::Mat &out);
void getStdDev(cv::Mat &out); void getStdDev(cv::Mat &out);
void getMean(cv::Mat &out); void getMean(cv::Mat &out);
}; };
void StatisticsImage::update(const cv::Mat &in) { StatisticsImage::StatisticsImage(cv::Size size) :
DCHECK(in.type() == CV_32F); StatisticsImage(size, std::numeric_limits<float>::infinity()) {}
DCHECK(in.size() == size_);
// Welford's Method StatisticsImage::StatisticsImage(cv::Size size, float max_f) {
size_ = size;
n_++; // channels: m, s, f
for (int i = 0; i < size_.width * size_.height; i++) { data_ = cv::Mat(size, CV_32FC3, cv::Scalar(0.0, 0.0, 0.0));
float x = ((float*) in.data)[i]; max_f_ = max_f;
if (!isValidDepth(x)) { continue; } // invalid value // TODO
float &m = data_[2*i]; if (!std::isinf(max_f_)) {
float &S = data_[2*i+1]; LOG(WARNING) << "TODO: max_f_ not used. Values calculated for all samples";
float m_prev = m;
m = m + (x - m) / n_;
S = S + (x - m) * (x - m_prev);
}
}
void StatisticsImage::getStdDev(cv::Mat &in) {
in = cv::Mat(size_, CV_32F, 0.0f);
for (int i = 0; i < size_.width * size_.height; i++) {
float &m = data_[2*i];
float &S = data_[2*i+1];
((float*) in.data)[i] = sqrt(S / n_);
} }
} }
void StatisticsImage::getMean(cv::Mat &in) { void StatisticsImage::reset() {
in = cv::Mat(size_, CV_32F, 0.0f); data_ = cv::Scalar(0.0, 0.0, 0.0);
for (int i = 0; i < size_.width * size_.height; i++) {
((float*) in.data)[i] = data_[2*i];
}
} }
class StatisticsImageNSamples { void StatisticsImage::update(const cv::Mat &in) {
private:
std::vector<cv::Mat> samples_;
cv::Size size_;
int i_;
int n_;
public:
StatisticsImageNSamples(cv::Size size, int n) {
size_ = size;
samples_ = std::vector<cv::Mat>(n);
i_ = 0;
n_ = n;
}
void update(const cv::Mat &in);
void getStdDev(cv::Mat &out);
void getVariance(cv::Mat &out);
void getMean(cv::Mat &out);
};
void StatisticsImageNSamples::update(const cv::Mat &in) {
DCHECK(in.type() == CV_32F); DCHECK(in.type() == CV_32F);
DCHECK(in.size() == size_); DCHECK(in.size() == size_);
// Welford's Method
i_ = (i_ + 1) % n_; for (int row = 0; row < in.rows; row++) {
in.copyTo(samples_[i_]); float* ptr_data = data_.ptr<float>(row);
} const float* ptr_in = in.ptr<float>(row);
void StatisticsImageNSamples::getStdDev(cv::Mat &out) {
cv::Mat var;
getVariance(var);
cv::sqrt(var, out);
}
void StatisticsImageNSamples::getVariance(cv::Mat &out) { for (int col = 0; col < in.cols; col++, ptr_in++) {
// Welford's Method float x = *ptr_in;
cv::Mat mat_m(size_, CV_32F, 0.0f); float &m = *ptr_data++;
cv::Mat mat_S(size_, CV_32F, 0.0f); float &s = *ptr_data++;
float &f = *ptr_data++;
float n = 0.0f;
for (int i_sample = (i_ + 1) % n_; i_sample != i_; i_sample = (i_sample + 1) % n_) {
if (samples_[i_sample].size() != size_) continue;
n += 1.0f;
for (int i = 0; i < size_.width * size_.height; i++) {
float &x = ((float*) samples_[i_sample].data)[i];
float &m = ((float*) mat_m.data)[i];
float &S = ((float*) mat_S.data)[i];
float m_prev = m; float m_prev = m;
if (!isValidDepth(x)) continue; if (!ftl::rgbd::isValidDepth(x)) continue;
m = m + (x - m) / n; f = f + 1.0f;
S = S + (x - m) * (x - m_prev); m = m + (x - m) / f;
s = s + (x - m) * (x - m_prev);
} }
} }
}
void StatisticsImage::getVariance(cv::Mat &out) {
std::vector<cv::Mat> channels(3);
cv::split(data_, channels);
cv::divide(channels[1], channels[2], out);
}
mat_S.copyTo(out); void StatisticsImage::getStdDev(cv::Mat &out) {
getVariance(out);
cv::sqrt(out, out);
} }
void StatisticsImageNSamples::getMean(cv::Mat &in) {} void StatisticsImage::getMean(cv::Mat &out) {
std::vector<cv::Mat> channels(3);
cv::split(data_, channels);
out = channels[0];
}
static Eigen::Affine3d create_rotation_matrix(float ax, float ay, float az) { static Eigen::Affine3d create_rotation_matrix(float ax, float ay, float az) {
Eigen::Affine3d rx = Eigen::Affine3d rx =
...@@ -234,7 +196,16 @@ void ftl::gui::Camera::setChannel(ftl::rgbd::channel_t c) { ...@@ -234,7 +196,16 @@ void ftl::gui::Camera::setChannel(ftl::rgbd::channel_t c) {
channel_ = c; channel_ = c;
switch (c) { switch (c) {
case ftl::rgbd::kChanRight: case ftl::rgbd::kChanRight:
case ftl::rgbd::kChanDepth: src_->setChannel(c); break; [[fallthrough]];
case ftl::rgbd::kChanDeviation:
if (stats_) { stats_->reset(); }
[[fallthrough]];
case ftl::rgbd::kChanDepth:
src_->setChannel(ftl::rgbd::kChanDepth);
break;
default: src_->setChannel(ftl::rgbd::kChanNone); default: src_->setChannel(ftl::rgbd::kChanNone);
} }
} }
...@@ -266,7 +237,7 @@ const GLTexture &ftl::gui::Camera::captureFrame() { ...@@ -266,7 +237,7 @@ const GLTexture &ftl::gui::Camera::captureFrame() {
if (channel_ == ftl::rgbd::kChanDeviation) { if (channel_ == ftl::rgbd::kChanDeviation) {
if (!stats_ && depth.rows > 0) { if (!stats_ && depth.rows > 0) {
stats_ = new StatisticsImageNSamples(depth.size(), 25); stats_ = new StatisticsImage(depth.size());
} }
if (stats_ && depth.rows > 0) { stats_->update(depth); } if (stats_ && depth.rows > 0) { stats_->update(depth); }
...@@ -288,7 +259,7 @@ const GLTexture &ftl::gui::Camera::captureFrame() { ...@@ -288,7 +259,7 @@ const GLTexture &ftl::gui::Camera::captureFrame() {
if (depth.rows == 0) { break; } if (depth.rows == 0) { break; }
//imageSize = Vector2f(depth.cols, depth.rows); //imageSize = Vector2f(depth.cols, depth.rows);
stats_->getStdDev(tmp); stats_->getStdDev(tmp);
tmp.convertTo(tmp, CV_8U, 50.0); tmp.convertTo(tmp, CV_8U, 1000.0);
applyColorMap(tmp, tmp, cv::COLORMAP_HOT); applyColorMap(tmp, tmp, cv::COLORMAP_HOT);
texture_.update(tmp); texture_.update(tmp);
break; break;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include <string> #include <string>
class StatisticsImageNSamples; class StatisticsImage;
namespace ftl { namespace ftl {
namespace gui { namespace gui {
...@@ -43,7 +43,7 @@ class Camera { ...@@ -43,7 +43,7 @@ class Camera {
nlohmann::json getMetaData(); nlohmann::json getMetaData();
StatisticsImageNSamples *stats_ = nullptr; StatisticsImage *stats_ = nullptr;
private: private:
Screen *screen_; Screen *screen_;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment