int main(void) { cout << "Eigen v" << EIGEN_WORLD_VERSION << "." << EIGEN_MAJOR_VERSION << "." << EIGEN_MINOR_VERSION << endl; static const int R = 288; static const int N = R*(R+1)/2; static const int M = 63; static const int HALF_M = M/2; static const float nsigma = 2.5f; MatrixXf data = MatrixXf::Random(M, N); MatrixXf mask = MatrixXf::Zero(M, N); MatrixXf result = MatrixXf::Zero(1, N); VectorXf std = VectorXf::Zero(N); VectorXf centroid = VectorXf::Zero(N); VectorXf mean = VectorXf::Zero(N); VectorXf minval = VectorXf::Zero(N); VectorXf maxval = VectorXf::Zero(N); cout << "computing..." << flush; double t = GetRealTime(); // computes the exact median if (M&1) { #pragma omp parallel for for (int i = 0; i < N; i++) { vector<float> row(data.data()+i*M, data.data()+(i+1)*M); nth_element(row.begin(), row.begin()+HALF_M, row.end()); centroid(i) = row[HALF_M]; } } // nth_element guarantees x_0,...,x_{n-1} < x_n else { #pragma omp parallel for for (int i = 0; i < N; i++) { vector<float> row(data.data()+i*M, data.data()+(i+1)*M); nth_element(row.begin(), row.begin()+HALF_M, row.end()); centroid(i) = row[HALF_M]; centroid(i) += *max_element(row.begin(), row.begin()+HALF_M); centroid(i) *= 0.5f; } } // compute the mean mean = data.colwise().mean(); // compute std (x) = sqrt ( 1/N SUM_i (x(i) - mean(x))^2 ) std = (((data.rowwise() - mean.transpose()).array().square()).colwise().sum() * (1.0f / M)) .array() .sqrt(); // compute n sigmas from centroid minval = centroid - std * nsigma; maxval = centroid + std * nsigma; // compute clip mask for (int i = 0; i < N; i++) { mask.col(i) = (data.col(i).array() > minval(i)).select(VectorXf::Ones(M), 0.0f); mask.col(i) = (data.col(i).array() < maxval(i)).select(VectorXf::Ones(M), 0.0f); } // apply clip mask to data data.array() *= mask.array(); // compute mean such that we ignore clipped data, this is our final result result = data.colwise().sum().array() / mask.colwise().sum().array(); t = GetRealTime() - t; cout << "[done]" << endl << endl; size_t bytes = data.size()*sizeof(float); cout << "data: " << M << "x" << N << endl; cout << "size: " << bytes*1e-6f << " MB" << endl; cout << "rate: " << bytes/(1e6f*t) << " MB/s" << endl; cout << "time: " << t << " s" << endl; return 0; }
void write_ply(const std::string &filename, const MatrixXu &F, const MatrixXf &V, const MatrixXf &N, const MatrixXf &Nf, const MatrixXf &UV, const MatrixXf &C, const ProgressCallback &progress) { auto message_cb = [](p_ply ply, const char *msg) { cerr << "rply: " << msg << endl; }; Timer<> timer; cout << "Writing \"" << filename << "\" (V=" << V.cols() << ", F=" << F.cols() << ") .. "; cout.flush(); if (N.size() > 0 && Nf.size() > 0) throw std::runtime_error("Please specify either face or vertex normals but not both!"); p_ply ply = ply_create(filename.c_str(), PLY_DEFAULT, message_cb, 0, nullptr); if (!ply) throw std::runtime_error("Unable to write PLY file!"); ply_add_comment(ply, "Generated by Instant Meshes"); ply_add_element(ply, "vertex", V.cols()); ply_add_scalar_property(ply, "x", PLY_FLOAT); ply_add_scalar_property(ply, "y", PLY_FLOAT); ply_add_scalar_property(ply, "z", PLY_FLOAT); if (N.size() > 0) { ply_add_scalar_property(ply, "nx", PLY_FLOAT); ply_add_scalar_property(ply, "ny", PLY_FLOAT); ply_add_scalar_property(ply, "nz", PLY_FLOAT); if (N.cols() != V.cols() || N.rows() != 3) throw std::runtime_error("Vertex normal matrix has incorrect size"); } if (UV.size() > 0) { ply_add_scalar_property(ply, "u", PLY_FLOAT); ply_add_scalar_property(ply, "v", PLY_FLOAT); if (UV.cols() != V.cols() || UV.rows() != 2) throw std::runtime_error("Texture coordinate matrix has incorrect size"); } if (C.size() > 0) { ply_add_scalar_property(ply, "red", PLY_FLOAT); ply_add_scalar_property(ply, "green", PLY_FLOAT); ply_add_scalar_property(ply, "blue", PLY_FLOAT); if (C.cols() != V.cols() || (C.rows() != 3 && C.rows() != 4)) throw std::runtime_error("Color matrix has incorrect size"); } /* Check for irregular faces */ std::map<uint32_t, std::pair<uint32_t, std::map<uint32_t, uint32_t>>> irregular; size_t nIrregular = 0; if (F.rows() == 4) { for (uint32_t f=0; f<F.cols(); ++f) { if (F(2, f) == F(3, f)) { nIrregular++; auto &value = irregular[F(2, f)]; value.first = f; value.second[F(0, f)] = F(1, f); } } } ply_add_element(ply, "face", F.cols() - nIrregular + irregular.size()); ply_add_list_property(ply, "vertex_indices", PLY_UINT8, PLY_INT); if (Nf.size() > 0) { ply_add_scalar_property(ply, "nx", PLY_FLOAT); ply_add_scalar_property(ply, "ny", PLY_FLOAT); ply_add_scalar_property(ply, "nz", PLY_FLOAT); if (Nf.cols() != F.cols() || Nf.rows() != 3) throw std::runtime_error("Face normal matrix has incorrect size"); } ply_write_header(ply); for (uint32_t j=0; j<V.cols(); ++j) { for (uint32_t i=0; i<V.rows(); ++i) ply_write(ply, V(i, j)); if (N.size() > 0) { for (uint32_t i=0; i<N.rows(); ++i) ply_write(ply, N(i, j)); } if (UV.size() > 0) { for (uint32_t i=0; i<UV.rows(); ++i) ply_write(ply, UV(i, j)); } if (C.size() > 0) { for (uint32_t i=0; i<std::min(3u, (uint32_t) C.rows()); ++i) ply_write(ply, C(i, j)); } if (progress && j % 500000 == 0) progress("Writing vertex data", j / (Float) V.cols()); } for (uint32_t f=0; f<F.cols(); ++f) { if (F.rows() == 4 && F(2, f) == F(3, f)) continue; ply_write(ply, F.rows()); for (uint32_t i=0; i<F.rows(); ++i) ply_write(ply, F(i, f)); if (Nf.size() > 0) { for (uint32_t i=0; i<Nf.rows(); ++i) ply_write(ply, Nf(i, f)); } if (progress && f % 500000 == 0) progress("Writing face data", f / (Float) F.cols()); } for (auto item : irregular) { auto face = item.second; uint32_t v = face.second.begin()->first, first = v; ply_write(ply, face.second.size()); while (true) { ply_write(ply, v); v = face.second[v]; if (v == first) break; } if (Nf.size() > 0) { for (uint32_t i=0; i<Nf.rows(); ++i) ply_write(ply, Nf(i, face.first)); } } ply_close(ply); cout << "done. ("; if (irregular.size() > 0) cout << irregular.size() << " irregular faces, "; cout << "took " << timeString(timer.value()) << ")" << endl; }
Vector<float> as_vector (const MatrixXf & x) { return Vector<float>(x.size(), const_cast<float *>(x.data())); }