void EnsureStencilInstantiation( void ) { MICStencil<float> csf( 0, 0, 0, 0 ); Matrix2D<float> mf( 2, 2 ); csf( mf, 0); MICStencil<double> csd( 0, 0, 0, 0 ); Matrix2D<double> md( 2, 2 ); csd( md, 0); }
CommandTransform::CommandTransform(const QSet<int> &selection, ldraw::model *model, Editor::RotationPivot pivot) : CommandBase(selection, model) { setText(i18n("Transform")); pivot_ = pivot; bool center = false; if (pivot_ == Editor::PivotCenter) center = true; CommandSelectionFilter csf(this); pivotpoint_ = PivotExtension::queryPivot(model_, center, &csf); for (QSet<int>::ConstIterator it = selection.constBegin(); it != selection.constEnd(); ++it) { if (model->elements()[*it]->get_type() == ldraw::type_ref) oldmatrices_[*it] = CAST_AS_CONST_REF(model->elements()[*it])->get_matrix(); } }
void qCSF::doAction() { //m_app should have already been initialized by CC when plugin is loaded! //(--> pure internal check) assert(m_app); if (!m_app) return; if ( !m_app->haveOneSelection() ) { m_app->dispToConsole("Select only one cloud!", ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } const ccHObject::Container& selectedEntities = m_app->getSelectedEntities(); ccHObject* ent = selectedEntities[0]; assert(ent); if (!ent || !ent->isA(CC_TYPES::POINT_CLOUD)) { m_app->dispToConsole("Select a real point cloud!", ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } //to get the point cloud from selected entity. ccPointCloud* pc = static_cast<ccPointCloud*>(ent); //Convert CC point cloud to CSF type unsigned count = pc->size(); wl::PointCloud csfPC; try { csfPC.reserve(count); } catch (const std::bad_alloc&) { m_app->dispToConsole("Not enough memory!", ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } for (unsigned i = 0; i < count; i++) { const CCVector3* P = pc->getPoint(i); wl::Point tmpPoint; //tmpPoint.x = P->x; //tmpPoint.y = P->y; //tmpPoint.z = P->z; tmpPoint.x = P->x; tmpPoint.y = -P->z; tmpPoint.z = P->y; csfPC.push_back(tmpPoint); } //initial dialog parameters static bool csf_postprocessing = false; static double cloth_resolution = 2; static double class_threshold = 0.5; static int csf_rigidness = 2; static int MaxIteration = 500; static bool ExportClothMesh = false; // display the dialog { ccCSFDlg csfDlg(m_app->getMainWindow()); csfDlg.postprocessingcheckbox->setChecked(csf_postprocessing); csfDlg.rig1->setChecked(csf_rigidness == 1); csfDlg.rig2->setChecked(csf_rigidness == 2); csfDlg.rig3->setChecked(csf_rigidness == 3); csfDlg.MaxIterationSpinBox->setValue(MaxIteration); csfDlg.cloth_resolutionSpinBox->setValue(cloth_resolution); csfDlg.class_thresholdSpinBox->setValue(class_threshold); csfDlg.exportClothMeshCheckBox->setChecked(ExportClothMesh); if (!csfDlg.exec()) { return; } //save the parameters for next time csf_postprocessing = csfDlg.postprocessingcheckbox->isChecked(); if (csfDlg.rig1->isChecked()) csf_rigidness = 1; else if (csfDlg.rig2->isChecked()) csf_rigidness = 2; else csf_rigidness = 3; MaxIteration = csfDlg.MaxIterationSpinBox->value(); cloth_resolution = csfDlg.cloth_resolutionSpinBox->value(); class_threshold = csfDlg.class_thresholdSpinBox->value(); ExportClothMesh = csfDlg.exportClothMeshCheckBox->isChecked(); } //display the progress dialog QProgressDialog pDlg; pDlg.setWindowTitle("CSF"); pDlg.setLabelText("Computing...."); pDlg.setCancelButton(0); pDlg.show(); QApplication::processEvents(); QElapsedTimer timer; timer.start(); //instantiation a CSF class CSF csf(csfPC); // setup parameter csf.params.k_nearest_points = 1; csf.params.bSloopSmooth = csf_postprocessing; csf.params.time_step = 0.65; csf.params.class_threshold = class_threshold; csf.params.cloth_resolution = cloth_resolution; csf.params.rigidness = csf_rigidness; csf.params.iterations = MaxIteration; //to do filtering std::vector<int> groundIndexes, offGroundIndexes; ccMesh* clothMesh = 0; if (!csf.do_filtering(groundIndexes, offGroundIndexes, ExportClothMesh, clothMesh, m_app)) { m_app->dispToConsole("Process failed", ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } m_app->dispToConsole(QString("[CSF] %1% of points classified as ground points").arg((groundIndexes.size() * 100.0) / count, 0, 'f', 2), ccMainAppInterface::STD_CONSOLE_MESSAGE); m_app->dispToConsole(QString("[CSF] Timing: %1 s.").arg(timer.elapsed() / 1000.0, 0, 'f', 1), ccMainAppInterface::STD_CONSOLE_MESSAGE); //extract ground subset ccPointCloud* groundpoint = 0; { CCLib::ReferenceCloud groundpc(pc); if (groundpc.reserve(static_cast<unsigned>(groundIndexes.size()))) { for (unsigned j = 0; j < groundIndexes.size(); ++j) { groundpc.addPointIndex(groundIndexes[j]); } groundpoint = pc->partialClone(&groundpc); } } if (!groundpoint) { m_app->dispToConsole("Failed to extract the ground subset (not enough memory)", ccMainAppInterface::WRN_CONSOLE_MESSAGE); } //extract off-ground subset ccPointCloud* offgroundpoint = 0; { CCLib::ReferenceCloud offgroundpc(pc); if (offgroundpc.reserve(static_cast<unsigned>(offGroundIndexes.size()))) { for (unsigned k = 0; k < offGroundIndexes.size(); ++k) { offgroundpc.addPointIndex(offGroundIndexes[k]); } offgroundpoint = pc->partialClone(&offgroundpc); } } if (!offgroundpoint) { m_app->dispToConsole("Failed to extract the off-ground subset (not enough memory)", ccMainAppInterface::WRN_CONSOLE_MESSAGE); if (!groundpoint) { //nothing to do! return; } } pDlg.hide(); QApplication::processEvents(); //hide the original cloud pc->setEnabled(false); //we add new group to DB/display ccHObject* cloudContainer = new ccHObject(pc->getName() + QString("_csf")); if (groundpoint) { groundpoint->setVisible(true); groundpoint->setName("ground points"); cloudContainer->addChild(groundpoint); } if (offgroundpoint) { offgroundpoint->setVisible(true); offgroundpoint->setName("off-ground points"); cloudContainer->addChild(offgroundpoint); } if (clothMesh) { clothMesh->computePerVertexNormals(); clothMesh->showNormals(true); cloudContainer->addChild(clothMesh); } m_app->addToDB(cloudContainer); m_app->refreshAll(); }
bool Yee_Compare(CompareArgs &args) { if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) || (args.ImgA->Get_Height() != args.ImgB->Get_Height())) { // args.ErrorStr = "Image dimensions do not match\n"; args.PixelsFailed = 0xffffffff; return false; } int dim = args.ImgA->Get_Width() * args.ImgA->Get_Height(); bool identical = true; for (int i = 0; i < dim; i++) { if (args.ImgA->Get(i) != args.ImgB->Get(i)) { identical = false; break; } } if (identical) { // args.ErrorStr = "Images are binary identical\n"; args.PixelsFailed = 0; return true; } // assuming colorspaces are in Adobe RGB (1998) convert to XYZ float *aX = new float[dim]; float *aY = new float[dim]; float *aZ = new float[dim]; float *bX = new float[dim]; float *bY = new float[dim]; float *bZ = new float[dim]; float *aLum = new float[dim]; float *bLum = new float[dim]; float *aA = new float[dim]; float *bA = new float[dim]; float *aB = new float[dim]; float *bB = new float[dim]; if (args.Verbose) printf("Converting RGB to XYZ\n"); unsigned int x, y, w, h; w = args.ImgA->Get_Width(); h = args.ImgA->Get_Height(); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { float r, g, b, l; int i = x + y * w; r = powf(args.ImgA->Get_Red(i) / 255.0f, args.Gamma); g = powf(args.ImgA->Get_Green(i) / 255.0f, args.Gamma); b = powf(args.ImgA->Get_Blue(i) / 255.0f, args.Gamma); AdobeRGBToXYZ(r,g,b,aX[i],aY[i],aZ[i]); XYZToLAB(aX[i], aY[i], aZ[i], l, aA[i], aB[i]); r = powf(args.ImgB->Get_Red(i) / 255.0f, args.Gamma); g = powf(args.ImgB->Get_Green(i) / 255.0f, args.Gamma); b = powf(args.ImgB->Get_Blue(i) / 255.0f, args.Gamma); AdobeRGBToXYZ(r,g,b,bX[i],bY[i],bZ[i]); XYZToLAB(bX[i], bY[i], bZ[i], l, bA[i], bB[i]); aLum[i] = aY[i] * args.Luminance; bLum[i] = bY[i] * args.Luminance; } } if (args.Verbose) printf("Constructing Laplacian Pyramids\n"); LPyramid *la = new LPyramid(aLum, w, h); LPyramid *lb = new LPyramid(bLum, w, h); float num_one_degree_pixels = (float) (2 * tan( args.FieldOfView * 0.5 * M_PI / 180) * 180 / M_PI); float pixels_per_degree = w / num_one_degree_pixels; if (args.Verbose) printf("Performing test\n"); float num_pixels = 1; unsigned int adaptation_level = 0; for (int i = 0; i < MAX_PYR_LEVELS; i++) { adaptation_level = i; if (num_pixels > num_one_degree_pixels) break; num_pixels *= 2; } float cpd[MAX_PYR_LEVELS]; cpd[0] = 0.5f * pixels_per_degree; for (int i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1]; float csf_max = csf(3.248f, 100.0f); float F_freq[MAX_PYR_LEVELS - 2]; for (int i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f); unsigned int pixels_failed = 0; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int index = x + y * w; float contrast[MAX_PYR_LEVELS - 2]; float sum_contrast = 0; for (int i = 0; i < MAX_PYR_LEVELS - 2; i++) { float n1 = fabsf(la->Get_Value(x,y,i) - la->Get_Value(x,y,i + 1)); float n2 = fabsf(lb->Get_Value(x,y,i) - lb->Get_Value(x,y,i + 1)); float numerator = (n1 > n2) ? n1 : n2; float d1 = fabsf(la->Get_Value(x,y,i+2)); float d2 = fabsf(lb->Get_Value(x,y,i+2)); float denominator = (d1 > d2) ? d1 : d2; if (denominator < 1e-5f) denominator = 1e-5f; contrast[i] = numerator / denominator; sum_contrast += contrast[i]; } if (sum_contrast < 1e-5) sum_contrast = 1e-5f; float F_mask[MAX_PYR_LEVELS - 2]; float adapt = la->Get_Value(x,y,adaptation_level) + lb->Get_Value(x,y,adaptation_level); adapt *= 0.5f; if (adapt < 1e-5) adapt = 1e-5f; for (int i = 0; i < MAX_PYR_LEVELS - 2; i++) { F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt)); } float factor = 0; for (int i = 0; i < MAX_PYR_LEVELS - 2; i++) { factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast; } if (factor < 1) factor = 1; if (factor > 10) factor = 10; float delta = fabsf(la->Get_Value(x,y,0) - lb->Get_Value(x,y,0)); bool pass = true; // pure luminance test if (delta > factor * tvi(adapt)) { pass = false; } else { // CIE delta E test with modifications float color_scale = 1.0f; // ramp down the color test in scotopic regions if (adapt < 10.0f) { color_scale = 1.0f - (10.0f - color_scale) / 10.0f; color_scale = color_scale * color_scale; } float da = aA[index] - bA[index]; float db = aB[index] - bB[index]; da = da * da; db = db * db; float delta_e = (da + db) * color_scale; if (delta_e > factor) { pass = false; } } if (!pass) { pixels_failed++; // if (args.ImgDiff) { // args.ImgDiff->Set(255, 0, 0, 255, index); // } } else { // if (args.ImgDiff) { // args.ImgDiff->Set(0, 0, 0, 255, index); // } } } } if (aX) delete[] aX; if (aY) delete[] aY; if (aZ) delete[] aZ; if (bX) delete[] bX; if (bY) delete[] bY; if (bZ) delete[] bZ; if (aLum) delete[] aLum; if (bLum) delete[] bLum; if (la) delete la; if (lb) delete lb; if (aA) delete aA; if (bA) delete bA; if (aB) delete aB; if (bB) delete bB; args.PixelsFailed = pixels_failed; return true; /* if (pixels_failed < args.ThresholdPixels) { args.ErrorStr = "Images are perceptually indistinguishable\n"; return true; } char different[100]; sprintf(different, "%d pixels are different\n", pixels_failed); args.ErrorStr = "Images are visibly different\n"; args.ErrorStr += different; if (args.ImgDiff) { if (args.ImgDiff->WritePPM()) { args.ErrorStr += "Wrote difference image to "; args.ErrorStr+= args.ImgDiff->Get_Name(); args.ErrorStr += "\n"; } else { args.ErrorStr += "Could not write difference image to "; args.ErrorStr+= args.ImgDiff->Get_Name(); args.ErrorStr += "\n"; } } return false; */ }
bool yee_compare(CompareArgs &args) { if ((args.image_a_->get_width() != args.image_b_->get_width()) or (args.image_a_->get_height() != args.image_b_->get_height())) { args.error_string_ = "Image dimensions do not match\n"; return false; } const auto w = args.image_a_->get_width(); const auto h = args.image_a_->get_height(); const auto dim = w * h; auto identical = true; for (auto i = 0u; i < dim; i++) { if (args.image_a_->get(i) != args.image_b_->get(i)) { identical = false; break; } } if (identical) { args.error_string_ = "Images are binary identical\n"; return true; } // Assuming colorspaces are in Adobe RGB (1998) convert to XYZ. std::vector<float> a_lum(dim); std::vector<float> b_lum(dim); std::vector<float> a_a(dim); std::vector<float> b_a(dim); std::vector<float> a_b(dim); std::vector<float> b_b(dim); if (args.verbose_) { std::cout << "Converting RGB to XYZ\n"; } const auto gamma = args.gamma_; const auto luminance = args.luminance_; #pragma omp parallel for shared(args, a_lum, b_lum, a_a, a_b, b_a, b_b) for (auto y = 0; y < static_cast<ptrdiff_t>(h); y++) { for (auto x = 0u; x < w; x++) { const auto i = x + y * w; const auto a_color_r = powf(args.image_a_->get_red(i) / 255.0f, gamma); const auto a_color_g = powf(args.image_a_->get_green(i) / 255.0f, gamma); const auto a_color_b = powf(args.image_a_->get_blue(i) / 255.0f, gamma); float a_x; float a_y; float a_z; adobe_rgb_to_xyz(a_color_r, a_color_g, a_color_b, a_x, a_y, a_z); float l; xyz_to_lab(a_x, a_y, a_z, l, a_a[i], a_b[i]); const auto b_color_r = powf(args.image_b_->get_red(i) / 255.0f, gamma); const auto b_color_g = powf(args.image_b_->get_green(i) / 255.0f, gamma); const auto b_color_b = powf(args.image_b_->get_blue(i) / 255.0f, gamma); float b_x; float b_y; float b_z; adobe_rgb_to_xyz(b_color_r, b_color_g, b_color_b, b_x, b_y, b_z); xyz_to_lab(b_x, b_y, b_z, l, b_a[i], b_b[i]); a_lum[i] = a_y * luminance; b_lum[i] = b_y * luminance; } } if (args.verbose_) { std::cout << "Constructing Laplacian Pyramids\n"; } const LPyramid la(a_lum, w, h); const LPyramid lb(b_lum, w, h); const auto num_one_degree_pixels = to_degrees(2 * std::tan(args.field_of_view_ * to_radians(.5f))); const auto pixels_per_degree = w / num_one_degree_pixels; if (args.verbose_) { std::cout << "Performing test\n"; } const auto adaptation_level = adaptation(num_one_degree_pixels); float cpd[MAX_PYR_LEVELS]; cpd[0] = 0.5f * pixels_per_degree; for (auto i = 1u; i < MAX_PYR_LEVELS; i++) { cpd[i] = 0.5f * cpd[i - 1]; } const auto csf_max = csf(3.248f, 100.0f); static_assert(MAX_PYR_LEVELS > 2, "MAX_PYR_LEVELS must be greater than 2"); float f_freq[MAX_PYR_LEVELS - 2]; for (auto i = 0u; i < MAX_PYR_LEVELS - 2; i++) { f_freq[i] = csf_max / csf(cpd[i], 100.0f); } auto pixels_failed = 0u; auto error_sum = 0.; #pragma omp parallel for reduction(+ : pixels_failed, error_sum) \ shared(args, a_a, a_b, b_a, b_b, cpd, f_freq) for (auto y = 0; y < static_cast<ptrdiff_t>(h); y++) { for (auto x = 0u; x < w; x++) { const auto index = y * w + x; const auto adapt = std::max((la.get_value(x, y, adaptation_level) + lb.get_value(x, y, adaptation_level)) * 0.5f, 1e-5f); auto sum_contrast = 0.f; auto factor = 0.f; for (auto i = 0u; i < MAX_PYR_LEVELS - 2; i++) { const auto n1 = fabsf(la.get_value(x, y, i) - la.get_value(x, y, i + 1)); const auto n2 = fabsf(lb.get_value(x, y, i) - lb.get_value(x, y, i + 1)); const auto numerator = std::max(n1, n2); const auto d1 = fabsf(la.get_value(x, y, i + 2)); const auto d2 = fabsf(lb.get_value(x, y, i + 2)); const auto denominator = std::max(std::max(d1, d2), 1e-5f); const auto contrast = numerator / denominator; const auto f_mask = mask(contrast * csf(cpd[i], adapt)); factor += contrast * f_freq[i] * f_mask; sum_contrast += contrast; } sum_contrast = std::max(sum_contrast, 1e-5f); factor /= sum_contrast; factor = std::min(std::max(factor, 1.f), 10.f); const auto delta = fabsf(la.get_value(x, y, 0) - lb.get_value(x, y, 0)); error_sum += delta; auto pass = true; // pure luminance test if (delta > factor * tvi(adapt)) { pass = false; } if (not args.luminance_only_) { // CIE delta E test with modifications auto color_scale = args.color_factor_; // ramp down the color test in scotopic regions if (adapt < 10.0f) { // Don't do color test at all. color_scale = 0.0; } const auto da = a_a[index] - b_a[index]; const auto db = a_b[index] - b_b[index]; const auto delta_e = (da * da + db * db) * color_scale; error_sum += delta_e; if (delta_e > factor) { pass = false; } } if (not pass) { pixels_failed++; if (args.image_difference_) { args.image_difference_->set(255, 0, 0, 255, index); } } else { if (args.image_difference_) { args.image_difference_->set(0, 0, 0, 255, index); } } } } const auto error_sum_buff = std::to_string(error_sum) + " error sum\n"; const auto different = std::to_string(pixels_failed) + " pixels are different\n"; // Always output image difference if requested. if (args.image_difference_) { args.image_difference_->write_to_file(args.image_difference_->get_name()); args.error_string_ += "Wrote difference image to "; args.error_string_ += args.image_difference_->get_name(); args.error_string_ += "\n"; } if (pixels_failed < args.threshold_pixels_) { args.error_string_ = "Images are perceptually indistinguishable\n"; args.error_string_ += different; return true; } args.error_string_ = "Images are visibly different\n"; args.error_string_ += different; if (args.sum_errors_) { args.error_string_ += error_sum_buff; } return false; }