From 86406600598dffbd0924958a1d8c13d5b5d24030 Mon Sep 17 00:00:00 2001 From: Andriy Date: Thu, 19 Sep 2024 11:58:23 -0400 Subject: [PATCH 1/3] initial --- CMakeLists.txt | 5 +- README.md | 3 + docs/source/Math/f_2dmoments.rst | 2 +- docs/source/featurelist.rst | 135 +++- src/nyx/env_features.cpp | 22 +- src/nyx/feature_mgr_init.cpp | 5 +- src/nyx/features/2d_geomoments.cpp | 611 +++++++++++++++++ src/nyx/features/2d_geomoments.h | 400 +++++++++++ src/nyx/features/2d_geomoments_basic.cpp | 337 ++++++++++ ...nontriv.cpp => 2d_geomoments_basic_nt.cpp} | 54 +- src/nyx/features/contour.cpp | 101 +++ src/nyx/features/image_moments.cpp | 621 ------------------ src/nyx/features/image_moments.h | 230 ------- src/nyx/features_calc_workflow.cpp | 2 +- src/nyx/featureset.cpp | 116 +++- src/nyx/featureset.h | 134 +++- src/nyx/gpu/geomoments.cuh | 10 + src/nyx/gpu/geomoments_central.cu | 22 +- src/nyx/gpu/geomoments_main.cu | 6 +- src/nyx/gpu/geomoments_raw.cu | 22 +- src/nyx/gpu/geomoments_weighting.cu | 10 +- src/nyx/reduce_by_feature.cpp | 42 +- src/nyx/reduce_trivial_rois.cpp | 45 +- 23 files changed, 1984 insertions(+), 951 deletions(-) create mode 100644 src/nyx/features/2d_geomoments.cpp create mode 100644 src/nyx/features/2d_geomoments.h create mode 100644 src/nyx/features/2d_geomoments_basic.cpp rename src/nyx/features/{image_moments_nontriv.cpp => 2d_geomoments_basic_nt.cpp} (75%) delete mode 100644 src/nyx/features/image_moments.cpp delete mode 100644 src/nyx/features/image_moments.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 61e11184..44e8f2b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,8 +161,9 @@ set(SOURCE src/nyx/features/hexagonality_polygonality.cpp src/nyx/features/image_matrix.cpp src/nyx/features/image_matrix_nontriv.cpp - src/nyx/features/image_moments.cpp - src/nyx/features/image_moments_nontriv.cpp + src/nyx/features/2d_geomoments.cpp + src/nyx/features/2d_geomoments_basic.cpp + src/nyx/features/2d_geomoments_nt.cpp src/nyx/features/intensity.cpp src/nyx/features/intensity_3d.cpp src/nyx/features/neighbors.cpp diff --git a/README.md b/README.md index 01714b1c..456cb82e 100644 --- a/README.md +++ b/README.md @@ -335,6 +335,9 @@ Apart from defining your feature set by explicitly specifying comma-separated fe | \*all_intensity\* | integrated_intensity, mean, median, min, max, range, standard_deviation, standard_error, uniformity, skewness, kurtosis, hyperskewness, hyperflatness, mean_absolute_deviation, energy, root_mean_squared, entropy, mode, uniformity, p01, p10, p25, p75, p90, p99, interquartile_range, robust_mean_absolute_deviation, mass_displacement | \*all_morphology\* | area_pixels_count, area_um2, centroid_x, centroid_y, weighted_centroid_y, weighted_centroid_x, compactness, bbox_ymin, bbox_xmin, bbox_height, bbox_width, major_axis_length, minor_axis_length, eccentricity, orientation, num_neighbors, extent, aspect_ratio, equivalent_diameter, convex_hull_area, solidity, perimeter, edge_mean_intensity, edge_stddev_intensity, edge_max_intensity, edge_min_intensity, circularity | \*basic_morphology\* | area_pixels_count, area_um2, centroid_x, centroid_y, bbox_ymin, bbox_xmin, bbox_height, bbox_width +| \*geomoms\* | shape and intensity geometric moments, equivalent to \*igeomoms\* and \*sgeomoms\* combined +| \*igeomoms\* | intensity raw moments IMOM_RM_pq, central moments IMOM_CM_pq, normalized raw moments IMOM_NRM_pq, normalized central moments IMOM_NCM_pq, Hu invariants IMOM_HUk, weighted raw moments IMOM_WRM_pq, weighted central moments IMOM_WCM_pq, weighted normalized central moments IMOM_WNCM_pq, weighted Hu invariants IMOM_WHUk +| \*sgeomoms\* | shape raw moments SPAT_MOMENT_pq, central moments CENTRAL_MOMENT_pq, normalized raw moments NORM_SPAT_MOMENT_pq, normalized central moments NORM_CENTRAL_MOMENT_pq, Hu invariants HU_Mk, weighted raw moments WEIGHTED_SPAT_MOMENT_pq, weighted central moments WEIGHTED_CENTRAL_MOMENT_pq, weighted normalized central moments WT_NORM_CTR_MOM_pq, weighted Hu invariants WEIGHTED_HU_Mk | \*all_glcm\* | glcm_asm, glcm_acor, glcm_cluprom, glcm_clushade, glcm_clutend, glcm_contrast, glcm_correlation, glcm_difave, glcm_difentro, glcm_difvar, glcm_dis, glcm_energy, glcm_entropy, glcm_hom1, glcm_hom2, glcm_id, glcm_idn, glcm_idm, glcm_idmn, glcm_infomeas1, glcm_infomeas2, glcm_iv, glcm_jave, glcm_je, glcm_jmax, glcm_jvar, glcm_sumaverage, glcm_sumentropy, glcm_sumvariance, glcm_variance | \*all_glrlm\* | glrlm_sre, glrlm_lre, glrlm_gln, glrlm_glnn, glrlm_rln, glrlm_rlnn, glrlm_rp, glrlm_glv, glrlm_rv, glrlm_re, glrlm_lglre, glrlm_hglre, glrlm_srlgle, glrlm_srhgle, glrlm_lrlgle, glrlm_lrhgle | \*all_glszm\* | glszm_sae, glszm_lae, glszm_gln, glszm_glnn, glszm_szn, glszm_sznn, glszm_zp, glszm_glv, glszm_zv, glszm_ze, glszm_lglze, glszm_hglze, glszm_salgle, glszm_sahgle, glszm_lalgle, glszm_lahgle diff --git a/docs/source/Math/f_2dmoments.rst b/docs/source/Math/f_2dmoments.rst index 9f28677c..a0b0275d 100644 --- a/docs/source/Math/f_2dmoments.rst +++ b/docs/source/Math/f_2dmoments.rst @@ -40,7 +40,7 @@ and represent the center of mass of the image :math:`f(x,y)`. Hu's Uniqueness Theorem states that if :math:`f(x,y)` is piecewise continuous and has nonzero values only in the finite part of the :math:`(x,y)` plane, then geometric moments of all orders exist. It can then be shown that the moment set :math:`{\mu_{pq}}` is uniquely determined by :math:`f(x,y)` and conversely, :math:`f(x,y)` is uniquely determined by :math:`{\mu_{pq}}`. Since an image has -finite area, a moment set can be evaluated computationally and used to uniquely describe the information contained in the image. +finite area, a moment set can be evaluated computationally and used to uniquely describe the information contained in the image. Nyxus calculates 2 sets of geometric moments: moments where :math:`f(x,y)=1` within the ROI mask and 0 outside the ROI mask define shape moments while moments whose :math:`f(x,y)` are intensity at pixel location :math:`x,y` define intensity moments. Raw moments ----------- diff --git a/docs/source/featurelist.rst b/docs/source/featurelist.rst index 0b6c2a98..d0ef16fc 100644 --- a/docs/source/featurelist.rst +++ b/docs/source/featurelist.rst @@ -555,7 +555,7 @@ Nyxus provided features - A set of Gabor filters of varying frequencies and orientations -**2D image moments:** +**2D shape image moments:** ---- @@ -689,6 +689,139 @@ Nyxus provided features * - WEIGHTED_HU_M7 - Weighted Hu's moment 7 +**2D intensity image moments:** + +---- + +.. list-table:: + :header-rows: 1 + + * - Nyxus feature code + - Description + * - IMOM_RM_00 + - Spatial (raw) moments + * - IMOM_RM_01 + - of order 00, 01, 02, etc + * - IMOM_RM_02 + - + * - IMOM_RM_03 + - + * - IMOM_RM_10 + - + * - IMOM_RM_11 + - + * - IMOM_RM_12 + - + * - IMOM_RM_20 + - + * - IMOM_RM_21 + - + * - IMOM_RM_30 + - + * - IMOM_WRM_00 + - Spatial moments weighted by pixel distance to ROI edge + * - IMOM_WRM_01 + - + * - IMOM_WRM_02 + - + * - IMOM_WRM_03 + - + * - IMOM_WRM_10 + - + * - IMOM_WRM_11 + - + * - IMOM_WRM_12 + - + * - IMOM_WRM_20 + - + * - IMOM_WRM_21 + - + * - IMOM_WRM_30 + - + * - IMOM_СM_02 + - Central moments + * - IMOM_СM_03 + - + * - IMOM_СM_11 + - + * - IMOM_СM_12 + - + * - IMOM_СM_20 + - + * - IMOM_СM_21 + - + * - IMOM_СM_30 + - + * - IMOM_WСM_02 + - Central moments weighted by pixel distance to ROI edge + * - IMOM_WСM_03 + - + * - IMOM_WСM_11 + - + * - IMOM_WСM_12 + - + * - IMOM_WСM_20 + - + * - IMOM_WСM_21 + - + * - IMOM_WСM_30 + - + * - IMOM_NСM_02 + - Normalized central moments + * - IMOM_NСM_03 + - + * - IMOM_NСM_11 + - + * - IMOM_NСM_ + - + * - IMOM_NСM_20 + - + * - IMOM_NСM_21 + - + * - IMOM_NСM_30 + - + * - IMOM_NRM_00 + - Normalized (standardized) spatial moments + * - IMOM_NRM_01 + - + * - IMOM_NRM_02 + - + * - IMOM_NRM_03 + - + * - IMOM_NRM_10 + - + * - IMOM_NRM_20 + - + * - IMOM_NRM_30 + - + * - IMOM_HU1 + - Hu's moment 1 + * - IMOM_HU2 + - Hu's moment 2 + * - IMOM_HU3 + - Hu's moment 3 + * - IMOM_HU4 + - Hu's moment 4 + * - IMOM_HU5 + - Hu's moment 5 + * - IMOM_HU6 + - Hu's moment 6 + * - IMOM_HU7 + - Hu's moment 7 + * - IMOM_WHU1 + - Weighted Hu's moment 1 + * - IMOM_WHU2 + - Weighted Hu's moment 2 + * - IMOM_WHU3 + - Weighted Hu's moment 3 + * - IMOM_WHU4 + - Weighted Hu's moment 4 + * - IMOM_WHU5 + - Weighted Hu's moment 5 + * - IMOM_WHU6 + - Weighted Hu's moment 6 + * - IMOM_WHU7 + - Weighted Hu's moment 7 **Neighbor features:** diff --git a/src/nyx/env_features.cpp b/src/nyx/env_features.cpp index 04d4a016..f8ed3c39 100644 --- a/src/nyx/env_features.cpp +++ b/src/nyx/env_features.cpp @@ -27,7 +27,7 @@ #include "features/gldzm.h" #include "features/glrlm.h" #include "features/glszm.h" -#include "features/image_moments.h" +#include "features/2d_geomoments.h" #include "features/intensity.h" #include "features/neighbors.h" #include "features/ngldm.h" @@ -248,7 +248,8 @@ bool Environment::expand_2D_featuregroup (const std::string & s) theFeatureSet.enableAll(); theFeatureSet.disableFeatures(GaborFeature::featureset); theFeatureSet.disableFeatures(GLCMFeature::featureset); - theFeatureSet.disableFeatures(ImageMomentsFeature::featureset); + theFeatureSet.disableFeatures(Imoms2D_feature::featureset); + theFeatureSet.disableFeatures(Smoms2D_feature::featureset); return true; } @@ -349,9 +350,22 @@ bool Environment::expand_2D_featuregroup (const std::string & s) return true; } - if (s == Nyxus::theFeatureSet.findGroupNameByCode(Fgroup2D::FG2_MOMENTS)) + if (s == Nyxus::theFeatureSet.findGroupNameByCode(Fgroup2D::FG2_GEOMOMENTS)) { - theFeatureSet.enableFeatures(ImageMomentsFeature::featureset); + theFeatureSet.enableFeatures (Smoms2D_feature::featureset); + theFeatureSet.enableFeatures (Imoms2D_feature::featureset); + return true; + } + + if (s == Nyxus::theFeatureSet.findGroupNameByCode(Fgroup2D::FG2_GEOMOMENTS_I)) + { + theFeatureSet.enableFeatures(Imoms2D_feature::featureset); + return true; + } + + if (s == Nyxus::theFeatureSet.findGroupNameByCode(Fgroup2D::FG2_GEOMOMENTS_S)) + { + theFeatureSet.enableFeatures(Smoms2D_feature::featureset); return true; } diff --git a/src/nyx/feature_mgr_init.cpp b/src/nyx/feature_mgr_init.cpp index eb707dee..90718172 100644 --- a/src/nyx/feature_mgr_init.cpp +++ b/src/nyx/feature_mgr_init.cpp @@ -20,7 +20,7 @@ #include "features/hexagonality_polygonality.h" #include "features/ngldm.h" #include "features/ngtdm.h" -#include "features/image_moments.h" +#include "features/2d_geomoments.h" #include "features/intensity.h" #include "features/intensity_3d.h" #include "features/moments.h" @@ -60,7 +60,8 @@ FeatureManager::FeatureManager() register_feature (new GLDMFeature()); register_feature (new NGLDMfeature()); register_feature (new NGTDMFeature()); - register_feature (new ImageMomentsFeature()); + register_feature (new Imoms2D_feature()); + register_feature (new Smoms2D_feature()); register_feature (new GaborFeature()); register_feature (new ZernikeFeature()); register_feature (new RadialDistributionFeature()); diff --git a/src/nyx/features/2d_geomoments.cpp b/src/nyx/features/2d_geomoments.cpp new file mode 100644 index 00000000..f05cbea7 --- /dev/null +++ b/src/nyx/features/2d_geomoments.cpp @@ -0,0 +1,611 @@ +#include "../featureset.h" + +#ifdef USE_GPU +#include "../gpucache.h" +#include "../gpu/geomoments.cuh" +#endif + +#include "2d_geomoments.h" + + +//********************** i-moms + +Imoms2D_feature::Imoms2D_feature() : FeatureMethod("Imoms2D") +{ + provide_features(Imoms2D_feature::featureset); + add_dependencies({ Nyxus::Feature2D::PERIMETER }); +} + +void Imoms2D_feature::calculate(LR& r) +{ + BasicGeomoms2D::calculate(r, intenAsInten); +} + +void Imoms2D_feature::osized_add_online_pixel(size_t x, size_t y, uint32_t intensity) +{ + BasicGeomoms2D::osized_add_online_pixel(x, y, intensity); +} + +void Imoms2D_feature::osized_calculate(LR& r, ImageLoader& imloader) +{ + BasicGeomoms2D::osized_calculate(r, imloader); +} + +void Imoms2D_feature::parallel_process_1_batch(size_t start, size_t end, std::vector* ptrLabels, std::unordered_map * ptrLabelData) +{ + for (auto i = start; i < end; i++) + { + int lab = (*ptrLabels)[i]; + LR& r = (*ptrLabelData)[lab]; + + if (r.has_bad_data()) + continue; + + Imoms2D_feature f; + f.calculate(r); + f.save_value(r.fvals); + } +} + +void Imoms2D_feature::save_value(std::vector>& fvals) +{ + fvals[(int)Nyxus::Feature2D::IMOM_RM_00][0] = m00; + fvals[(int)Nyxus::Feature2D::IMOM_RM_01][0] = m01; + fvals[(int)Nyxus::Feature2D::IMOM_RM_02][0] = m02; + fvals[(int)Nyxus::Feature2D::IMOM_RM_03][0] = m03; + fvals[(int)Nyxus::Feature2D::IMOM_RM_10][0] = m10; + fvals[(int)Nyxus::Feature2D::IMOM_RM_11][0] = m11; + fvals[(int)Nyxus::Feature2D::IMOM_RM_12][0] = m12; + fvals[(int)Nyxus::Feature2D::IMOM_RM_13][0] = m13; + fvals[(int)Nyxus::Feature2D::IMOM_RM_20][0] = m20; + fvals[(int)Nyxus::Feature2D::IMOM_RM_21][0] = m21; + fvals[(int)Nyxus::Feature2D::IMOM_RM_22][0] = m22; + fvals[(int)Nyxus::Feature2D::IMOM_RM_23][0] = m23; + fvals[(int)Nyxus::Feature2D::IMOM_RM_30][0] = m30; + + fvals[(int)Nyxus::Feature2D::IMOM_WRM_00][0] = wm00; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_01][0] = wm01; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_02][0] = wm02; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_03][0] = wm03; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_10][0] = wm10; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_11][0] = wm11; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_12][0] = wm12; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_20][0] = wm20; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_21][0] = wm21; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_30][0] = wm30; + + fvals[(int)Nyxus::Feature2D::IMOM_CM_00][0] = mu00; + fvals[(int)Nyxus::Feature2D::IMOM_CM_01][0] = mu01; + fvals[(int)Nyxus::Feature2D::IMOM_CM_02][0] = mu02; + fvals[(int)Nyxus::Feature2D::IMOM_CM_03][0] = mu03; + fvals[(int)Nyxus::Feature2D::IMOM_CM_10][0] = mu10; + fvals[(int)Nyxus::Feature2D::IMOM_CM_11][0] = mu11; + fvals[(int)Nyxus::Feature2D::IMOM_CM_12][0] = mu12; + fvals[(int)Nyxus::Feature2D::IMOM_CM_13][0] = mu13; + fvals[(int)Nyxus::Feature2D::IMOM_CM_20][0] = mu20; + fvals[(int)Nyxus::Feature2D::IMOM_CM_21][0] = mu21; + fvals[(int)Nyxus::Feature2D::IMOM_CM_22][0] = mu22; + fvals[(int)Nyxus::Feature2D::IMOM_CM_23][0] = mu23; + fvals[(int)Nyxus::Feature2D::IMOM_CM_30][0] = mu30; + fvals[(int)Nyxus::Feature2D::IMOM_CM_31][0] = mu31; + fvals[(int)Nyxus::Feature2D::IMOM_CM_32][0] = mu32; + fvals[(int)Nyxus::Feature2D::IMOM_CM_33][0] = mu33; + + fvals[(int)Nyxus::Feature2D::IMOM_WCM_02][0] = wmu02; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_03][0] = wmu03; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_11][0] = wmu11; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_12][0] = wmu12; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_20][0] = wmu20; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_21][0] = wmu21; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_30][0] = wmu30; + + fvals[(int)Nyxus::Feature2D::IMOM_NCM_02][0] = nu02; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_03][0] = nu03; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_11][0] = nu11; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_12][0] = nu12; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_20][0] = nu20; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_21][0] = nu21; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_30][0] = nu30; + + fvals[(int)Nyxus::Feature2D::IMOM_NRM_00][0] = w00; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_01][0] = w01; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_02][0] = w02; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_03][0] = w03; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_10][0] = w10; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_11][0] = w11; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_12][0] = w12; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_13][0] = w13; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_20][0] = w20; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_21][0] = w21; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_22][0] = w22; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_23][0] = w23; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_30][0] = w30; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_31][0] = w31; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_32][0] = w32; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_33][0] = w33; + + fvals[(int)Nyxus::Feature2D::IMOM_HU1][0] = hm1; + fvals[(int)Nyxus::Feature2D::IMOM_HU2][0] = hm2; + fvals[(int)Nyxus::Feature2D::IMOM_HU3][0] = hm3; + fvals[(int)Nyxus::Feature2D::IMOM_HU4][0] = hm4; + fvals[(int)Nyxus::Feature2D::IMOM_HU5][0] = hm5; + fvals[(int)Nyxus::Feature2D::IMOM_HU6][0] = hm6; + fvals[(int)Nyxus::Feature2D::IMOM_HU7][0] = hm7; + + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_02][0] = wncm02; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_03][0] = wncm03; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_11][0] = wncm11; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_12][0] = wncm12; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_20][0] = wncm20; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_21][0] = wncm21; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_30][0] = wncm30; + + fvals[(int)Nyxus::Feature2D::IMOM_WHU1][0] = whm1; + fvals[(int)Nyxus::Feature2D::IMOM_WHU2][0] = whm2; + fvals[(int)Nyxus::Feature2D::IMOM_WHU3][0] = whm3; + fvals[(int)Nyxus::Feature2D::IMOM_WHU4][0] = whm4; + fvals[(int)Nyxus::Feature2D::IMOM_WHU5][0] = whm5; + fvals[(int)Nyxus::Feature2D::IMOM_WHU6][0] = whm6; + fvals[(int)Nyxus::Feature2D::IMOM_WHU7][0] = whm7; +} + +#ifdef USE_GPU + +void Imoms2D_feature::gpu_process_all_rois( + const std::vector& Labels, + std::unordered_map & RoiData, + size_t batch_offset, + size_t batch_len) +{ + for (auto i = 0; i < batch_len; i++) + { + size_t far_i = i + batch_offset; + auto lab = Labels[far_i]; + LR& r = RoiData[lab]; + + // Calculate features + Imoms2D_feature f; + f.calculate_via_gpu(r, i); + + //---delayed until we process all the ROIs on GPU-side---> imf.save_value (r.fvals); + + // Pull the result from GPU cache and save it + if (!NyxusGpu::gpu_featurestatebuf.download()) + { + std::cerr << "error in " << __FILE__ << ":" << __LINE__ << "\n"; + return; + } + + save_values_from_gpu_buffer (RoiData, Labels, NyxusGpu::gpu_featurestatebuf, batch_offset, batch_len); + } +} + +void Imoms2D_feature::calculate_via_gpu(LR& r, size_t roi_idx) +{ + bool ok = NyxusGpu::GeoMoments2D_calculate(roi_idx, false); + if (!ok) + std::cerr << "Geometric moments: error calculating features on GPU\n"; +} + +void Imoms2D_feature::save_values_from_gpu_buffer( + std::unordered_map & roidata, + const std::vector& roilabels, + const GpuCache& intermediate_already_hostside, + size_t batch_offset, + size_t batch_len) +{ + for (size_t i = 0; i < batch_len; i++) + { + size_t roiidx = batch_offset + i; + auto lbl = roilabels[roiidx]; + LR& roi = roidata[lbl]; + auto& fvals = roi.fvals; + + size_t offs = i * GpusideState::__COUNT__; + const gpureal* ptrBuf = &intermediate_already_hostside.hobuffer[offs]; + + fvals[(int)Nyxus::Feature2D::IMOM_RM_00][0] = ptrBuf[GpusideState::RM00]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_01][0] = ptrBuf[GpusideState::RM01]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_02][0] = ptrBuf[GpusideState::RM02]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_03][0] = ptrBuf[GpusideState::RM03]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_10][0] = ptrBuf[GpusideState::RM10]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_11][0] = ptrBuf[GpusideState::RM11]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_12][0] = ptrBuf[GpusideState::RM12]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_13][0] = ptrBuf[GpusideState::RM13]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_20][0] = ptrBuf[GpusideState::RM20]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_21][0] = ptrBuf[GpusideState::RM21]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_22][0] = ptrBuf[GpusideState::RM22]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_23][0] = ptrBuf[GpusideState::RM23]; + fvals[(int)Nyxus::Feature2D::IMOM_RM_30][0] = ptrBuf[GpusideState::RM30]; + + fvals[(int)Nyxus::Feature2D::IMOM_CM_00][0] = ptrBuf[GpusideState::CM00]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_01][0] = ptrBuf[GpusideState::CM01]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_02][0] = ptrBuf[GpusideState::CM02]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_03][0] = ptrBuf[GpusideState::CM03]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_10][0] = ptrBuf[GpusideState::CM10]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_11][0] = ptrBuf[GpusideState::CM11]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_12][0] = ptrBuf[GpusideState::CM12]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_13][0] = ptrBuf[GpusideState::CM13]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_20][0] = ptrBuf[GpusideState::CM20]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_21][0] = ptrBuf[GpusideState::CM21]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_22][0] = ptrBuf[GpusideState::CM22]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_23][0] = ptrBuf[GpusideState::CM23]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_30][0] = ptrBuf[GpusideState::CM30]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_31][0] = ptrBuf[GpusideState::CM31]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_32][0] = ptrBuf[GpusideState::CM32]; + fvals[(int)Nyxus::Feature2D::IMOM_CM_33][0] = ptrBuf[GpusideState::CM33]; + + fvals[(int)Nyxus::Feature2D::IMOM_NRM_00][0] = ptrBuf[GpusideState::W00]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_01][0] = ptrBuf[GpusideState::W01]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_02][0] = ptrBuf[GpusideState::W02]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_03][0] = ptrBuf[GpusideState::W03]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_10][0] = ptrBuf[GpusideState::W10]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_11][0] = ptrBuf[GpusideState::W11]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_12][0] = ptrBuf[GpusideState::W12]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_13][0] = ptrBuf[GpusideState::W13]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_20][0] = ptrBuf[GpusideState::W20]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_21][0] = ptrBuf[GpusideState::W21]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_22][0] = ptrBuf[GpusideState::W22]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_23][0] = ptrBuf[GpusideState::W23]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_30][0] = ptrBuf[GpusideState::W30]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_31][0] = ptrBuf[GpusideState::W31]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_32][0] = ptrBuf[GpusideState::W32]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_33][0] = ptrBuf[GpusideState::W33]; + + fvals[(int)Nyxus::Feature2D::IMOM_NCM_02][0] = ptrBuf[GpusideState::NU02]; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_03][0] = ptrBuf[GpusideState::NU03]; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_11][0] = ptrBuf[GpusideState::NU11]; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_12][0] = ptrBuf[GpusideState::NU12]; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_20][0] = ptrBuf[GpusideState::NU20]; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_21][0] = ptrBuf[GpusideState::NU21]; + fvals[(int)Nyxus::Feature2D::IMOM_NCM_30][0] = ptrBuf[GpusideState::NU30]; + + fvals[(int)Nyxus::Feature2D::IMOM_HU1][0] = ptrBuf[GpusideState::H1]; + fvals[(int)Nyxus::Feature2D::IMOM_HU2][0] = ptrBuf[GpusideState::H2]; + fvals[(int)Nyxus::Feature2D::IMOM_HU3][0] = ptrBuf[GpusideState::H3]; + fvals[(int)Nyxus::Feature2D::IMOM_HU4][0] = ptrBuf[GpusideState::H4]; + fvals[(int)Nyxus::Feature2D::IMOM_HU5][0] = ptrBuf[GpusideState::H5]; + fvals[(int)Nyxus::Feature2D::IMOM_HU6][0] = ptrBuf[GpusideState::H6]; + fvals[(int)Nyxus::Feature2D::IMOM_HU7][0] = ptrBuf[GpusideState::H7]; + + fvals[(int)Nyxus::Feature2D::IMOM_WRM_00][0] = ptrBuf[GpusideState::WRM00]; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_01][0] = ptrBuf[GpusideState::WRM01]; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_02][0] = ptrBuf[GpusideState::WRM02]; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_03][0] = ptrBuf[GpusideState::WRM03]; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_10][0] = ptrBuf[GpusideState::WRM10]; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_11][0] = ptrBuf[GpusideState::WRM11]; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_12][0] = ptrBuf[GpusideState::WRM12]; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_20][0] = ptrBuf[GpusideState::WRM20]; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_21][0] = ptrBuf[GpusideState::WRM21]; + fvals[(int)Nyxus::Feature2D::IMOM_WRM_30][0] = ptrBuf[GpusideState::WRM30]; + + fvals[(int)Nyxus::Feature2D::IMOM_WCM_02][0] = ptrBuf[GpusideState::WCM02]; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_03][0] = ptrBuf[GpusideState::WCM03]; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_11][0] = ptrBuf[GpusideState::WCM11]; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_12][0] = ptrBuf[GpusideState::WCM12]; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_20][0] = ptrBuf[GpusideState::WCM20]; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_21][0] = ptrBuf[GpusideState::WCM21]; + fvals[(int)Nyxus::Feature2D::IMOM_WCM_30][0] = ptrBuf[GpusideState::WCM30]; + + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_02][0] = ptrBuf[GpusideState::WNU02]; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_03][0] = ptrBuf[GpusideState::WNU03]; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_11][0] = ptrBuf[GpusideState::WNU11]; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_12][0] = ptrBuf[GpusideState::WNU12]; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_20][0] = ptrBuf[GpusideState::WNU20]; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_21][0] = ptrBuf[GpusideState::WNU21]; + fvals[(int)Nyxus::Feature2D::IMOM_WNCM_30][0] = ptrBuf[GpusideState::WNU30]; + + fvals[(int)Nyxus::Feature2D::IMOM_WHU1][0] = ptrBuf[GpusideState::WH1]; + fvals[(int)Nyxus::Feature2D::IMOM_WHU2][0] = ptrBuf[GpusideState::WH2]; + fvals[(int)Nyxus::Feature2D::IMOM_WHU3][0] = ptrBuf[GpusideState::WH3]; + fvals[(int)Nyxus::Feature2D::IMOM_WHU4][0] = ptrBuf[GpusideState::WH4]; + fvals[(int)Nyxus::Feature2D::IMOM_WHU5][0] = ptrBuf[GpusideState::WH5]; + fvals[(int)Nyxus::Feature2D::IMOM_WHU6][0] = ptrBuf[GpusideState::WH6]; + fvals[(int)Nyxus::Feature2D::IMOM_WHU7][0] = ptrBuf[GpusideState::WH7]; + } +} + +#endif + + + +//********************** s-moms + +Smoms2D_feature::Smoms2D_feature() : FeatureMethod("Smoms2D") +{ + provide_features(Smoms2D_feature::featureset); + add_dependencies({ Nyxus::Feature2D::PERIMETER }); +} + +void Smoms2D_feature::calculate(LR& r) +{ + BasicGeomoms2D::calculate(r, intenAsShape); +} + +void Smoms2D_feature::osized_add_online_pixel(size_t x, size_t y, uint32_t intensity) +{ + BasicGeomoms2D::osized_add_online_pixel(x, y, intensity); +} + +void Smoms2D_feature::osized_calculate(LR& r, ImageLoader& imloader) +{ + BasicGeomoms2D::osized_calculate(r, imloader); +} + +void Smoms2D_feature::parallel_process_1_batch(size_t start, size_t end, std::vector* ptrLabels, std::unordered_map * ptrLabelData) +{ + for (auto i = start; i < end; i++) + { + int lab = (*ptrLabels)[i]; + LR& r = (*ptrLabelData)[lab]; + + if (r.has_bad_data()) + continue; + + Smoms2D_feature f; + f.calculate(r); + f.save_value(r.fvals); + } +} + +void Smoms2D_feature::save_value(std::vector>& fvals) +{ + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_00][0] = m00; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_01][0] = m01; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_02][0] = m02; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_03][0] = m03; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_10][0] = m10; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_11][0] = m11; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_12][0] = m12; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_13][0] = m13; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_20][0] = m20; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_21][0] = m21; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_22][0] = m22; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_23][0] = m23; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_30][0] = m30; + + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_00][0] = wm00; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_01][0] = wm01; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_02][0] = wm02; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_03][0] = wm03; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_10][0] = wm10; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_11][0] = wm11; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_12][0] = wm12; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_20][0] = wm20; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_21][0] = wm21; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_30][0] = wm30; + + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_00][0] = mu00; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_01][0] = mu01; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_02][0] = mu02; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_03][0] = mu03; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_10][0] = mu10; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_11][0] = mu11; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_12][0] = mu12; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_13][0] = mu13; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_20][0] = mu20; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_21][0] = mu21; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_22][0] = mu22; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_23][0] = mu23; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_30][0] = mu30; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_31][0] = mu31; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_32][0] = mu32; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_33][0] = mu33; + + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_02][0] = wmu02; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_03][0] = wmu03; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_11][0] = wmu11; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_12][0] = wmu12; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_20][0] = wmu20; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_21][0] = wmu21; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_30][0] = wmu30; + + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_02][0] = nu02; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_03][0] = nu03; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_11][0] = nu11; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_12][0] = nu12; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_20][0] = nu20; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_21][0] = nu21; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_30][0] = nu30; + + fvals[(int)Nyxus::Feature2D::IMOM_NRM_00][0] = w00; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_01][0] = w01; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_02][0] = w02; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_03][0] = w03; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_10][0] = w10; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_11][0] = w11; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_12][0] = w12; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_13][0] = w13; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_20][0] = w20; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_21][0] = w21; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_22][0] = w22; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_23][0] = w23; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_30][0] = w30; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_31][0] = w31; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_32][0] = w32; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_33][0] = w33; + + fvals[(int)Nyxus::Feature2D::HU_M1][0] = hm1; + fvals[(int)Nyxus::Feature2D::HU_M2][0] = hm2; + fvals[(int)Nyxus::Feature2D::HU_M3][0] = hm3; + fvals[(int)Nyxus::Feature2D::HU_M4][0] = hm4; + fvals[(int)Nyxus::Feature2D::HU_M5][0] = hm5; + fvals[(int)Nyxus::Feature2D::HU_M6][0] = hm6; + fvals[(int)Nyxus::Feature2D::HU_M7][0] = hm7; + + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_02][0] = wncm02; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_03][0] = wncm03; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_11][0] = wncm11; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_12][0] = wncm12; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_20][0] = wncm20; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_21][0] = wncm21; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_30][0] = wncm30; + + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M1][0] = whm1; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M2][0] = whm2; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M3][0] = whm3; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M4][0] = whm4; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M5][0] = whm5; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M6][0] = whm6; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M7][0] = whm7; +} + +#ifdef USE_GPU + +void Smoms2D_feature::gpu_process_all_rois( + const std::vector& Labels, + std::unordered_map & RoiData, + size_t batch_offset, + size_t batch_len) +{ + for (auto i = 0; i < batch_len; i++) + { + size_t far_i = i + batch_offset; + auto lab = Labels[far_i]; + LR& r = RoiData[lab]; + + // Calculate features + Smoms2D_feature f; + f.calculate_via_gpu(r, i); + + //---delayed until we process all the ROIs on GPU-side---> imf.save_value (r.fvals); + + // Pull the result from GPU cache and save it + if (!NyxusGpu::gpu_featurestatebuf.download()) + { + std::cerr << "error in " << __FILE__ << ":" << __LINE__ << "\n"; + return; + } + + save_values_from_gpu_buffer(RoiData, Labels, NyxusGpu::gpu_featurestatebuf, batch_offset, batch_len); + } +} + +void Smoms2D_feature::calculate_via_gpu(LR& r, size_t roi_idx) +{ + bool ok = NyxusGpu::GeoMoments2D_calculate(roi_idx, true); + if (!ok) + std::cerr << "Geometric moments: error calculating features on GPU\n"; +} + +void Smoms2D_feature::save_values_from_gpu_buffer( + std::unordered_map & roidata, + const std::vector& roilabels, + const GpuCache& intermediate_already_hostside, + size_t batch_offset, + size_t batch_len) +{ + for (size_t i = 0; i < batch_len; i++) + { + size_t roiidx = batch_offset + i; + auto lbl = roilabels[roiidx]; + LR& roi = roidata[lbl]; + auto& fvals = roi.fvals; + + size_t offs = i * GpusideState::__COUNT__; + const gpureal* ptrBuf = &intermediate_already_hostside.hobuffer[offs]; + + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_00][0] = ptrBuf[GpusideState::RM00]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_01][0] = ptrBuf[GpusideState::RM01]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_02][0] = ptrBuf[GpusideState::RM02]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_03][0] = ptrBuf[GpusideState::RM03]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_10][0] = ptrBuf[GpusideState::RM10]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_11][0] = ptrBuf[GpusideState::RM11]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_12][0] = ptrBuf[GpusideState::RM12]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_13][0] = ptrBuf[GpusideState::RM13]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_20][0] = ptrBuf[GpusideState::RM20]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_21][0] = ptrBuf[GpusideState::RM21]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_22][0] = ptrBuf[GpusideState::RM22]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_23][0] = ptrBuf[GpusideState::RM23]; + fvals[(int)Nyxus::Feature2D::SPAT_MOMENT_30][0] = ptrBuf[GpusideState::RM30]; + + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_00][0] = ptrBuf[GpusideState::CM00]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_01][0] = ptrBuf[GpusideState::CM01]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_02][0] = ptrBuf[GpusideState::CM02]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_03][0] = ptrBuf[GpusideState::CM03]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_10][0] = ptrBuf[GpusideState::CM10]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_11][0] = ptrBuf[GpusideState::CM11]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_12][0] = ptrBuf[GpusideState::CM12]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_13][0] = ptrBuf[GpusideState::CM13]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_20][0] = ptrBuf[GpusideState::CM20]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_21][0] = ptrBuf[GpusideState::CM21]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_22][0] = ptrBuf[GpusideState::CM22]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_23][0] = ptrBuf[GpusideState::CM23]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_30][0] = ptrBuf[GpusideState::CM30]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_31][0] = ptrBuf[GpusideState::CM31]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_32][0] = ptrBuf[GpusideState::CM32]; + fvals[(int)Nyxus::Feature2D::CENTRAL_MOMENT_33][0] = ptrBuf[GpusideState::CM33]; + + fvals[(int)Nyxus::Feature2D::IMOM_NRM_00][0] = ptrBuf[GpusideState::W00]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_01][0] = ptrBuf[GpusideState::W01]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_02][0] = ptrBuf[GpusideState::W02]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_03][0] = ptrBuf[GpusideState::W03]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_10][0] = ptrBuf[GpusideState::W10]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_11][0] = ptrBuf[GpusideState::W11]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_12][0] = ptrBuf[GpusideState::W12]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_13][0] = ptrBuf[GpusideState::W13]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_20][0] = ptrBuf[GpusideState::W20]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_21][0] = ptrBuf[GpusideState::W21]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_22][0] = ptrBuf[GpusideState::W22]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_23][0] = ptrBuf[GpusideState::W23]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_30][0] = ptrBuf[GpusideState::W30]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_31][0] = ptrBuf[GpusideState::W31]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_32][0] = ptrBuf[GpusideState::W32]; + fvals[(int)Nyxus::Feature2D::IMOM_NRM_33][0] = ptrBuf[GpusideState::W33]; + + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_02][0] = ptrBuf[GpusideState::NU02]; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_03][0] = ptrBuf[GpusideState::NU03]; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_11][0] = ptrBuf[GpusideState::NU11]; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_12][0] = ptrBuf[GpusideState::NU12]; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_20][0] = ptrBuf[GpusideState::NU20]; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_21][0] = ptrBuf[GpusideState::NU21]; + fvals[(int)Nyxus::Feature2D::NORM_CENTRAL_MOMENT_30][0] = ptrBuf[GpusideState::NU30]; + + fvals[(int)Nyxus::Feature2D::HU_M1][0] = ptrBuf[GpusideState::H1]; + fvals[(int)Nyxus::Feature2D::HU_M2][0] = ptrBuf[GpusideState::H2]; + fvals[(int)Nyxus::Feature2D::HU_M3][0] = ptrBuf[GpusideState::H3]; + fvals[(int)Nyxus::Feature2D::HU_M4][0] = ptrBuf[GpusideState::H4]; + fvals[(int)Nyxus::Feature2D::HU_M5][0] = ptrBuf[GpusideState::H5]; + fvals[(int)Nyxus::Feature2D::HU_M6][0] = ptrBuf[GpusideState::H6]; + fvals[(int)Nyxus::Feature2D::HU_M7][0] = ptrBuf[GpusideState::H7]; + + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_00][0] = ptrBuf[GpusideState::WRM00]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_01][0] = ptrBuf[GpusideState::WRM01]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_02][0] = ptrBuf[GpusideState::WRM02]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_03][0] = ptrBuf[GpusideState::WRM03]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_10][0] = ptrBuf[GpusideState::WRM10]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_11][0] = ptrBuf[GpusideState::WRM11]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_12][0] = ptrBuf[GpusideState::WRM12]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_20][0] = ptrBuf[GpusideState::WRM20]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_21][0] = ptrBuf[GpusideState::WRM21]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_30][0] = ptrBuf[GpusideState::WRM30]; + + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_02][0] = ptrBuf[GpusideState::WCM02]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_03][0] = ptrBuf[GpusideState::WCM03]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_11][0] = ptrBuf[GpusideState::WCM11]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_12][0] = ptrBuf[GpusideState::WCM12]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_20][0] = ptrBuf[GpusideState::WCM20]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_21][0] = ptrBuf[GpusideState::WCM21]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_30][0] = ptrBuf[GpusideState::WCM30]; + + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_02][0] = ptrBuf[GpusideState::WNU02]; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_03][0] = ptrBuf[GpusideState::WNU03]; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_11][0] = ptrBuf[GpusideState::WNU11]; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_12][0] = ptrBuf[GpusideState::WNU12]; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_20][0] = ptrBuf[GpusideState::WNU20]; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_21][0] = ptrBuf[GpusideState::WNU21]; + fvals[(int)Nyxus::Feature2D::WT_NORM_CTR_MOM_30][0] = ptrBuf[GpusideState::WNU30]; + + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M1][0] = ptrBuf[GpusideState::WH1]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M2][0] = ptrBuf[GpusideState::WH2]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M3][0] = ptrBuf[GpusideState::WH3]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M4][0] = ptrBuf[GpusideState::WH4]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M5][0] = ptrBuf[GpusideState::WH5]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M6][0] = ptrBuf[GpusideState::WH6]; + fvals[(int)Nyxus::Feature2D::WEIGHTED_HU_M7][0] = ptrBuf[GpusideState::WH7]; + } +} + +#endif + + diff --git a/src/nyx/features/2d_geomoments.h b/src/nyx/features/2d_geomoments.h new file mode 100644 index 00000000..a251afd3 --- /dev/null +++ b/src/nyx/features/2d_geomoments.h @@ -0,0 +1,400 @@ +#pragma once + +#pragma once + +#include +#include "../roi_cache.h" +#include "contour.h" +#include "image_matrix.h" +#include "../feature_method.h" + +// Inspired by Yavuz Unver +// +// Hu Moments and Digit Recognition Algorithm: +// http://www.wseas.us/e-library/conferences/2013/CambridgeUK/AISE/AISE-15.pdf +// + +using pixcloud = std::vector ; // cloud of pixels +using reintenvec = std::vector ; // cloud of pixel intensities +using pixcloud_NT = OutOfRamPixelCloud; + +typedef double (*intenfunction) (double inten); + +template +class GpuCache; + +class BasicGeomoms2D +{ +public: + + void calculate(LR& r, intenfunction ifun); + void osized_add_online_pixel(size_t x, size_t y, uint32_t intensity) {} // Not supporting online for image moments + void osized_calculate(LR& r, ImageLoader& imloader); + +protected: + + StatsInt baseX = 0, baseY = 0; // cached min X and Y of the ROI. Reason - Pixel2's X and Y are absolute so we need to make them relative. Must be set in calculate() prior to calculating any 2D moment + double originOfX = 0, originOfY = 0; // centroids + double m00 = 0, m01 = 0, m02 = 0, m03 = 0, m10 = 0, m11 = 0, m12 = 0, m13 = 0, m20 = 0, m21 = 0, m22 = 0, m23 = 0, m30 = 0; // spatial moments + double wm00 = 0, wm01 = 0, wm02 = 0, wm03 = 0, wm10 = 0, wm11 = 0, wm12 = 0, wm20 = 0, wm21 = 0, wm30 = 0; // weighted spatial moments + double w00 = 0, w01 = 0, w02 = 0, w03 = 0, w10 = 0, w11 = 0, w12 = 0, w13 = 0, w20 = 0, w21 = 0, w22 = 0, w23 = 0, w30 = 0, w31 = 0, w32 = 0, w33 = 0; // normalized spatial moments + double nu02 = 0, nu03 = 0, nu11 = 0, nu12 = 0, nu20 = 0, nu21 = 0, nu30 = 0; // normalized central moments + double mu00 = 0, mu01 = 0, mu02 = 0, mu03 = 0, mu10 = 0, mu11 = 0, mu12 = 0, mu13 = 0, mu20 = 0, mu21 = 0, mu22 = 0, mu23 = 0, mu30 = 0, mu31 = 0, mu32 = 0, mu33 = 0; // central moments + double wmu02 = 0, wmu03 = 0, wmu11 = 0, wmu12 = 0, wmu20 = 0, wmu21 = 0, wmu30 = 0; // weighted central moments + double hm1 = 0, hm2 = 0, hm3 = 0, hm4 = 0, hm5 = 0, hm6 = 0, hm7 = 0; // Hu invariants + double wncm02 = 0, wncm03 = 0, wncm11 = 0, wncm12 = 0, wncm20 = 0, wncm21 = 0, wncm30 = 0; // weighted normalized central moments + double whm1 = 0, whm2 = 0, whm3 = 0, whm4 = 0, whm5 = 0, whm6 = 0, whm7 = 0; // weighted Hu invariants + + const double weighting_epsilon = 0.001; + + // function that filters a pixel intensity for use by a shape or intensity moment + intenfunction INTEN; + + // trivial ROI + double moment(const pixcloud& cloud, int p, int q); + double moment(const pixcloud& cloud, const reintenvec& real_intens, int p, int q); + void calcOrigins(const pixcloud& cloud); + void calcOrigins(const pixcloud& cloud, const reintenvec& real_valued_intensities); + double centralMom(const pixcloud& c, int p, int q); + double centralMom(const pixcloud& c, const reintenvec& realintens, int p, int q); + double normRawMom(const pixcloud& cloud, int p, int q); + double normCentralMom(const pixcloud& c, int p, int q); + double normCentralMom(const pixcloud& cloud, const reintenvec& realintens, int p, int q); + std::tuple calcHu_imp(double _02, double _03, double _11, double _12, double _20, double _21, double _30); + void calcRawMoments(const pixcloud& cloud); + void calcNormRawMoments(const pixcloud& cloud); + void calcNormCentralMoments(const pixcloud& cloud); + void calcWeightedRawMoments(const pixcloud& cloud, const reintenvec& real_valued_intensities); + void calcCentralMoments(const pixcloud& cloud); + void calcWeightedCentralMoments(const pixcloud& cloud, const reintenvec& real_valued_intensities); + void calcWeightedNormCentralMoms(const pixcloud& cloud, const reintenvec& realintens); + void calcHuInvariants(const pixcloud& cloud); + void calcWeightedHuInvariants(const pixcloud& cloud, const reintenvec& real_valued_intensities); + + // Non-trivial ROI + double moment(const pixcloud_NT& cloud, int p, int q); + void calcOrigins(const pixcloud_NT& cloud); + double centralMom(const pixcloud_NT& c, int p, int q); + double normRawMom(const pixcloud_NT& cloud, int p, int q); + double normCentralMom(const pixcloud_NT& c, int p, int q); + std::tuple calcHuInvariants_imp(const pixcloud_NT& cloud); + void calcRawMoments(const pixcloud_NT& cloud); + void calcNormRawMoments(const pixcloud_NT& cloud); + void calcNormCentralMoments(const pixcloud_NT& cloud); + void calcWeightedRawMoments(const pixcloud_NT& cloud); + void calcCentralMoments(const pixcloud_NT& cloud); + void calcWeightedCentralMoments(const pixcloud_NT& cloud); + void calcHuInvariants(const pixcloud_NT& cloud); + void calcWeightedHuInvariants(const pixcloud_NT& cloud); +}; + +// 2D intensity geometric features +class Imoms2D_feature : public BasicGeomoms2D, public FeatureMethod +{ +public: + + const constexpr static std::initializer_list featureset = + { + // -- intensity raw moments + Nyxus::Feature2D::IMOM_RM_00, + Nyxus::Feature2D::IMOM_RM_01, + Nyxus::Feature2D::IMOM_RM_02, + Nyxus::Feature2D::IMOM_RM_03, + Nyxus::Feature2D::IMOM_RM_10, + Nyxus::Feature2D::IMOM_RM_11, + Nyxus::Feature2D::IMOM_RM_12, + Nyxus::Feature2D::IMOM_RM_13, + Nyxus::Feature2D::IMOM_RM_20, + Nyxus::Feature2D::IMOM_RM_21, + Nyxus::Feature2D::IMOM_RM_22, + Nyxus::Feature2D::IMOM_RM_23, + Nyxus::Feature2D::IMOM_RM_30, + + // -- intensity central moments + Nyxus::Feature2D::IMOM_CM_00, + Nyxus::Feature2D::IMOM_CM_01, + Nyxus::Feature2D::IMOM_CM_02, + Nyxus::Feature2D::IMOM_CM_03, + Nyxus::Feature2D::IMOM_CM_10, + Nyxus::Feature2D::IMOM_CM_11, + Nyxus::Feature2D::IMOM_CM_12, + Nyxus::Feature2D::IMOM_CM_13, + Nyxus::Feature2D::IMOM_CM_20, + Nyxus::Feature2D::IMOM_CM_21, + Nyxus::Feature2D::IMOM_CM_22, + Nyxus::Feature2D::IMOM_CM_23, + Nyxus::Feature2D::IMOM_CM_30, + Nyxus::Feature2D::IMOM_CM_31, + Nyxus::Feature2D::IMOM_CM_32, + Nyxus::Feature2D::IMOM_CM_33, + + // -- intensity normalized raw moments + Nyxus::Feature2D::IMOM_NRM_00, + Nyxus::Feature2D::IMOM_NRM_01, + Nyxus::Feature2D::IMOM_NRM_02, + Nyxus::Feature2D::IMOM_NRM_03, + Nyxus::Feature2D::IMOM_NRM_10, + Nyxus::Feature2D::IMOM_NRM_11, + Nyxus::Feature2D::IMOM_NRM_12, + Nyxus::Feature2D::IMOM_NRM_13, + Nyxus::Feature2D::IMOM_NRM_20, + Nyxus::Feature2D::IMOM_NRM_21, + Nyxus::Feature2D::IMOM_NRM_22, + Nyxus::Feature2D::IMOM_NRM_23, + Nyxus::Feature2D::IMOM_NRM_30, + Nyxus::Feature2D::IMOM_NRM_31, + Nyxus::Feature2D::IMOM_NRM_32, + Nyxus::Feature2D::IMOM_NRM_33, + + // -- intensity normalized central moments + Nyxus::Feature2D::IMOM_NCM_02, + Nyxus::Feature2D::IMOM_NCM_03, + Nyxus::Feature2D::IMOM_NCM_11, + Nyxus::Feature2D::IMOM_NCM_12, + Nyxus::Feature2D::IMOM_NCM_20, + Nyxus::Feature2D::IMOM_NCM_21, + Nyxus::Feature2D::IMOM_NCM_30, + + // -- intensity Hu's moments 1-7 + Nyxus::Feature2D::IMOM_HU1, + Nyxus::Feature2D::IMOM_HU2, + Nyxus::Feature2D::IMOM_HU3, + Nyxus::Feature2D::IMOM_HU4, + Nyxus::Feature2D::IMOM_HU5, + Nyxus::Feature2D::IMOM_HU6, + Nyxus::Feature2D::IMOM_HU7, + + // -- intensity weighted raw moments + Nyxus::Feature2D::IMOM_WRM_00, + Nyxus::Feature2D::IMOM_WRM_01, + Nyxus::Feature2D::IMOM_WRM_02, + Nyxus::Feature2D::IMOM_WRM_03, + Nyxus::Feature2D::IMOM_WRM_10, + Nyxus::Feature2D::IMOM_WRM_11, + Nyxus::Feature2D::IMOM_WRM_12, + Nyxus::Feature2D::IMOM_WRM_20, + Nyxus::Feature2D::IMOM_WRM_21, + Nyxus::Feature2D::IMOM_WRM_30, + + // -- intensity weighted central moments + Nyxus::Feature2D::IMOM_WCM_02, + Nyxus::Feature2D::IMOM_WCM_03, + Nyxus::Feature2D::IMOM_WCM_11, + Nyxus::Feature2D::IMOM_WCM_12, + Nyxus::Feature2D::IMOM_WCM_20, + Nyxus::Feature2D::IMOM_WCM_21, + Nyxus::Feature2D::IMOM_WCM_30, + + // -- intensity weighted normalized central moments + Nyxus::Feature2D::IMOM_WNCM_02, + Nyxus::Feature2D::IMOM_WNCM_03, + Nyxus::Feature2D::IMOM_WNCM_11, + Nyxus::Feature2D::IMOM_WNCM_12, + Nyxus::Feature2D::IMOM_WNCM_20, + Nyxus::Feature2D::IMOM_WNCM_21, + Nyxus::Feature2D::IMOM_WNCM_30, + + // -- intensity weighted Hu's moments 1-7 + Nyxus::Feature2D::IMOM_WHU1, + Nyxus::Feature2D::IMOM_WHU2, + Nyxus::Feature2D::IMOM_WHU3, + Nyxus::Feature2D::IMOM_WHU4, + Nyxus::Feature2D::IMOM_WHU5, + Nyxus::Feature2D::IMOM_WHU6, + Nyxus::Feature2D::IMOM_WHU7 + }; + + Imoms2D_feature(); + void calculate(LR& r); + void osized_add_online_pixel(size_t x, size_t y, uint32_t intensity); + void osized_calculate(LR& r, ImageLoader& imloader); + void save_value(std::vector>& feature_vals); + static void parallel_process_1_batch(size_t start, size_t end, std::vector* ptrLabels, std::unordered_map * ptrLabelData); + +#ifdef USE_GPU + static void gpu_process_all_rois(const std::vector& ptrLabels, std::unordered_map & ptrLabelData, size_t batch_offset, size_t batch_len); + void calculate_via_gpu(LR& r, size_t roi_index); + static void save_values_from_gpu_buffer ( + std::unordered_map & roidata, + const std::vector& roilabels, + const GpuCache& intermediate_already_hostside, + size_t batch_offset, + size_t batch_len); +#endif + + static bool required(const FeatureSet & fs) { return fs.anyEnabled(Imoms2D_feature::featureset); } // compatibility with manual reduce + +private: + + static inline double intenAsInten(double a) { return a; }; +}; + +// 2D shape geometric features +class Smoms2D_feature : public BasicGeomoms2D, public FeatureMethod +{ +public: + + const constexpr static std::initializer_list featureset = + { + // Spatial (raw) moments + Nyxus::Feature2D::SPAT_MOMENT_00, + Nyxus::Feature2D::SPAT_MOMENT_01, + Nyxus::Feature2D::SPAT_MOMENT_02, + Nyxus::Feature2D::SPAT_MOMENT_03, + Nyxus::Feature2D::SPAT_MOMENT_10, + Nyxus::Feature2D::SPAT_MOMENT_11, + Nyxus::Feature2D::SPAT_MOMENT_12, + Nyxus::Feature2D::SPAT_MOMENT_13, + Nyxus::Feature2D::SPAT_MOMENT_20, + Nyxus::Feature2D::SPAT_MOMENT_21, + Nyxus::Feature2D::SPAT_MOMENT_22, + Nyxus::Feature2D::SPAT_MOMENT_23, + Nyxus::Feature2D::SPAT_MOMENT_30, + + // Weighted spatial moments + Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_00, + Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_01, + Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_02, + Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_03, + Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_10, + Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_11, + Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_12, + Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_20, + Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_21, + Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_30, + + // Central moments + Nyxus::Feature2D::CENTRAL_MOMENT_00, + Nyxus::Feature2D::CENTRAL_MOMENT_01, + Nyxus::Feature2D::CENTRAL_MOMENT_02, + Nyxus::Feature2D::CENTRAL_MOMENT_03, + Nyxus::Feature2D::CENTRAL_MOMENT_10, + Nyxus::Feature2D::CENTRAL_MOMENT_11, + Nyxus::Feature2D::CENTRAL_MOMENT_12, + Nyxus::Feature2D::CENTRAL_MOMENT_13, + Nyxus::Feature2D::CENTRAL_MOMENT_20, + Nyxus::Feature2D::CENTRAL_MOMENT_21, + Nyxus::Feature2D::CENTRAL_MOMENT_22, + Nyxus::Feature2D::CENTRAL_MOMENT_23, + Nyxus::Feature2D::CENTRAL_MOMENT_30, + Nyxus::Feature2D::CENTRAL_MOMENT_31, + Nyxus::Feature2D::CENTRAL_MOMENT_32, + Nyxus::Feature2D::CENTRAL_MOMENT_33, + + // Weighted central moments + Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_02, + Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_03, + Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_11, + Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_12, + Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_20, + Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_21, + Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_30, + + // weighted normalized central moments + Nyxus::Feature2D::WT_NORM_CTR_MOM_02, + Nyxus::Feature2D::WT_NORM_CTR_MOM_03, + Nyxus::Feature2D::WT_NORM_CTR_MOM_11, + Nyxus::Feature2D::WT_NORM_CTR_MOM_12, + Nyxus::Feature2D::WT_NORM_CTR_MOM_20, + Nyxus::Feature2D::WT_NORM_CTR_MOM_21, + Nyxus::Feature2D::WT_NORM_CTR_MOM_30, + + // Normalized central moments + Nyxus::Feature2D::NORM_CENTRAL_MOMENT_02, + Nyxus::Feature2D::NORM_CENTRAL_MOMENT_03, + Nyxus::Feature2D::NORM_CENTRAL_MOMENT_11, + Nyxus::Feature2D::NORM_CENTRAL_MOMENT_12, + Nyxus::Feature2D::NORM_CENTRAL_MOMENT_20, + Nyxus::Feature2D::NORM_CENTRAL_MOMENT_21, + Nyxus::Feature2D::NORM_CENTRAL_MOMENT_30, + + // Normalized (standardized) spatial moments + Nyxus::Feature2D::NORM_SPAT_MOMENT_00, + Nyxus::Feature2D::NORM_SPAT_MOMENT_01, + Nyxus::Feature2D::NORM_SPAT_MOMENT_02, + Nyxus::Feature2D::NORM_SPAT_MOMENT_03, + Nyxus::Feature2D::NORM_SPAT_MOMENT_10, + Nyxus::Feature2D::NORM_SPAT_MOMENT_11, + Nyxus::Feature2D::NORM_SPAT_MOMENT_12, + Nyxus::Feature2D::NORM_SPAT_MOMENT_13, + Nyxus::Feature2D::NORM_SPAT_MOMENT_20, + Nyxus::Feature2D::NORM_SPAT_MOMENT_21, + Nyxus::Feature2D::NORM_SPAT_MOMENT_22, + Nyxus::Feature2D::NORM_SPAT_MOMENT_23, + Nyxus::Feature2D::NORM_SPAT_MOMENT_30, + Nyxus::Feature2D::NORM_SPAT_MOMENT_31, + Nyxus::Feature2D::NORM_SPAT_MOMENT_32, + Nyxus::Feature2D::NORM_SPAT_MOMENT_33, + + // Hu's moments 1-7 + Nyxus::Feature2D::HU_M1, + Nyxus::Feature2D::HU_M2, + Nyxus::Feature2D::HU_M3, + Nyxus::Feature2D::HU_M4, + Nyxus::Feature2D::HU_M5, + Nyxus::Feature2D::HU_M6, + Nyxus::Feature2D::HU_M7, + + // Weighted Hu's moments 1-7 + Nyxus::Feature2D::WEIGHTED_HU_M1, + Nyxus::Feature2D::WEIGHTED_HU_M2, + Nyxus::Feature2D::WEIGHTED_HU_M3, + Nyxus::Feature2D::WEIGHTED_HU_M4, + Nyxus::Feature2D::WEIGHTED_HU_M5, + Nyxus::Feature2D::WEIGHTED_HU_M6, + Nyxus::Feature2D::WEIGHTED_HU_M7, + }; + + Smoms2D_feature(); + void calculate(LR& r); + void osized_add_online_pixel(size_t x, size_t y, uint32_t intensity); + void osized_calculate(LR& r, ImageLoader& imloader); + void save_value(std::vector>& feature_vals); + static void parallel_process_1_batch(size_t start, size_t end, std::vector* ptrLabels, std::unordered_map * ptrLabelData); + +#ifdef USE_GPU + static void gpu_process_all_rois(const std::vector& ptrLabels, std::unordered_map & ptrLabelData, size_t batch_offset, size_t batch_len); + void calculate_via_gpu(LR& r, size_t roi_index); + static void save_values_from_gpu_buffer( + std::unordered_map & roidata, + const std::vector& roilabels, + const GpuCache& intermediate_already_hostside, + size_t batch_offset, + size_t batch_len); +#endif + + static bool required (const FeatureSet& fs) { return fs.anyEnabled(Smoms2D_feature::featureset); } // compatibility with manual reduce + +private: + + static inline double intenAsShape(double a) { return 1.0; }; +}; + +// interface with the GPU backend +#ifdef USE_GPU + +namespace NyxusGpu +{ + bool GeoMoments2D_calculate (size_t roi_idx, bool need_shape_moments); +} + +#endif + +// helpers +namespace Nyxus +{ + extern size_t largest_roi_imatr_buf_len; // set in phase 2 + + // Copies integer pixel cloud intensities to real-valued vector + void copy_pixcloud_intensities(reintenvec& dst, const pixcloud& src); + + // Applies to distance-to-contour weighting to intensities of pixel cloud + void apply_dist2contour_weighting( + // output + reintenvec& weighted_intensities, + // input + const pixcloud& cloud, + const pixcloud& contour, + const double epsilon); +} + diff --git a/src/nyx/features/2d_geomoments_basic.cpp b/src/nyx/features/2d_geomoments_basic.cpp new file mode 100644 index 00000000..ec3faf7b --- /dev/null +++ b/src/nyx/features/2d_geomoments_basic.cpp @@ -0,0 +1,337 @@ +#include "../environment.h" +#ifdef USE_GPU +#include "../gpucache.h" +#include "../gpu/geomoments.cuh" +#endif +#include "2d_geomoments.h" + +using namespace Nyxus; + +#ifdef USE_GPU + + void save_values_from_gpu_buffer( + std::unordered_map & roidata, + const std::vector& roilabels, + const GpuCache& intermediate_already_hostside, + size_t batch_offset, + size_t batch_len); + +#endif + + namespace Nyxus + { + void copy_pixcloud_intensities(reintenvec& dst, const pixcloud& src) + { + dst.reserve(src.size()); + for (auto pxl : src) + dst.push_back(RealPixIntens(pxl.inten)); + } + + /// @brief Applies to distance-to-contour weighting to intensities of pixel cloud. Saves the result in 'realintens' + void apply_dist2contour_weighting( + // input & output + reintenvec& realintens, + // input + const pixcloud& cloud, + const pixcloud& contour, + const double epsilon) + { + size_t n = cloud.size(); + for (size_t i = 0; i < n; i++) + { + auto& p = cloud[i]; + + // pixel distance + double mind2 = p.min_sqdist(contour); + double dist = std::sqrt(mind2); + + // weighted intensity + double I = 1.0; // shape moments => constant intensity within the ROI + realintens[i] = I / (dist + epsilon); + } + } + } + +void BasicGeomoms2D::calculate(LR& r, intenfunction ifun) +{ + INTEN = ifun; + + // intercept blank ROIs + if (r.aux_max == r.aux_min) + { + // spatial moments + m00 = m01 = m02 = m03 = m10 = m11 = m12 = m13 = m20 = m21 = m22 = m23 = m30 = + // weighted spatial moments + wm00 = wm01 = wm02 = wm03 = wm10 = wm11 = wm12 = wm20 = wm21 = wm30 = + // normalized spatial moments + w00 = w01 = w02 = w03 = w10 = w11 = w12 = w13 = w20 = w21 = w22 = w23 = w30 = w31 = w32 = w33 = + // normalized central moments + nu02 = nu03 = nu11 = nu12 = nu20 = nu21 = nu30 = + // central moments + mu00 = mu01 = mu02 = mu03 = mu10 = mu11 = mu12 = mu13 = mu20 = mu21 = mu22 = mu23 = mu30 = mu31 = mu32 = mu33 = + // weighted central moments + wmu02 = wmu03 = wmu11 = wmu12 = wmu20 = wmu21 = wmu30 = + // Hu invariants + hm1 = hm2 = hm3 = hm4 = hm5 = hm6 = hm7 = + // weighted Hu invariants + whm1 = whm2 = whm3 = whm4 = whm5 = whm6 = whm7 = theEnvironment.nan_substitute; + + return; + } + + // Cache ROI frame of reference + baseX = r.aabb.get_xmin(); + baseY = r.aabb.get_ymin(); + + // -- non-weighted moments + auto& c = r.raw_pixels; + calcOrigins(c); + calcRawMoments(c); + calcCentralMoments(c); + calcNormRawMoments(c); + calcNormCentralMoments(c); + calcHuInvariants(c); + + // -- prepare weighted pixel cloud + std::vector w; + Nyxus::copy_pixcloud_intensities(w, c); + Nyxus::apply_dist2contour_weighting(w, c, r.contour, weighting_epsilon); + + // -- weighted moments + calcOrigins(c, w); + calcWeightedRawMoments(c, w); + calcWeightedCentralMoments(c, w); + calcWeightedNormCentralMoms(c, w); + calcWeightedHuInvariants(c, w); + +} + +double BasicGeomoms2D::moment(const pixcloud& cloud, int p, int q) +{ + double q_ = q, p_ = p, sum = 0; + for (auto& pxl : cloud) + sum += INTEN(double(pxl.inten)) * pow(double(pxl.x - baseX), p_) * pow(double(pxl.y - baseY), q_); + return sum; +} + +double BasicGeomoms2D::moment(const pixcloud& c, const reintenvec& real_intens, int p, int q) +{ + double q_ = q, p_ = p, sum = 0; + size_t n = c.size(); + for (size_t i = 0; i < n; i++) + { + const Pixel2& pxl = c[i]; + sum += real_intens[i] * pow(double(pxl.x - baseX), p_) * pow(double(pxl.y - baseY), q_); + } + return sum; +} + +void BasicGeomoms2D::calcOrigins(const pixcloud& cloud) +{ + double m00 = moment(cloud, 0, 0), + m10 = moment(cloud, 1, 0), + m01 = moment(cloud, 0, 1); + originOfX = m10 / m00; + originOfY = m01 / m00; +} + +void BasicGeomoms2D::calcOrigins(const pixcloud& cloud, const reintenvec& real_valued_intensities) +{ + double m00 = moment(cloud, real_valued_intensities, 0, 0); + originOfX = moment(cloud, real_valued_intensities, 1, 0) / m00; + originOfY = moment(cloud, real_valued_intensities, 0, 1) / m00; +} + +/// @brief Calculates the central 2D moment of order q,p of ROI pixel cloud +double BasicGeomoms2D::centralMom(const pixcloud& cloud, int p, int q) +{ + double sum = 0; + for (auto& pxl : cloud) + sum += INTEN(double(pxl.inten)) * pow(double(pxl.x - baseX) - originOfX, p) * pow(double(pxl.y - baseY) - originOfY, q); + return sum; +} + +/// @brief Calculates the central 2D moment of order q,p of ROI pixel cloud using real-valued intensities +double BasicGeomoms2D::centralMom(const pixcloud& cloud, const reintenvec& realintens, int p, int q) +{ + double sum = 0; + size_t n = cloud.size(); + for (size_t i = 0; i < n; i++) + { + auto& pxl = cloud[i]; + sum += realintens[i] * pow(double(pxl.x - baseX) - originOfX, p) * pow(double(pxl.y - baseY) - originOfY, q); + } + return sum; +} + +/// @brief Calculates the normalized spatial 2D moment of order q,p of ROI pixel cloud +double BasicGeomoms2D::normRawMom(const pixcloud& cloud, int p, int q) +{ + double k = ((double(p) + double(q)) / 2.0) + 1.0; + double retval = moment(cloud, p, q) / pow(moment(cloud, 0, 0), k); + return retval; +} + +/// @brief Calculates the normalized central 2D moment of order q,p of ROI pixel cloud +double BasicGeomoms2D::normCentralMom(const pixcloud& cloud, int p, int q) +{ + double temp = ((double(p) + double(q)) / 2.0) + 1.0; + double retval = centralMom(cloud, p, q) / pow(moment(cloud, 0, 0), temp); + return retval; +} + +/// @brief Calculates the normalized central 2D moment of order q,p of ROI pixel cloud using real-valued intensities 'realintens' +double BasicGeomoms2D::normCentralMom(const pixcloud& cloud, const reintenvec& realintens, int p, int q) +{ + double temp = ((double(p) + double(q)) / 2.0) + 1.0; + double retval = centralMom(cloud, realintens, p, q) / pow(moment(cloud, realintens, 0, 0), temp); + return retval; +} + +// Hu-1962 invariants +// _02, _03, _11, _12, _20, _21, _30 are normed central moments +std::tuple BasicGeomoms2D::calcHu_imp(double _02, double _03, double _11, double _12, double _20, double _21, double _30) +{ + double h1 = _20 + _02; + double h2 = pow((_20 - _02), 2) + 4 * (pow(_11, 2)); + double h3 = pow((_30 - 3 * _12), 2) + + pow((3 * _21 - _03), 2); + double h4 = pow((_30 + _12), 2) + + pow((_21 + _03), 2); + double h5 = (_30 - 3 * _12) * + (_30 + _12) * + (pow(_30 + _12, 2) - 3 * pow(_21 + _03, 2)) + + (3 * _21 - _03) * (_21 + _03) * + (pow(3 * (_30 + _12), 2) - pow(_21 + _03, 2)); + double h6 = (_20 - _02) * (pow(_30 + _12, 2) - + pow(_21 + _03, 2)) + (4 * _11 * (_30 + _12) * + _21 + _03); + double h7 = (3 * _21 - _03) * (_30 + _12) * (pow(_30 + _12, 2) - + 3 * pow(_21 + _03, 2)) - (_30 - 3 * _12) * (_21 + _03) * + (3 * pow(_30 + _12, 2) - pow(_21 + _03, 2)); + + return { h1, h2, h3, h4, h5,h6, h7 }; +} + +// Prerequisite: precalculated normed central moments 'nu02 ... nu30' +void BasicGeomoms2D::calcHuInvariants(const pixcloud& cloud) +{ + std::tie(hm1, hm2, hm3, hm4, hm5, hm6, hm7) = calcHu_imp(nu02, nu03, nu11, nu12, nu20, nu21, nu30); +} + +// Prerequisite: precalculated weighted normed central moments 'wncm02 ... wncm30' +void BasicGeomoms2D::calcWeightedHuInvariants(const pixcloud& cloud, const reintenvec& realintens) +{ + std::tie(whm1, whm2, whm3, whm4, whm5, whm6, whm7) = calcHu_imp(wncm02, wncm03, wncm11, wncm12, wncm20, wncm21, wncm30); +} + +void BasicGeomoms2D::calcRawMoments(const pixcloud& cloud) +{ + m00 = moment(cloud, 0, 0); + m01 = moment(cloud, 0, 1); + m02 = moment(cloud, 0, 2); + m03 = moment(cloud, 0, 3); + m10 = moment(cloud, 1, 0); + m11 = moment(cloud, 1, 1); + m12 = moment(cloud, 1, 2); + m13 = moment(cloud, 1, 3); + m20 = moment(cloud, 2, 0); + m21 = moment(cloud, 2, 1); + m22 = moment(cloud, 2, 2); + m23 = moment(cloud, 2, 3); + m30 = moment(cloud, 3, 0); +} + +void BasicGeomoms2D::calcWeightedRawMoments(const pixcloud& cloud, const reintenvec& real_intens) +{ + wm00 = moment(cloud, real_intens, 0, 0); + wm01 = moment(cloud, real_intens, 0, 1); + wm02 = moment(cloud, real_intens, 0, 2); + wm03 = moment(cloud, real_intens, 0, 3); + wm10 = moment(cloud, real_intens, 1, 0); + wm11 = moment(cloud, real_intens, 1, 1); + wm12 = moment(cloud, real_intens, 1, 2); + wm20 = moment(cloud, real_intens, 2, 0); + wm21 = moment(cloud, real_intens, 2, 1); + wm30 = moment(cloud, real_intens, 3, 0); +} + +void BasicGeomoms2D::calcCentralMoments(const pixcloud& cloud) +{ + mu00 = centralMom(cloud, 0, 0); + mu01 = centralMom(cloud, 0, 1); + mu02 = centralMom(cloud, 0, 2); + mu03 = centralMom(cloud, 0, 3); + + mu10 = centralMom(cloud, 1, 0); + mu11 = centralMom(cloud, 1, 1); + mu12 = centralMom(cloud, 1, 2); + mu13 = centralMom(cloud, 1, 3); + + mu20 = centralMom(cloud, 2, 0); + mu21 = centralMom(cloud, 2, 1); + mu22 = centralMom(cloud, 2, 2); + mu23 = centralMom(cloud, 2, 3); + + mu30 = centralMom(cloud, 3, 0); + mu31 = centralMom(cloud, 3, 1); + mu32 = centralMom(cloud, 3, 2); + mu33 = centralMom(cloud, 3, 3); +} + +void BasicGeomoms2D::calcWeightedCentralMoments(const pixcloud& cloud, const reintenvec& realintens) +{ + wmu02 = centralMom(cloud, realintens, 0, 2); + wmu03 = centralMom(cloud, realintens, 0, 3); + wmu11 = centralMom(cloud, realintens, 1, 1); + wmu12 = centralMom(cloud, realintens, 1, 2); + wmu20 = centralMom(cloud, realintens, 2, 0); + wmu21 = centralMom(cloud, realintens, 2, 1); + wmu30 = centralMom(cloud, realintens, 3, 0); +} + +void BasicGeomoms2D::calcNormCentralMoments(const pixcloud& cloud) +{ + nu02 = normCentralMom(cloud, 0, 2); + nu03 = normCentralMom(cloud, 0, 3); + nu11 = normCentralMom(cloud, 1, 1); + nu12 = normCentralMom(cloud, 1, 2); + nu20 = normCentralMom(cloud, 2, 0); + nu21 = normCentralMom(cloud, 2, 1); + nu30 = normCentralMom(cloud, 3, 0); +} + +void BasicGeomoms2D::calcWeightedNormCentralMoms(const pixcloud& cloud, const reintenvec& realintens) +{ + wncm20 = normCentralMom(cloud, realintens, 2, 0); + wncm02 = normCentralMom(cloud, realintens, 0, 2); + wncm11 = normCentralMom(cloud, realintens, 1, 1); + wncm30 = normCentralMom(cloud, realintens, 3, 0); + wncm12 = normCentralMom(cloud, realintens, 1, 2); + wncm21 = normCentralMom(cloud, realintens, 2, 1); + wncm03 = normCentralMom(cloud, realintens, 0, 3); +} + +void BasicGeomoms2D::calcNormRawMoments(const pixcloud& cloud) +{ + w00 = normRawMom(cloud, 0, 0); + w01 = normRawMom(cloud, 0, 1); + w02 = normRawMom(cloud, 0, 2); + w03 = normRawMom(cloud, 0, 3); + + w10 = normRawMom(cloud, 1, 0); + w11 = normRawMom(cloud, 1, 1); + w12 = normRawMom(cloud, 1, 2); + w13 = normRawMom(cloud, 1, 3); + + w20 = normRawMom(cloud, 2, 0); + w21 = normRawMom(cloud, 2, 1); + w22 = normRawMom(cloud, 2, 2); + w23 = normRawMom(cloud, 2, 3); + + w30 = normRawMom(cloud, 3, 0); + w31 = normRawMom(cloud, 3, 1); + w32 = normRawMom(cloud, 3, 2); + w33 = normRawMom(cloud, 3, 3); +} + diff --git a/src/nyx/features/image_moments_nontriv.cpp b/src/nyx/features/2d_geomoments_basic_nt.cpp similarity index 75% rename from src/nyx/features/image_moments_nontriv.cpp rename to src/nyx/features/2d_geomoments_basic_nt.cpp index 530553f2..8108aeda 100644 --- a/src/nyx/features/image_moments_nontriv.cpp +++ b/src/nyx/features/2d_geomoments_basic_nt.cpp @@ -1,6 +1,6 @@ -#include "image_moments.h" +#include "2d_geomoments.h" -void ImageMomentsFeature::osized_calculate(LR& r, ImageLoader&) +void BasicGeomoms2D::osized_calculate(LR& r, ImageLoader&) { // Cache ROI frame of reference baseX = r.aabb.get_xmin(); @@ -8,16 +8,16 @@ void ImageMomentsFeature::osized_calculate(LR& r, ImageLoader&) // Calculate non-weighted moments auto& c = r.raw_pixels_NT; - calcOrigins (c); - calcRawMoments (c); - calcCentralMoments (c); - calcNormRawMoments (c); - calcNormCentralMoments (c); - calcHuInvariants (c); + calcOrigins(c); + calcRawMoments(c); + calcCentralMoments(c); + calcNormRawMoments(c); + calcNormCentralMoments(c); + calcHuInvariants(c); // Prepare weighted pixel cloud pixcloud_NT w; - w.init(r.label, "ImageMomentsFeature-osized_calculate-w"); + w.init(r.label, "BasicGeomoms2D-osized_calculate-w"); // Implement apply_dist2contour_weighting (w, r.contour, weighting_epsilon) : for (auto p : c) @@ -36,14 +36,14 @@ void ImageMomentsFeature::osized_calculate(LR& r, ImageLoader&) } // Calculate weighted moments - calcOrigins (w); - calcWeightedRawMoments (w); - calcWeightedCentralMoments (w); - calcWeightedHuInvariants (w); + calcOrigins(w); + calcWeightedRawMoments(w); + calcWeightedCentralMoments(w); + calcWeightedHuInvariants(w); } /// @brief Calculates the spatial 2D moment of order q,p f ROI pixel cloud -double ImageMomentsFeature::moment (const pixcloud_NT& cloud, int p, int q) +double BasicGeomoms2D::moment(const pixcloud_NT& cloud, int p, int q) { double q_ = q, p_ = p, sum = 0; for (auto pxl : cloud) @@ -51,7 +51,7 @@ double ImageMomentsFeature::moment (const pixcloud_NT& cloud, int p, int q) return sum; } -void ImageMomentsFeature::calcOrigins(const pixcloud_NT& cloud) +void BasicGeomoms2D::calcOrigins(const pixcloud_NT& cloud) { double m00 = moment(cloud, 0, 0); originOfX = moment(cloud, 1, 0) / m00; @@ -59,7 +59,7 @@ void ImageMomentsFeature::calcOrigins(const pixcloud_NT& cloud) } /// @brief Calculates the central 2D moment of order q,p of ROI pixel cloud -double ImageMomentsFeature::centralMom(const pixcloud_NT& cloud, int p, int q) +double BasicGeomoms2D::centralMom(const pixcloud_NT& cloud, int p, int q) { double sum = 0; for (auto pxl : cloud) @@ -68,7 +68,7 @@ double ImageMomentsFeature::centralMom(const pixcloud_NT& cloud, int p, int q) } /// @brief Calculates the normalized spatial 2D moment of order q,p of ROI pixel cloud -double ImageMomentsFeature::normRawMom(const pixcloud_NT& cloud, int p, int q) +double BasicGeomoms2D::normRawMom(const pixcloud_NT& cloud, int p, int q) { double stddev = centralMom(cloud, 2, 2); int w = std::max(q, p); @@ -79,14 +79,14 @@ double ImageMomentsFeature::normRawMom(const pixcloud_NT& cloud, int p, int q) } /// @brief Calculates the normalized central 2D moment of order q,p of ROI pixel cloud -double ImageMomentsFeature::normCentralMom(const pixcloud_NT& cloud, int p, int q) +double BasicGeomoms2D::normCentralMom(const pixcloud_NT& cloud, int p, int q) { double temp = ((double(p) + double(q)) / 2.0) + 1.0; double retval = centralMom(cloud, p, q) / pow(moment(cloud, 0, 0), temp); return retval; } -std::tuple ImageMomentsFeature::calcHuInvariants_imp(const pixcloud_NT& cloud) +std::tuple BasicGeomoms2D::calcHuInvariants_imp(const pixcloud_NT& cloud) { // calculate the 7 Hu-1962 invariants @@ -119,17 +119,17 @@ std::tuple ImageMomentsF return { h1, h2, h3, h4, h5, h6, h7 }; } -void ImageMomentsFeature::calcHuInvariants(const pixcloud_NT& cloud) +void BasicGeomoms2D::calcHuInvariants(const pixcloud_NT& cloud) { std::tie(hm1, hm2, hm3, hm4, hm5, hm6, hm7) = calcHuInvariants_imp(cloud); } -void ImageMomentsFeature::calcWeightedHuInvariants(const pixcloud_NT& cloud) +void BasicGeomoms2D::calcWeightedHuInvariants(const pixcloud_NT& cloud) { std::tie(whm1, whm2, whm3, whm4, whm5, whm6, whm7) = calcHuInvariants_imp(cloud); } -void ImageMomentsFeature::calcRawMoments(const pixcloud_NT& cloud) +void BasicGeomoms2D::calcRawMoments(const pixcloud_NT& cloud) { m00 = moment(cloud, 0, 0); m01 = moment(cloud, 0, 1); @@ -148,7 +148,7 @@ void ImageMomentsFeature::calcRawMoments(const pixcloud_NT& cloud) /// @brief /// @param cloud Cloud of weighted ROI pixels -void ImageMomentsFeature::calcWeightedRawMoments(const pixcloud_NT& cloud) +void BasicGeomoms2D::calcWeightedRawMoments(const pixcloud_NT& cloud) { wm00 = moment(cloud, 0, 0); wm01 = moment(cloud, 0, 1); @@ -162,7 +162,7 @@ void ImageMomentsFeature::calcWeightedRawMoments(const pixcloud_NT& cloud) wm30 = moment(cloud, 3, 0); } -void ImageMomentsFeature::calcCentralMoments(const pixcloud_NT& cloud) +void BasicGeomoms2D::calcCentralMoments(const pixcloud_NT& cloud) { mu02 = centralMom(cloud, 0, 2); mu03 = centralMom(cloud, 0, 3); @@ -173,7 +173,7 @@ void ImageMomentsFeature::calcCentralMoments(const pixcloud_NT& cloud) mu30 = centralMom(cloud, 3, 0); } -void ImageMomentsFeature::calcWeightedCentralMoments(const pixcloud_NT& cloud) +void BasicGeomoms2D::calcWeightedCentralMoments(const pixcloud_NT& cloud) { wmu02 = centralMom(cloud, 0, 2); wmu03 = centralMom(cloud, 0, 3); @@ -184,7 +184,7 @@ void ImageMomentsFeature::calcWeightedCentralMoments(const pixcloud_NT& cloud) wmu30 = centralMom(cloud, 3, 0); } -void ImageMomentsFeature::calcNormCentralMoments(const pixcloud_NT& cloud) +void BasicGeomoms2D::calcNormCentralMoments(const pixcloud_NT& cloud) { nu02 = normCentralMom(cloud, 0, 2); nu03 = normCentralMom(cloud, 0, 3); @@ -195,7 +195,7 @@ void ImageMomentsFeature::calcNormCentralMoments(const pixcloud_NT& cloud) nu30 = normCentralMom(cloud, 3, 0); } -void ImageMomentsFeature::calcNormRawMoments(const pixcloud_NT& cloud) +void BasicGeomoms2D::calcNormRawMoments(const pixcloud_NT& cloud) { w00 = normRawMom(cloud, 0, 0); w01 = normRawMom(cloud, 0, 1); diff --git a/src/nyx/features/contour.cpp b/src/nyx/features/contour.cpp index 52b4a248..1059a498 100644 --- a/src/nyx/features/contour.cpp +++ b/src/nyx/features/contour.cpp @@ -73,6 +73,107 @@ bool ContourFeature::required(const FeatureSet& fs) Feature2D::WEIGHTED_HU_M5, Feature2D::WEIGHTED_HU_M6, Feature2D::WEIGHTED_HU_M7, + + // -- intensity raw moments + Nyxus::Feature2D::IMOM_RM_00, + Nyxus::Feature2D::IMOM_RM_01, + Nyxus::Feature2D::IMOM_RM_02, + Nyxus::Feature2D::IMOM_RM_03, + Nyxus::Feature2D::IMOM_RM_10, + Nyxus::Feature2D::IMOM_RM_11, + Nyxus::Feature2D::IMOM_RM_12, + Nyxus::Feature2D::IMOM_RM_13, + Nyxus::Feature2D::IMOM_RM_20, + Nyxus::Feature2D::IMOM_RM_21, + Nyxus::Feature2D::IMOM_RM_22, + Nyxus::Feature2D::IMOM_RM_23, + Nyxus::Feature2D::IMOM_RM_30, + // -- intensity central moments + Nyxus::Feature2D::IMOM_CM_00, + Nyxus::Feature2D::IMOM_CM_01, + Nyxus::Feature2D::IMOM_CM_02, + Nyxus::Feature2D::IMOM_CM_03, + Nyxus::Feature2D::IMOM_CM_10, + Nyxus::Feature2D::IMOM_CM_11, + Nyxus::Feature2D::IMOM_CM_12, + Nyxus::Feature2D::IMOM_CM_13, + Nyxus::Feature2D::IMOM_CM_20, + Nyxus::Feature2D::IMOM_CM_21, + Nyxus::Feature2D::IMOM_CM_22, + Nyxus::Feature2D::IMOM_CM_23, + Nyxus::Feature2D::IMOM_CM_30, + Nyxus::Feature2D::IMOM_CM_31, + Nyxus::Feature2D::IMOM_CM_32, + Nyxus::Feature2D::IMOM_CM_33, + // -- intensity normalized raw moments + Nyxus::Feature2D::IMOM_NRM_00, + Nyxus::Feature2D::IMOM_NRM_01, + Nyxus::Feature2D::IMOM_NRM_02, + Nyxus::Feature2D::IMOM_NRM_03, + Nyxus::Feature2D::IMOM_NRM_10, + Nyxus::Feature2D::IMOM_NRM_11, + Nyxus::Feature2D::IMOM_NRM_12, + Nyxus::Feature2D::IMOM_NRM_13, + Nyxus::Feature2D::IMOM_NRM_20, + Nyxus::Feature2D::IMOM_NRM_21, + Nyxus::Feature2D::IMOM_NRM_22, + Nyxus::Feature2D::IMOM_NRM_23, + Nyxus::Feature2D::IMOM_NRM_30, + Nyxus::Feature2D::IMOM_NRM_31, + Nyxus::Feature2D::IMOM_NRM_32, + Nyxus::Feature2D::IMOM_NRM_33, + // -- intensity normalized central moments + Nyxus::Feature2D::IMOM_NCM_02, + Nyxus::Feature2D::IMOM_NCM_03, + Nyxus::Feature2D::IMOM_NCM_11, + Nyxus::Feature2D::IMOM_NCM_12, + Nyxus::Feature2D::IMOM_NCM_20, + Nyxus::Feature2D::IMOM_NCM_21, + Nyxus::Feature2D::IMOM_NCM_30, + // -- intensity Hu's moments 1-7 + Nyxus::Feature2D::IMOM_HU1, + Nyxus::Feature2D::IMOM_HU2, + Nyxus::Feature2D::IMOM_HU3, + Nyxus::Feature2D::IMOM_HU4, + Nyxus::Feature2D::IMOM_HU5, + Nyxus::Feature2D::IMOM_HU6, + Nyxus::Feature2D::IMOM_HU7, + // -- intensity weighted raw moments + Nyxus::Feature2D::IMOM_WRM_00, + Nyxus::Feature2D::IMOM_WRM_01, + Nyxus::Feature2D::IMOM_WRM_02, + Nyxus::Feature2D::IMOM_WRM_03, + Nyxus::Feature2D::IMOM_WRM_10, + Nyxus::Feature2D::IMOM_WRM_11, + Nyxus::Feature2D::IMOM_WRM_12, + Nyxus::Feature2D::IMOM_WRM_20, + Nyxus::Feature2D::IMOM_WRM_21, + Nyxus::Feature2D::IMOM_WRM_30, + // -- intensity weighted central moments + Nyxus::Feature2D::IMOM_WCM_02, + Nyxus::Feature2D::IMOM_WCM_03, + Nyxus::Feature2D::IMOM_WCM_11, + Nyxus::Feature2D::IMOM_WCM_12, + Nyxus::Feature2D::IMOM_WCM_20, + Nyxus::Feature2D::IMOM_WCM_21, + Nyxus::Feature2D::IMOM_WCM_30, + // -- intensity weighted normalized central moments + Nyxus::Feature2D::IMOM_WNCM_02, + Nyxus::Feature2D::IMOM_WNCM_03, + Nyxus::Feature2D::IMOM_WNCM_11, + Nyxus::Feature2D::IMOM_WNCM_12, + Nyxus::Feature2D::IMOM_WNCM_20, + Nyxus::Feature2D::IMOM_WNCM_21, + Nyxus::Feature2D::IMOM_WNCM_30, + // -- intensity weighted Hu's moments 1-7 + Nyxus::Feature2D::IMOM_WHU1, + Nyxus::Feature2D::IMOM_WHU2, + Nyxus::Feature2D::IMOM_WHU3, + Nyxus::Feature2D::IMOM_WHU4, + Nyxus::Feature2D::IMOM_WHU5, + Nyxus::Feature2D::IMOM_WHU6, + Nyxus::Feature2D::IMOM_WHU7, + // misc Feature2D::ROI_RADIUS_MEAN, Feature2D::ROI_RADIUS_MAX, diff --git a/src/nyx/features/image_moments.cpp b/src/nyx/features/image_moments.cpp deleted file mode 100644 index 5efdba2c..00000000 --- a/src/nyx/features/image_moments.cpp +++ /dev/null @@ -1,621 +0,0 @@ -#include "../environment.h" -#ifdef USE_GPU - #include "../gpucache.h" - #include "../gpu/geomoments.cuh" -#endif -#include "image_moments.h" - -using namespace Nyxus; - -#define MOMENTS_OF_BINARY -#ifdef MOMENTS_OF_BINARY - #define INTEN(x) 1.0 -#else - #define INTEN(x) x -#endif - -ImageMomentsFeature::ImageMomentsFeature() : FeatureMethod("ImageMomentsFeature") -{ - provide_features (ImageMomentsFeature::featureset); - add_dependencies ({Feature2D::PERIMETER}); -} - -void ImageMomentsFeature::calculate (LR& r) -{ - // intercept blank ROIs - if (r.aux_max == r.aux_min) - { - // spatial moments - m00 = m01 = m02 = m03 = m10 = m11 = m12 = m13 = m20 = m21 = m22 = m23 = m30 = - // weighted spatial moments - wm00 = wm01 = wm02 = wm03 = wm10 = wm11 = wm12 = wm20 = wm21 = wm30 = - // normalized spatial moments - w00 = w01 = w02 = w03 = w10 = w11 = w12 = w13 = w20 = w21 = w22 = w23 = w30 = w31 = w32 = w33 = - // normalized central moments - nu02 = nu03 = nu11 = nu12 = nu20 = nu21 = nu30 = - // central moments - mu00 = mu01 = mu02 = mu03 = mu10 = mu11 = mu12 = mu13 = mu20 = mu21 = mu22 = mu23 = mu30 = mu31 = mu32 = mu33 = - // weighted central moments - wmu02 = wmu03 = wmu11 = wmu12 = wmu20 = wmu21 = wmu30 = - // Hu invariants - hm1 = hm2 = hm3 = hm4 = hm5 = hm6 = hm7 = - // weighted Hu invariants - whm1 = whm2 = whm3 = whm4 = whm5 = whm6 = whm7 = theEnvironment.nan_substitute; - - return; - } - - // Cache ROI frame of reference - baseX = r.aabb.get_xmin(); - baseY = r.aabb.get_ymin(); - - // Calculate non-weighted moments - auto& c = r.raw_pixels; - calcOrigins (c); - calcRawMoments (c); - calcCentralMoments (c); - calcNormRawMoments (c); - calcNormCentralMoments (c); - calcHuInvariants (c); - - // Prepare weighted pixel cloud - std::vector w; - Nyxus::copy_pixcloud_intensities (w, c); - Nyxus::apply_dist2contour_weighting (w, c, r.contour, weighting_epsilon); - - // Calculate weighted moments - calcOrigins (c, w); - calcWeightedRawMoments (c, w); - calcWeightedCentralMoments (c, w); - calcWeightedNormCentralMoms (c, w); - calcWeightedHuInvariants (c, w); -} - -#ifdef USE_GPU -void ImageMomentsFeature::calculate_via_gpu (LR& r, size_t roi_idx) -{ - bool ok = NyxusGpu::ImageMomentsFeature_calculate (roi_idx); - if (!ok) - std::cerr << "Geometric moments: error calculating features on GPU\n"; -} -#endif - -void ImageMomentsFeature::osized_add_online_pixel (size_t x, size_t y, uint32_t intensity) {} // Not supporting online for image moments - -void ImageMomentsFeature::save_value(std::vector>& fvals) -{ - fvals[(int)Feature2D::SPAT_MOMENT_00][0] = m00; - fvals[(int)Feature2D::SPAT_MOMENT_01][0] = m01; - fvals[(int)Feature2D::SPAT_MOMENT_02][0] = m02; - fvals[(int)Feature2D::SPAT_MOMENT_03][0] = m03; - fvals[(int)Feature2D::SPAT_MOMENT_10][0] = m10; - fvals[(int)Feature2D::SPAT_MOMENT_11][0] = m11; - fvals[(int)Feature2D::SPAT_MOMENT_12][0] = m12; - fvals[(int)Feature2D::SPAT_MOMENT_13][0] = m13; - fvals[(int)Feature2D::SPAT_MOMENT_20][0] = m20; - fvals[(int)Feature2D::SPAT_MOMENT_21][0] = m21; - fvals[(int)Feature2D::SPAT_MOMENT_22][0] = m22; - fvals[(int)Feature2D::SPAT_MOMENT_23][0] = m23; - fvals[(int)Feature2D::SPAT_MOMENT_30][0] = m30; - - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_00][0] = wm00; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_01][0] = wm01; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_02][0] = wm02; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_03][0] = wm03; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_10][0] = wm10; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_11][0] = wm11; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_12][0] = wm12; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_20][0] = wm20; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_21][0] = wm21; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_30][0] = wm30; - - fvals[(int)Feature2D::CENTRAL_MOMENT_00][0] = mu00; - fvals[(int)Feature2D::CENTRAL_MOMENT_01][0] = mu01; - fvals[(int)Feature2D::CENTRAL_MOMENT_02][0] = mu02; - fvals[(int)Feature2D::CENTRAL_MOMENT_03][0] = mu03; - fvals[(int)Feature2D::CENTRAL_MOMENT_10][0] = mu10; - fvals[(int)Feature2D::CENTRAL_MOMENT_11][0] = mu11; - fvals[(int)Feature2D::CENTRAL_MOMENT_12][0] = mu12; - fvals[(int)Feature2D::CENTRAL_MOMENT_13][0] = mu13; - fvals[(int)Feature2D::CENTRAL_MOMENT_20][0] = mu20; - fvals[(int)Feature2D::CENTRAL_MOMENT_21][0] = mu21; - fvals[(int)Feature2D::CENTRAL_MOMENT_22][0] = mu22; - fvals[(int)Feature2D::CENTRAL_MOMENT_23][0] = mu23; - fvals[(int)Feature2D::CENTRAL_MOMENT_30][0] = mu30; - fvals[(int)Feature2D::CENTRAL_MOMENT_31][0] = mu31; - fvals[(int)Feature2D::CENTRAL_MOMENT_32][0] = mu32; - fvals[(int)Feature2D::CENTRAL_MOMENT_33][0] = mu33; - - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_02][0] = wmu02; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_03][0] = wmu03; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_11][0] = wmu11; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_12][0] = wmu12; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_20][0] = wmu20; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_21][0] = wmu21; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_30][0] = wmu30; - - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_02][0] = nu02; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_03][0] = nu03; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_11][0] = nu11; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_12][0] = nu12; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_20][0] = nu20; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_21][0] = nu21; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_30][0] = nu30; - - fvals[(int)Feature2D::NORM_SPAT_MOMENT_00][0] = w00; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_01][0] = w01; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_02][0] = w02; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_03][0] = w03; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_10][0] = w10; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_11][0] = w11; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_12][0] = w12; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_13][0] = w13; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_20][0] = w20; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_21][0] = w21; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_22][0] = w22; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_23][0] = w23; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_30][0] = w30; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_31][0] = w31; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_32][0] = w32; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_33][0] = w33; - - fvals[(int)Feature2D::HU_M1][0] = hm1; - fvals[(int)Feature2D::HU_M2][0] = hm2; - fvals[(int)Feature2D::HU_M3][0] = hm3; - fvals[(int)Feature2D::HU_M4][0] = hm4; - fvals[(int)Feature2D::HU_M5][0] = hm5; - fvals[(int)Feature2D::HU_M6][0] = hm6; - fvals[(int)Feature2D::HU_M7][0] = hm7; - - fvals[(int)Feature2D::WT_NORM_CTR_MOM_02][0] = wncm02; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_03][0] = wncm03; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_11][0] = wncm11; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_12][0] = wncm12; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_20][0] = wncm20; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_21][0] = wncm21; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_30][0] = wncm30; - - fvals[(int)Feature2D::WEIGHTED_HU_M1][0] = whm1; - fvals[(int)Feature2D::WEIGHTED_HU_M2][0] = whm2; - fvals[(int)Feature2D::WEIGHTED_HU_M3][0] = whm3; - fvals[(int)Feature2D::WEIGHTED_HU_M4][0] = whm4; - fvals[(int)Feature2D::WEIGHTED_HU_M5][0] = whm5; - fvals[(int)Feature2D::WEIGHTED_HU_M6][0] = whm6; - fvals[(int)Feature2D::WEIGHTED_HU_M7][0] = whm7; -} - -/// @brief Calculates a spatial 2D moment of order q,p of ROI pixel cloud -double ImageMomentsFeature::moment (const pixcloud& cloud, int p, int q) -{ - double q_ = q, p_ = p, sum = 0; - for (auto& pxl : cloud) - sum += INTEN(double(pxl.inten)) * pow(double(pxl.x-baseX), p_) * pow(double(pxl.y-baseY), q_); - return sum; -} - -/// @brief Calculates a spatial 2D moment of order q,p of ROI pixel cloud 'c' using real-valued intensities 'real_intens' -double ImageMomentsFeature::moment (const pixcloud & c, const intcloud & real_intens, int p, int q) -{ - double q_ = q, p_ = p, sum = 0; - size_t n = c.size(); - for (size_t i=0; i ImageMomentsFeature::calcHu_imp (double _02, double _03, double _11, double _12, double _20, double _21, double _30) -{ - double h1 = _20 + _02; - double h2 = pow((_20 - _02), 2) + 4 * (pow(_11, 2)); - double h3 = pow((_30 - 3 * _12), 2) + - pow((3 * _21 - _03), 2); - double h4 = pow((_30 + _12), 2) + - pow((_21 + _03), 2); - double h5 = (_30 - 3 * _12) * - (_30 + _12) * - (pow(_30 + _12, 2) - 3 * pow(_21 + _03, 2)) + - (3 * _21 - _03) * (_21 + _03) * - (pow(3 * (_30 + _12), 2) - pow(_21 + _03, 2)); - double h6 = (_20 - _02) * (pow(_30 + _12, 2) - - pow(_21 + _03, 2)) + (4 * _11 * (_30 + _12) * - _21 + _03); - double h7 = (3 * _21 - _03) * (_30 + _12) * (pow(_30 + _12, 2) - - 3 * pow(_21 + _03, 2)) - (_30 - 3 * _12) * (_21 + _03) * - (3 * pow(_30 + _12, 2) - pow(_21 + _03, 2)); - - return { h1, h2, h3, h4, h5,h6, h7 }; -} - -// Prerequisite: precalculated normed central moments 'nu02 ... nu30' -void ImageMomentsFeature::calcHuInvariants (const pixcloud & cloud) -{ - std::tie(hm1, hm2, hm3, hm4, hm5, hm6, hm7) = calcHu_imp (nu02, nu03, nu11, nu12, nu20, nu21, nu30); -} - -// Prerequisite: precalculated weighted normed central moments 'wncm02 ... wncm30' -void ImageMomentsFeature::calcWeightedHuInvariants (const pixcloud & cloud, const intcloud & realintens) -{ - std::tie(whm1, whm2, whm3, whm4, whm5, whm6, whm7) = calcHu_imp (wncm02, wncm03, wncm11, wncm12, wncm20, wncm21, wncm30); -} - -void ImageMomentsFeature::calcRawMoments (const pixcloud & cloud) -{ - m00 = moment (cloud, 0, 0); - m01 = moment (cloud, 0, 1); - m02 = moment (cloud, 0, 2); - m03 = moment (cloud, 0, 3); - m10 = moment (cloud, 1, 0); - m11 = moment (cloud, 1, 1); - m12 = moment (cloud, 1, 2); - m13 = moment (cloud, 1, 3); - m20 = moment (cloud, 2, 0); - m21 = moment (cloud, 2, 1); - m22 = moment (cloud, 2, 2); - m23 = moment (cloud, 2, 3); - m30 = moment (cloud, 3, 0); -} - -void ImageMomentsFeature::calcWeightedRawMoments (const pixcloud & cloud, const intcloud & real_intens) -{ - wm00 = moment (cloud, real_intens, 0, 0); - wm01 = moment (cloud, real_intens, 0, 1); - wm02 = moment (cloud, real_intens, 0, 2); - wm03 = moment (cloud, real_intens, 0, 3); - wm10 = moment (cloud, real_intens, 1, 0); - wm11 = moment (cloud, real_intens, 1, 1); - wm12 = moment (cloud, real_intens, 1, 2); - wm20 = moment (cloud, real_intens, 2, 0); - wm21 = moment (cloud, real_intens, 2, 1); - wm30 = moment (cloud, real_intens, 3, 0); -} - -void ImageMomentsFeature::calcCentralMoments (const pixcloud & cloud) -{ - mu00 = centralMom (cloud, 0, 0); - mu01 = centralMom (cloud, 0, 1); - mu02 = centralMom (cloud, 0, 2); - mu03 = centralMom (cloud, 0, 3); - - mu10 = centralMom (cloud, 1, 0); - mu11 = centralMom (cloud, 1, 1); - mu12 = centralMom (cloud, 1, 2); - mu13 = centralMom (cloud, 1, 3); - - mu20 = centralMom (cloud, 2, 0); - mu21 = centralMom (cloud, 2, 1); - mu22 = centralMom (cloud, 2, 2); - mu23 = centralMom (cloud, 2, 3); - - mu30 = centralMom (cloud, 3, 0); - mu31 = centralMom (cloud, 3, 1); - mu32 = centralMom (cloud, 3, 2); - mu33 = centralMom (cloud, 3, 3); -} - -void ImageMomentsFeature::calcWeightedCentralMoments (const pixcloud& cloud, const intcloud& realintens) -{ - wmu02 = centralMom (cloud, realintens, 0, 2); - wmu03 = centralMom (cloud, realintens, 0, 3); - wmu11 = centralMom (cloud, realintens, 1, 1); - wmu12 = centralMom (cloud, realintens, 1, 2); - wmu20 = centralMom (cloud, realintens, 2, 0); - wmu21 = centralMom (cloud, realintens, 2, 1); - wmu30 = centralMom (cloud, realintens, 3, 0); -} - -void ImageMomentsFeature::calcNormCentralMoments (const pixcloud & cloud) -{ - nu02 = normCentralMom (cloud, 0, 2); - nu03 = normCentralMom (cloud, 0, 3); - nu11 = normCentralMom (cloud, 1, 1); - nu12 = normCentralMom (cloud, 1, 2); - nu20 = normCentralMom (cloud, 2, 0); - nu21 = normCentralMom (cloud, 2, 1); - nu30 = normCentralMom (cloud, 3, 0); -} - -void ImageMomentsFeature::calcWeightedNormCentralMoms (const pixcloud & cloud, const intcloud& realintens) -{ - wncm20 = normCentralMom (cloud, realintens, 2, 0); - wncm02 = normCentralMom (cloud, realintens, 0, 2); - wncm11 = normCentralMom (cloud, realintens, 1, 1); - wncm30 = normCentralMom (cloud, realintens, 3, 0); - wncm12 = normCentralMom (cloud, realintens, 1, 2); - wncm21 = normCentralMom (cloud, realintens, 2, 1); - wncm03 = normCentralMom (cloud, realintens, 0, 3); -} - -void ImageMomentsFeature::calcNormRawMoments (const pixcloud & cloud) -{ - w00 = normRawMom (cloud, 0, 0); - w01 = normRawMom (cloud, 0, 1); - w02 = normRawMom (cloud, 0, 2); - w03 = normRawMom (cloud, 0, 3); - - w10 = normRawMom (cloud, 1, 0); - w11 = normRawMom (cloud, 1, 1); - w12 = normRawMom (cloud, 1, 2); - w13 = normRawMom (cloud, 1, 3); - - w20 = normRawMom (cloud, 2, 0); - w21 = normRawMom (cloud, 2, 1); - w22 = normRawMom (cloud, 2, 2); - w23 = normRawMom (cloud, 2, 3); - - w30 = normRawMom (cloud, 3, 0); - w31 = normRawMom (cloud, 3, 1); - w32 = normRawMom (cloud, 3, 2); - w33 = normRawMom (cloud, 3, 3); -} - -/// @brief Calculates the features for a subset of ROIs in a thread-safe way with other ROI subsets -/// @param start Start index of the ROI label vector -/// @param end End index of the ROI label vector -/// @param ptrLabels ROI label vector -/// @param ptrLabelData ROI data -void ImageMomentsFeature::parallel_process_1_batch (size_t start, size_t end, std::vector* ptrLabels, std::unordered_map * ptrLabelData) -{ - for (auto i = start; i < end; i++) - { - int lab = (*ptrLabels)[i]; - LR& r = (*ptrLabelData)[lab]; - - if (r.has_bad_data()) - continue; - - ImageMomentsFeature imf; - imf.calculate(r); - imf.save_value(r.fvals); - } -} - -#ifdef USE_GPU - -void save_values_from_gpu_buffer( - std::unordered_map & roidata, - const std::vector& roilabels, - const GpuCache& intermediate_already_hostside, - size_t batch_offset, - size_t batch_len) -{ - for (size_t i = 0; i < batch_len; i++) - { - size_t roiidx = batch_offset + i; - auto lbl = roilabels[roiidx]; - LR& roi = roidata[lbl]; - auto& fvals = roi.fvals; - - size_t offs = i * GpusideState::__COUNT__; - const gpureal* ptrBuf = &intermediate_already_hostside.hobuffer[offs]; - - fvals[(int)Feature2D::SPAT_MOMENT_00][0] = ptrBuf[GpusideState::RM00]; - fvals[(int)Feature2D::SPAT_MOMENT_01][0] = ptrBuf[GpusideState::RM01]; - fvals[(int)Feature2D::SPAT_MOMENT_02][0] = ptrBuf[GpusideState::RM02]; - fvals[(int)Feature2D::SPAT_MOMENT_03][0] = ptrBuf[GpusideState::RM03]; - fvals[(int)Feature2D::SPAT_MOMENT_10][0] = ptrBuf[GpusideState::RM10]; - fvals[(int)Feature2D::SPAT_MOMENT_11][0] = ptrBuf[GpusideState::RM11]; - fvals[(int)Feature2D::SPAT_MOMENT_12][0] = ptrBuf[GpusideState::RM12]; - fvals[(int)Feature2D::SPAT_MOMENT_13][0] = ptrBuf[GpusideState::RM13]; - fvals[(int)Feature2D::SPAT_MOMENT_20][0] = ptrBuf[GpusideState::RM20]; - fvals[(int)Feature2D::SPAT_MOMENT_21][0] = ptrBuf[GpusideState::RM21]; - fvals[(int)Feature2D::SPAT_MOMENT_22][0] = ptrBuf[GpusideState::RM22]; - fvals[(int)Feature2D::SPAT_MOMENT_23][0] = ptrBuf[GpusideState::RM23]; - fvals[(int)Feature2D::SPAT_MOMENT_30][0] = ptrBuf[GpusideState::RM30]; - - fvals[(int)Feature2D::CENTRAL_MOMENT_00][0] = ptrBuf[GpusideState::CM00]; - fvals[(int)Feature2D::CENTRAL_MOMENT_01][0] = ptrBuf[GpusideState::CM01]; - fvals[(int)Feature2D::CENTRAL_MOMENT_02][0] = ptrBuf[GpusideState::CM02]; - fvals[(int)Feature2D::CENTRAL_MOMENT_03][0] = ptrBuf[GpusideState::CM03]; - fvals[(int)Feature2D::CENTRAL_MOMENT_10][0] = ptrBuf[GpusideState::CM10]; - fvals[(int)Feature2D::CENTRAL_MOMENT_11][0] = ptrBuf[GpusideState::CM11]; - fvals[(int)Feature2D::CENTRAL_MOMENT_12][0] = ptrBuf[GpusideState::CM12]; - fvals[(int)Feature2D::CENTRAL_MOMENT_13][0] = ptrBuf[GpusideState::CM13]; - fvals[(int)Feature2D::CENTRAL_MOMENT_20][0] = ptrBuf[GpusideState::CM20]; - fvals[(int)Feature2D::CENTRAL_MOMENT_21][0] = ptrBuf[GpusideState::CM21]; - fvals[(int)Feature2D::CENTRAL_MOMENT_22][0] = ptrBuf[GpusideState::CM22]; - fvals[(int)Feature2D::CENTRAL_MOMENT_23][0] = ptrBuf[GpusideState::CM23]; - fvals[(int)Feature2D::CENTRAL_MOMENT_30][0] = ptrBuf[GpusideState::CM30]; - fvals[(int)Feature2D::CENTRAL_MOMENT_31][0] = ptrBuf[GpusideState::CM31]; - fvals[(int)Feature2D::CENTRAL_MOMENT_32][0] = ptrBuf[GpusideState::CM32]; - fvals[(int)Feature2D::CENTRAL_MOMENT_33][0] = ptrBuf[GpusideState::CM33]; - - fvals[(int)Feature2D::NORM_SPAT_MOMENT_00][0] = ptrBuf[GpusideState::W00]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_01][0] = ptrBuf[GpusideState::W01]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_02][0] = ptrBuf[GpusideState::W02]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_03][0] = ptrBuf[GpusideState::W03]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_10][0] = ptrBuf[GpusideState::W10]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_11][0] = ptrBuf[GpusideState::W11]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_12][0] = ptrBuf[GpusideState::W12]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_13][0] = ptrBuf[GpusideState::W13]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_20][0] = ptrBuf[GpusideState::W20]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_21][0] = ptrBuf[GpusideState::W21]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_22][0] = ptrBuf[GpusideState::W22]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_23][0] = ptrBuf[GpusideState::W23]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_30][0] = ptrBuf[GpusideState::W30]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_31][0] = ptrBuf[GpusideState::W31]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_32][0] = ptrBuf[GpusideState::W32]; - fvals[(int)Feature2D::NORM_SPAT_MOMENT_33][0] = ptrBuf[GpusideState::W33]; - - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_02][0] = ptrBuf[GpusideState::NU02]; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_03][0] = ptrBuf[GpusideState::NU03]; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_11][0] = ptrBuf[GpusideState::NU11]; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_12][0] = ptrBuf[GpusideState::NU12]; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_20][0] = ptrBuf[GpusideState::NU20]; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_21][0] = ptrBuf[GpusideState::NU21]; - fvals[(int)Feature2D::NORM_CENTRAL_MOMENT_30][0] = ptrBuf[GpusideState::NU30]; - - fvals[(int)Feature2D::HU_M1][0] = ptrBuf[GpusideState::H1]; - fvals[(int)Feature2D::HU_M2][0] = ptrBuf[GpusideState::H2]; - fvals[(int)Feature2D::HU_M3][0] = ptrBuf[GpusideState::H3]; - fvals[(int)Feature2D::HU_M4][0] = ptrBuf[GpusideState::H4]; - fvals[(int)Feature2D::HU_M5][0] = ptrBuf[GpusideState::H5]; - fvals[(int)Feature2D::HU_M6][0] = ptrBuf[GpusideState::H6]; - fvals[(int)Feature2D::HU_M7][0] = ptrBuf[GpusideState::H7]; - - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_00][0] = ptrBuf[GpusideState::WRM00]; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_01][0] = ptrBuf[GpusideState::WRM01]; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_02][0] = ptrBuf[GpusideState::WRM02]; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_03][0] = ptrBuf[GpusideState::WRM03]; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_10][0] = ptrBuf[GpusideState::WRM10]; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_11][0] = ptrBuf[GpusideState::WRM11]; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_12][0] = ptrBuf[GpusideState::WRM12]; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_20][0] = ptrBuf[GpusideState::WRM20]; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_21][0] = ptrBuf[GpusideState::WRM21]; - fvals[(int)Feature2D::WEIGHTED_SPAT_MOMENT_30][0] = ptrBuf[GpusideState::WRM30]; - - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_02][0] = ptrBuf[GpusideState::WCM02]; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_03][0] = ptrBuf[GpusideState::WCM03]; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_11][0] = ptrBuf[GpusideState::WCM11]; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_12][0] = ptrBuf[GpusideState::WCM12]; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_20][0] = ptrBuf[GpusideState::WCM20]; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_21][0] = ptrBuf[GpusideState::WCM21]; - fvals[(int)Feature2D::WEIGHTED_CENTRAL_MOMENT_30][0] = ptrBuf[GpusideState::WCM30]; - - fvals[(int)Feature2D::WT_NORM_CTR_MOM_02][0] = ptrBuf[GpusideState::WNU02]; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_03][0] = ptrBuf[GpusideState::WNU03]; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_11][0] = ptrBuf[GpusideState::WNU11]; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_12][0] = ptrBuf[GpusideState::WNU12]; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_20][0] = ptrBuf[GpusideState::WNU20]; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_21][0] = ptrBuf[GpusideState::WNU21]; - fvals[(int)Feature2D::WT_NORM_CTR_MOM_30][0] = ptrBuf[GpusideState::WNU30]; - - fvals[(int)Feature2D::WEIGHTED_HU_M1][0] = ptrBuf[GpusideState::WH1]; - fvals[(int)Feature2D::WEIGHTED_HU_M2][0] = ptrBuf[GpusideState::WH2]; - fvals[(int)Feature2D::WEIGHTED_HU_M3][0] = ptrBuf[GpusideState::WH3]; - fvals[(int)Feature2D::WEIGHTED_HU_M4][0] = ptrBuf[GpusideState::WH4]; - fvals[(int)Feature2D::WEIGHTED_HU_M5][0] = ptrBuf[GpusideState::WH5]; - fvals[(int)Feature2D::WEIGHTED_HU_M6][0] = ptrBuf[GpusideState::WH6]; - fvals[(int)Feature2D::WEIGHTED_HU_M7][0] = ptrBuf[GpusideState::WH7]; - } -} - -void ImageMomentsFeature::gpu_process_all_rois ( - const std::vector & Labels, - std::unordered_map & RoiData, - size_t batch_offset, - size_t batch_len) -{ - for (auto i=0; i < batch_len; i++) - { - size_t far_i = i + batch_offset; - auto lab = Labels[far_i]; - LR& r = RoiData[lab]; - - // Calculate features - ImageMomentsFeature imf; - imf.calculate_via_gpu (r, i); - //---delayed until we process all the ROIs on GPU-side---> imf.save_value (r.fvals); - - // Pull the result from GPU cache and save it - if (!NyxusGpu::gpu_featurestatebuf.download()) - { - std::cerr << "error in " << __FILE__ << ":" << __LINE__ << "\n"; - return; - } - - save_values_from_gpu_buffer (RoiData, Labels, NyxusGpu::gpu_featurestatebuf, batch_offset, batch_len); - } -} - -#endif // USE_GPU - -namespace Nyxus -{ - void copy_pixcloud_intensities (intcloud & dst, const pixcloud & src) - { - dst.reserve (src.size()); - for (auto pxl : src) - dst.push_back (RealPixIntens(pxl.inten)); - } - - /// @brief Applies to distance-to-contour weighting to intensities of pixel cloud. Saves the result in 'realintens' - void apply_dist2contour_weighting( - // input & output - intcloud & realintens, - // input - const pixcloud & cloud, - const pixcloud & contour, - const double epsilon) - { - size_t n = cloud.size(); - for (size_t i = 0; i < n; i++) - { - auto& p = cloud[i]; - - // pixel distance - double mind2 = p.min_sqdist (contour); - double dist = std::sqrt(mind2); - - // weighted intensity - double I = 1.0; // shape moments => constant intensity within the ROI - realintens[i] = I / (dist + epsilon); - } - } -} diff --git a/src/nyx/features/image_moments.h b/src/nyx/features/image_moments.h deleted file mode 100644 index 7f678e11..00000000 --- a/src/nyx/features/image_moments.h +++ /dev/null @@ -1,230 +0,0 @@ -#pragma once - -#include -#include "../roi_cache.h" -#include "contour.h" -#include "image_matrix.h" -#include "../feature_method.h" - -// Inspired by Yavuz Unver -// -// Hu Moments and Digit Recognition Algorithm: -// http://www.wseas.us/e-library/conferences/2013/CambridgeUK/AISE/AISE-15.pdf -// - -using pixcloud = std::vector ; // cloud of pixels -using intcloud = std::vector ; // cloud of pixel intensities -using pixcloud_NT = OutOfRamPixelCloud; - -/// @brief Hu invariants, weighted Hu invariants, spatial , central, and normalized central moments. -class ImageMomentsFeature: public FeatureMethod -{ -public: - // Codes of features implemented by this class. Used in feature manager's mechanisms, - // in the feature group nickname expansion, and in the feature value output - const constexpr static std::initializer_list featureset = - { - // Spatial (raw) moments - Nyxus::Feature2D::SPAT_MOMENT_00, - Nyxus::Feature2D::SPAT_MOMENT_01, - Nyxus::Feature2D::SPAT_MOMENT_02, - Nyxus::Feature2D::SPAT_MOMENT_03, - Nyxus::Feature2D::SPAT_MOMENT_10, - Nyxus::Feature2D::SPAT_MOMENT_11, - Nyxus::Feature2D::SPAT_MOMENT_12, - Nyxus::Feature2D::SPAT_MOMENT_13, - Nyxus::Feature2D::SPAT_MOMENT_20, - Nyxus::Feature2D::SPAT_MOMENT_21, - Nyxus::Feature2D::SPAT_MOMENT_22, - Nyxus::Feature2D::SPAT_MOMENT_23, - Nyxus::Feature2D::SPAT_MOMENT_30, - - // Weighted spatial moments - Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_00, - Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_01, - Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_02, - Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_03, - Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_10, - Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_11, - Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_12, - Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_20, - Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_21, - Nyxus::Feature2D::WEIGHTED_SPAT_MOMENT_30, - - // Central moments - Nyxus::Feature2D::CENTRAL_MOMENT_00, - Nyxus::Feature2D::CENTRAL_MOMENT_01, - Nyxus::Feature2D::CENTRAL_MOMENT_02, - Nyxus::Feature2D::CENTRAL_MOMENT_03, - Nyxus::Feature2D::CENTRAL_MOMENT_10, - Nyxus::Feature2D::CENTRAL_MOMENT_11, - Nyxus::Feature2D::CENTRAL_MOMENT_12, - Nyxus::Feature2D::CENTRAL_MOMENT_13, - Nyxus::Feature2D::CENTRAL_MOMENT_20, - Nyxus::Feature2D::CENTRAL_MOMENT_21, - Nyxus::Feature2D::CENTRAL_MOMENT_22, - Nyxus::Feature2D::CENTRAL_MOMENT_23, - Nyxus::Feature2D::CENTRAL_MOMENT_30, - Nyxus::Feature2D::CENTRAL_MOMENT_31, - Nyxus::Feature2D::CENTRAL_MOMENT_32, - Nyxus::Feature2D::CENTRAL_MOMENT_33, - - // Weighted central moments - Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_02, - Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_03, - Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_11, - Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_12, - Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_20, - Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_21, - Nyxus::Feature2D::WEIGHTED_CENTRAL_MOMENT_30, - - // weighted normalized central moments - Nyxus::Feature2D::WT_NORM_CTR_MOM_02, - Nyxus::Feature2D::WT_NORM_CTR_MOM_03, - Nyxus::Feature2D::WT_NORM_CTR_MOM_11, - Nyxus::Feature2D::WT_NORM_CTR_MOM_12, - Nyxus::Feature2D::WT_NORM_CTR_MOM_20, - Nyxus::Feature2D::WT_NORM_CTR_MOM_21, - Nyxus::Feature2D::WT_NORM_CTR_MOM_30, - - // Normalized central moments - Nyxus::Feature2D::NORM_CENTRAL_MOMENT_02, - Nyxus::Feature2D::NORM_CENTRAL_MOMENT_03, - Nyxus::Feature2D::NORM_CENTRAL_MOMENT_11, - Nyxus::Feature2D::NORM_CENTRAL_MOMENT_12, - Nyxus::Feature2D::NORM_CENTRAL_MOMENT_20, - Nyxus::Feature2D::NORM_CENTRAL_MOMENT_21, - Nyxus::Feature2D::NORM_CENTRAL_MOMENT_30, - - // Normalized (standardized) spatial moments - Nyxus::Feature2D::NORM_SPAT_MOMENT_00, - Nyxus::Feature2D::NORM_SPAT_MOMENT_01, - Nyxus::Feature2D::NORM_SPAT_MOMENT_02, - Nyxus::Feature2D::NORM_SPAT_MOMENT_03, - Nyxus::Feature2D::NORM_SPAT_MOMENT_10, - Nyxus::Feature2D::NORM_SPAT_MOMENT_11, - Nyxus::Feature2D::NORM_SPAT_MOMENT_12, - Nyxus::Feature2D::NORM_SPAT_MOMENT_13, - Nyxus::Feature2D::NORM_SPAT_MOMENT_20, - Nyxus::Feature2D::NORM_SPAT_MOMENT_21, - Nyxus::Feature2D::NORM_SPAT_MOMENT_22, - Nyxus::Feature2D::NORM_SPAT_MOMENT_23, - Nyxus::Feature2D::NORM_SPAT_MOMENT_30, - Nyxus::Feature2D::NORM_SPAT_MOMENT_31, - Nyxus::Feature2D::NORM_SPAT_MOMENT_32, - Nyxus::Feature2D::NORM_SPAT_MOMENT_33, - - // Hu's moments 1-7 - Nyxus::Feature2D::HU_M1, - Nyxus::Feature2D::HU_M2, - Nyxus::Feature2D::HU_M3, - Nyxus::Feature2D::HU_M4, - Nyxus::Feature2D::HU_M5, - Nyxus::Feature2D::HU_M6, - Nyxus::Feature2D::HU_M7, - - // Weighted Hu's moments 1-7 - Nyxus::Feature2D::WEIGHTED_HU_M1, - Nyxus::Feature2D::WEIGHTED_HU_M2, - Nyxus::Feature2D::WEIGHTED_HU_M3, - Nyxus::Feature2D::WEIGHTED_HU_M4, - Nyxus::Feature2D::WEIGHTED_HU_M5, - Nyxus::Feature2D::WEIGHTED_HU_M6, - Nyxus::Feature2D::WEIGHTED_HU_M7 - }; - - ImageMomentsFeature(); - - void calculate(LR& r); - void osized_add_online_pixel(size_t x, size_t y, uint32_t intensity); - void osized_calculate(LR& r, ImageLoader& imloader); - void save_value(std::vector>& feature_vals); - static void parallel_process_1_batch(size_t start, size_t end, std::vector* ptrLabels, std::unordered_map * ptrLabelData); - static void gpu_process_all_rois (const std::vector& ptrLabels, std::unordered_map & ptrLabelData, size_t batch_offset, size_t batch_len); - - // Compatibility with manual reduce - static bool required(const FeatureSet& fs) - { - return fs.anyEnabled (ImageMomentsFeature::featureset); - } - -private: - // Trivial ROI - double moment (const pixcloud& cloud, int p, int q); - double moment (const pixcloud& cloud, const intcloud& real_intens, int p, int q); - void calcOrigins (const pixcloud& cloud); - void calcOrigins (const pixcloud& cloud, const intcloud& real_valued_intensities); - double centralMom (const pixcloud& c, int p, int q); - double centralMom(const pixcloud& c, const intcloud& realintens, int p, int q); - double normRawMom (const pixcloud& cloud, int p, int q); - double normCentralMom (const pixcloud& c, int p, int q); - double normCentralMom (const pixcloud& cloud, const intcloud& realintens, int p, int q); - std::tuple calcHu_imp (double _02, double _03, double _11, double _12, double _20, double _21, double _30); - void calcRawMoments (const pixcloud& cloud); - void calcNormRawMoments (const pixcloud& cloud); - void calcNormCentralMoments (const pixcloud& cloud); - void calcWeightedRawMoments (const pixcloud& cloud); - void calcWeightedRawMoments (const pixcloud& cloud, const intcloud& real_valued_intensities); - void calcCentralMoments (const pixcloud& cloud); - void calcWeightedCentralMoments (const pixcloud& cloud, const intcloud& real_valued_intensities); - void calcWeightedNormCentralMoms (const pixcloud& cloud, const intcloud& realintens); - void calcHuInvariants (const pixcloud& cloud); - void calcWeightedHuInvariants (const pixcloud& cloud, const intcloud& real_valued_intensities); - - // Non-trivial ROI - double moment(const pixcloud_NT& cloud, int p, int q); - void calcOrigins(const pixcloud_NT& cloud); - double centralMom(const pixcloud_NT& c, int p, int q); - double normRawMom(const pixcloud_NT& cloud, int p, int q); - double normCentralMom(const pixcloud_NT& c, int p, int q); - std::tuple calcHuInvariants_imp(const pixcloud_NT& cloud); - void calcRawMoments(const pixcloud_NT& cloud); - void calcNormRawMoments(const pixcloud_NT& cloud); - void calcNormCentralMoments(const pixcloud_NT& cloud); - void calcWeightedRawMoments(const pixcloud_NT& cloud); - void calcCentralMoments(const pixcloud_NT& cloud); - void calcWeightedCentralMoments(const pixcloud_NT& cloud); - void calcHuInvariants(const pixcloud_NT& cloud); - void calcWeightedHuInvariants(const pixcloud_NT& cloud); - -#ifdef USE_GPU - void calculate_via_gpu(LR& r, size_t roi_index); -#endif - - StatsInt baseX = 0, baseY = 0; // cached min X and Y of the ROI. Reason - Pixel2's X and Y are absolute so we need to make them relative. Must be set in calculate() prior to calculating any 2D moment - double originOfX = 0, originOfY = 0; // centroids - double m00=0, m01=0, m02=0, m03=0, m10=0, m11=0, m12=0, m13=0, m20=0, m21=0, m22=0, m23=0, m30=0; // spatial moments - double wm00 = 0, wm01 = 0, wm02 = 0, wm03 = 0, wm10 = 0, wm11 = 0, wm12 = 0, wm20 = 0, wm21 = 0, wm30 = 0; // weighted spatial moments - double w00=0, w01=0, w02=0, w03=0, w10=0, w11=0, w12=0, w13=0, w20=0, w21=0, w22=0, w23=0, w30=0, w31=0, w32=0, w33=0; // normalized spatial moments - double nu02 = 0, nu03 = 0, nu11 = 0, nu12 = 0, nu20 = 0, nu21 = 0, nu30 = 0; // normalized central moments - double mu00=0, mu01=0, mu02=0, mu03=0, mu10=0, mu11=0, mu12=0, mu13=0, mu20=0, mu21=0, mu22=0, mu23=0, mu30=0, mu31=0, mu32=0, mu33=0; // central moments - double wmu02 = 0, wmu03 = 0, wmu11 = 0, wmu12 = 0, wmu20 = 0, wmu21 = 0, wmu30 = 0; // weighted central moments - double hm1 = 0, hm2 = 0, hm3 = 0, hm4 = 0, hm5 = 0, hm6 = 0, hm7 = 0; // Hu invariants - double wncm02 = 0, wncm03 = 0, wncm11 = 0, wncm12 = 0, wncm20 = 0, wncm21 = 0, wncm30 = 0; // weighted normalized central moments - double whm1 = 0, whm2 = 0, whm3 = 0, whm4 = 0, whm5 = 0, whm6 = 0, whm7 = 0; // weighted Hu invariants - - const double weighting_epsilon = 0.001; -}; - -namespace NyxusGpu -{ - bool ImageMomentsFeature_calculate(size_t roi_idx); -} - -namespace Nyxus -{ - extern size_t largest_roi_imatr_buf_len; // set in phase 2 - - /// @brief Copies integer pixel cloud intensities to real-valued vector - void copy_pixcloud_intensities (intcloud & dst, const pixcloud & src); - - /// @brief Applies to distance-to-contour weighting to intensities of pixel cloud - void apply_dist2contour_weighting( - // output - intcloud & weighted_intensities, - // input - const pixcloud & cloud, - const pixcloud & contour, - const double epsilon); -} - diff --git a/src/nyx/features_calc_workflow.cpp b/src/nyx/features_calc_workflow.cpp index 09a23a34..e3e5c564 100644 --- a/src/nyx/features_calc_workflow.cpp +++ b/src/nyx/features_calc_workflow.cpp @@ -28,7 +28,7 @@ #include "features/gldm.h" #include "features/hexagonality_polygonality.h" #include "features/ngtdm.h" -#include "features/image_moments.h" +#include "features/2d_geomoments.h" #include "features/moments.h" #include "features/neighbors.h" #include "features/caliper.h" diff --git a/src/nyx/featureset.cpp b/src/nyx/featureset.cpp index aa70fd8e..a335f43c 100644 --- a/src/nyx/featureset.cpp +++ b/src/nyx/featureset.cpp @@ -367,7 +367,7 @@ namespace Nyxus { "MEAN_FRAC", Feature2D::MEAN_FRAC }, { "RADIAL_CV", Feature2D::RADIAL_CV }, - // 2D image moments: + // 2D shape geometric moments: { "SPAT_MOMENT_00", Feature2D::SPAT_MOMENT_00}, { "SPAT_MOMENT_01", Feature2D::SPAT_MOMENT_01}, { "SPAT_MOMENT_02", Feature2D::SPAT_MOMENT_02}, @@ -467,6 +467,116 @@ namespace Nyxus { "WEIGHTED_HU_M6", Feature2D::WEIGHTED_HU_M6}, { "WEIGHTED_HU_M7", Feature2D::WEIGHTED_HU_M7}, + // 2D intensity geometric moments + + // -- intensity raw moments + { "IMOM_RM_00", Feature2D::IMOM_RM_00 }, + { "IMOM_RM_01", Feature2D::IMOM_RM_01 }, + { "IMOM_RM_02", Feature2D::IMOM_RM_02 }, + { "IMOM_RM_03", Feature2D::IMOM_RM_03 }, + { "IMOM_RM_10", Feature2D::IMOM_RM_10 }, + { "IMOM_RM_11", Feature2D::IMOM_RM_11 }, + { "IMOM_RM_12", Feature2D::IMOM_RM_12 }, + { "IMOM_RM_13", Feature2D::IMOM_RM_13 }, + { "IMOM_RM_20", Feature2D::IMOM_RM_20 }, + { "IMOM_RM_21", Feature2D::IMOM_RM_21 }, + { "IMOM_RM_22", Feature2D::IMOM_RM_22 }, + { "IMOM_RM_23", Feature2D::IMOM_RM_23 }, + { "IMOM_RM_30", Feature2D::IMOM_RM_30 }, + + // -- intensity central moments + { "IMOM_CM_00", Feature2D::IMOM_CM_00 }, + { "IMOM_CM_01", Feature2D::IMOM_CM_01 }, + { "IMOM_CM_02", Feature2D::IMOM_CM_02 }, + { "IMOM_CM_03", Feature2D::IMOM_CM_03 }, + { "IMOM_CM_10", Feature2D::IMOM_CM_10 }, + { "IMOM_CM_11", Feature2D::IMOM_CM_11 }, + { "IMOM_CM_12", Feature2D::IMOM_CM_12 }, + { "IMOM_CM_13", Feature2D::IMOM_CM_13 }, + { "IMOM_CM_20", Feature2D::IMOM_CM_20 }, + { "IMOM_CM_21", Feature2D::IMOM_CM_21 }, + { "IMOM_CM_22", Feature2D::IMOM_CM_22 }, + { "IMOM_CM_23", Feature2D::IMOM_CM_23 }, + { "IMOM_CM_30", Feature2D::IMOM_CM_30 }, + { "IMOM_CM_31", Feature2D::IMOM_CM_31 }, + { "IMOM_CM_32", Feature2D::IMOM_CM_32 }, + { "IMOM_CM_33", Feature2D::IMOM_CM_33 }, + + // -- intensity normalized raw moments + { "IMOM_NRM_00", Feature2D::IMOM_NRM_00 }, + { "IMOM_NRM_01", Feature2D::IMOM_NRM_01 }, + { "IMOM_NRM_02", Feature2D::IMOM_NRM_02 }, + { "IMOM_NRM_03", Feature2D::IMOM_NRM_03 }, + { "IMOM_NRM_10", Feature2D::IMOM_NRM_10 }, + { "IMOM_NRM_11", Feature2D::IMOM_NRM_11 }, + { "IMOM_NRM_12", Feature2D::IMOM_NRM_12 }, + { "IMOM_NRM_13", Feature2D::IMOM_NRM_13 }, + { "IMOM_NRM_20", Feature2D::IMOM_NRM_20 }, + { "IMOM_NRM_21", Feature2D::IMOM_NRM_21 }, + { "IMOM_NRM_22", Feature2D::IMOM_NRM_22 }, + { "IMOM_NRM_23", Feature2D::IMOM_NRM_23 }, + { "IMOM_NRM_30", Feature2D::IMOM_NRM_30 }, + { "IMOM_NRM_31", Feature2D::IMOM_NRM_31 }, + { "IMOM_NRM_32", Feature2D::IMOM_NRM_32 }, + { "IMOM_NRM_33", Feature2D::IMOM_NRM_33 }, + + // -- intensity normalized central moments + { "IMOM_NCM_02", Feature2D::IMOM_NCM_02 }, + { "IMOM_NCM_03", Feature2D::IMOM_NCM_03 }, + { "IMOM_NCM_11", Feature2D::IMOM_NCM_11 }, + { "IMOM_NCM_12", Feature2D::IMOM_NCM_12 }, + { "IMOM_NCM_20", Feature2D::IMOM_NCM_20 }, + { "IMOM_NCM_21", Feature2D::IMOM_NCM_21 }, + { "IMOM_NCM_30", Feature2D::IMOM_NCM_30 }, + + // -- intensity Hu's moments 1-7 + { "IMOM_HU1", Feature2D::IMOM_HU1 }, + { "IMOM_HU2", Feature2D::IMOM_HU2 }, + { "IMOM_HU3", Feature2D::IMOM_HU3 }, + { "IMOM_HU4", Feature2D::IMOM_HU4 }, + { "IMOM_HU5", Feature2D::IMOM_HU5 }, + { "IMOM_HU6", Feature2D::IMOM_HU6 }, + { "IMOM_HU7", Feature2D::IMOM_HU7 }, + + // -- intensity weighted raw moments + { "IMOM_WRM_00", Feature2D::IMOM_WRM_00 }, + { "IMOM_WRM_01", Feature2D::IMOM_WRM_01 }, + { "IMOM_WRM_02", Feature2D::IMOM_WRM_02 }, + { "IMOM_WRM_03", Feature2D::IMOM_WRM_03 }, + { "IMOM_WRM_10", Feature2D::IMOM_WRM_10 }, + { "IMOM_WRM_11", Feature2D::IMOM_WRM_11 }, + { "IMOM_WRM_12", Feature2D::IMOM_WRM_12 }, + { "IMOM_WRM_20", Feature2D::IMOM_WRM_20 }, + { "IMOM_WRM_21", Feature2D::IMOM_WRM_21 }, + { "IMOM_WRM_30", Feature2D::IMOM_WRM_30 }, + + // -- intensity weighted central moments + { "IMOM_WCM_02", Feature2D::IMOM_WCM_02 }, + { "IMOM_WCM_03", Feature2D::IMOM_WCM_03 }, + { "IMOM_WCM_11", Feature2D::IMOM_WCM_11 }, + { "IMOM_WCM_12", Feature2D::IMOM_WCM_12 }, + { "IMOM_WCM_20", Feature2D::IMOM_WCM_20 }, + { "IMOM_WCM_21", Feature2D::IMOM_WCM_21 }, + { "IMOM_WCM_30", Feature2D::IMOM_WCM_30 }, + + // -- intensity weighted normalized central moments + { "IMOM_WNCM_02", Feature2D::IMOM_WNCM_02 }, + { "IMOM_WNCM_03", Feature2D::IMOM_WNCM_03 }, + { "IMOM_WNCM_11", Feature2D::IMOM_WNCM_11 }, + { "IMOM_WNCM_12", Feature2D::IMOM_WNCM_12 }, + { "IMOM_WNCM_20", Feature2D::IMOM_WNCM_20 }, + { "IMOM_WNCM_21", Feature2D::IMOM_WNCM_21 }, + { "IMOM_WNCM_30", Feature2D::IMOM_WNCM_30 }, + + // -- intensity weighted Hu's moments 1-7 + { "IMOM_WHU1", Feature2D::IMOM_WHU1 }, + { "IMOM_WHU2", Feature2D::IMOM_WHU2 }, + { "IMOM_WHU3", Feature2D::IMOM_WHU3 }, + { "IMOM_WHU4", Feature2D::IMOM_WHU4 }, + { "IMOM_WHU5", Feature2D::IMOM_WHU5 }, + { "IMOM_WHU6", Feature2D::IMOM_WHU6 }, + { "IMOM_WHU7", Feature2D::IMOM_WHU7 }, + // Gabor filter based feature: { "GABOR", Feature2D::GABOR }, }; @@ -502,7 +612,9 @@ namespace Nyxus { "*ALL_BUT_GLCM*", Fgroup2D::FG2_ALL_BUT_GLCM }, { "*ALL_EASY*", Fgroup2D::FG2_EASY }, { "*ALL_NEIGHBOR*", Fgroup2D::FG2_NEIG }, - { "*2DMOMENTS*", Fgroup2D::FG2_MOMENTS }, + { "*GEOMOMS*", Fgroup2D::FG2_GEOMOMENTS }, + { "*IGEOMOMS*", Fgroup2D::FG2_GEOMOMENTS_I }, + { "*SGEOMOMS*", Fgroup2D::FG2_GEOMOMENTS_S }, }; std::map UserFacing_3D_featureNames = diff --git a/src/nyx/featureset.h b/src/nyx/featureset.h index f439b027..4e0e549e 100644 --- a/src/nyx/featureset.h +++ b/src/nyx/featureset.h @@ -356,7 +356,9 @@ namespace Nyxus RADIAL_CV, ZERNIKE2D, - // Spatial (raw) moments + // Shape geometric moments + + // -- shape raw moments SPAT_MOMENT_00, SPAT_MOMENT_01, SPAT_MOMENT_02, @@ -371,7 +373,7 @@ namespace Nyxus SPAT_MOMENT_23, SPAT_MOMENT_30, - // Central moments + // -- shape central moments CENTRAL_MOMENT_00, CENTRAL_MOMENT_01, CENTRAL_MOMENT_02, @@ -389,7 +391,7 @@ namespace Nyxus CENTRAL_MOMENT_32, CENTRAL_MOMENT_33, - // Normalized (standardized) spatial moments + // -- shape normalized raw moments NORM_SPAT_MOMENT_00, NORM_SPAT_MOMENT_01, NORM_SPAT_MOMENT_02, @@ -407,7 +409,7 @@ namespace Nyxus NORM_SPAT_MOMENT_32, NORM_SPAT_MOMENT_33, - // Normalized central moments + // -- shape normalized central moments NORM_CENTRAL_MOMENT_02, NORM_CENTRAL_MOMENT_03, NORM_CENTRAL_MOMENT_11, @@ -416,7 +418,7 @@ namespace Nyxus NORM_CENTRAL_MOMENT_21, NORM_CENTRAL_MOMENT_30, - // Hu's moments 1-7 + // -- shape Hu's moments 1-7 HU_M1, HU_M2, HU_M3, @@ -425,7 +427,7 @@ namespace Nyxus HU_M6, HU_M7, - // Weighted spatial moments + // -- shape weighted raw moments WEIGHTED_SPAT_MOMENT_00, WEIGHTED_SPAT_MOMENT_01, WEIGHTED_SPAT_MOMENT_02, @@ -437,7 +439,7 @@ namespace Nyxus WEIGHTED_SPAT_MOMENT_21, WEIGHTED_SPAT_MOMENT_30, - // Weighted central moments + // -- shape weighted central moments WEIGHTED_CENTRAL_MOMENT_02, WEIGHTED_CENTRAL_MOMENT_03, WEIGHTED_CENTRAL_MOMENT_11, @@ -446,7 +448,7 @@ namespace Nyxus WEIGHTED_CENTRAL_MOMENT_21, WEIGHTED_CENTRAL_MOMENT_30, - // Weighted normalized central moments + // -- shape weighted normalized central moments WT_NORM_CTR_MOM_02, WT_NORM_CTR_MOM_03, WT_NORM_CTR_MOM_11, @@ -455,7 +457,7 @@ namespace Nyxus WT_NORM_CTR_MOM_21, WT_NORM_CTR_MOM_30, - // Weighted Hu's moments 1-7 + // -- shape weighted Hu's moments 1-7 WEIGHTED_HU_M1, WEIGHTED_HU_M2, WEIGHTED_HU_M3, @@ -464,6 +466,116 @@ namespace Nyxus WEIGHTED_HU_M6, WEIGHTED_HU_M7, + // Intensity geometric moments + + // -- intensity raw moments + IMOM_RM_00, + IMOM_RM_01, + IMOM_RM_02, + IMOM_RM_03, + IMOM_RM_10, + IMOM_RM_11, + IMOM_RM_12, + IMOM_RM_13, + IMOM_RM_20, + IMOM_RM_21, + IMOM_RM_22, + IMOM_RM_23, + IMOM_RM_30, + + // -- intensity central moments + IMOM_CM_00, + IMOM_CM_01, + IMOM_CM_02, + IMOM_CM_03, + IMOM_CM_10, + IMOM_CM_11, + IMOM_CM_12, + IMOM_CM_13, + IMOM_CM_20, + IMOM_CM_21, + IMOM_CM_22, + IMOM_CM_23, + IMOM_CM_30, + IMOM_CM_31, + IMOM_CM_32, + IMOM_CM_33, + + // -- intensity normalized raw moments + IMOM_NRM_00, + IMOM_NRM_01, + IMOM_NRM_02, + IMOM_NRM_03, + IMOM_NRM_10, + IMOM_NRM_11, + IMOM_NRM_12, + IMOM_NRM_13, + IMOM_NRM_20, + IMOM_NRM_21, + IMOM_NRM_22, + IMOM_NRM_23, + IMOM_NRM_30, + IMOM_NRM_31, + IMOM_NRM_32, + IMOM_NRM_33, + + // -- intensity normalized central moments + IMOM_NCM_02, + IMOM_NCM_03, + IMOM_NCM_11, + IMOM_NCM_12, + IMOM_NCM_20, + IMOM_NCM_21, + IMOM_NCM_30, + + // -- intensity Hu's moments 1-7 + IMOM_HU1, + IMOM_HU2, + IMOM_HU3, + IMOM_HU4, + IMOM_HU5, + IMOM_HU6, + IMOM_HU7, + + // -- intensity weighted raw moments + IMOM_WRM_00, + IMOM_WRM_01, + IMOM_WRM_02, + IMOM_WRM_03, + IMOM_WRM_10, + IMOM_WRM_11, + IMOM_WRM_12, + IMOM_WRM_20, + IMOM_WRM_21, + IMOM_WRM_30, + + // -- intensity weighted central moments + IMOM_WCM_02, + IMOM_WCM_03, + IMOM_WCM_11, + IMOM_WCM_12, + IMOM_WCM_20, + IMOM_WCM_21, + IMOM_WCM_30, + + // -- intensity weighted normalized central moments + IMOM_WNCM_02, + IMOM_WNCM_03, + IMOM_WNCM_11, + IMOM_WNCM_12, + IMOM_WNCM_20, + IMOM_WNCM_21, + IMOM_WNCM_30, + + // -- intensity weighted Hu's moments 1-7 + IMOM_WHU1, + IMOM_WHU2, + IMOM_WHU3, + IMOM_WHU4, + IMOM_WHU5, + IMOM_WHU6, + IMOM_WHU7, + _COUNT_ }; @@ -578,7 +690,9 @@ namespace Nyxus FG2_ALL_BUT_GLCM, FG2_EASY, FG2_NEIG, - FG2_MOMENTS, + FG2_GEOMOMENTS, // shape and intensity geometric moments + FG2_GEOMOMENTS_I, // intensity geometric moments + FG2_GEOMOMENTS_S, // shape geometric moments _COUNT_ }; diff --git a/src/nyx/gpu/geomoments.cuh b/src/nyx/gpu/geomoments.cuh index 6fa12b75..1109108d 100644 --- a/src/nyx/gpu/geomoments.cuh +++ b/src/nyx/gpu/geomoments.cuh @@ -3,6 +3,14 @@ namespace NyxusGpu { + inline __device__ double int_pow(double a, int b) + { + double retval = 1.0; + for (int i = 0; i < b; i++) + retval *= a; + return retval; + } + bool ImageMomentsFeature_calcOrigins ( // output gpureal* d_intermediate, @@ -17,6 +25,7 @@ namespace NyxusGpu // output gpureal* d_intermediate, // input + bool need_shape_moments, const Pixel2* d_roicloud, size_t cloud_len, double* d_prereduce, // reduction helper [roi_cloud_len] @@ -27,6 +36,7 @@ namespace NyxusGpu // output gpureal* d_intermediate, // input + bool need_shape_moments, const Pixel2* d_roicloud, size_t cloud_len, double* d_prereduce, // reduction helper [roi_cloud_len] void* d_temp_storage, diff --git a/src/nyx/gpu/geomoments_central.cu b/src/nyx/gpu/geomoments_central.cu index bbc67c37..e74eb8ab 100644 --- a/src/nyx/gpu/geomoments_central.cu +++ b/src/nyx/gpu/geomoments_central.cu @@ -11,16 +11,6 @@ namespace NyxusGpu { - __device__ double pow_pos_int_central(double a, int b) - { - if (b == 0) - return 1.0; - double retval = 1.0; - for (int i = 0; i < b; i++) - retval *= a; - return retval; - } - __global__ void kerCentralMomentAll_snu( // out double* d_prereduce00, @@ -40,6 +30,7 @@ namespace NyxusGpu double* d_prereduce32, double* d_prereduce33, // in + int ipow, const Pixel2* d_roicloud, size_t cloudlen, gpureal* origin_x, @@ -50,7 +41,7 @@ namespace NyxusGpu if (tid >= cloudlen) return; - float I = 1, // <--shape moments-- d_roicloud[tid].inten, + float I = int_pow (d_roicloud[tid].inten, ipow), OX = *origin_x, OY = *origin_y, X = float(d_roicloud[tid].x) - OX, @@ -160,6 +151,7 @@ namespace NyxusGpu // out gpureal* d_result, // in + bool need_shape_moments, const Pixel2* d_roicloud, size_t cloudlen, gpureal* origin_x, @@ -168,6 +160,9 @@ namespace NyxusGpu void* d_devreduce_tempstorage, size_t& devreduce_tempstorage_szb) { + // prepare the shape/intensity selector + int ipow = need_shape_moments ? 0 : 1; + // prepare lanes of partial totals double* d_pr00 = d_prereduce, * d_pr01 = &d_prereduce[cloudlen], @@ -194,7 +189,7 @@ namespace NyxusGpu d_pr20, d_pr21, d_pr22, d_pr23, d_pr30, d_pr31, d_pr32, d_pr33, // in - d_roicloud, cloudlen, origin_x, origin_y); + ipow, d_roicloud, cloudlen, origin_x, origin_y); CHECKERR(cudaDeviceSynchronize()); CHECKERR(cudaGetLastError()); @@ -286,12 +281,13 @@ namespace NyxusGpu // output gpureal* d_intermed, // input + bool need_shape_moments, const Pixel2* d_roicloud, size_t cloud_len, double* d_prereduce, // reduction helper [roi_cloud_len] void* d_temp_storage, size_t& temp_storage_szb) { - if (drvCentralMomentAll__snu(d_intermed, d_roicloud, cloud_len, &d_intermed[ORGX], &d_intermed[ORGY], d_prereduce, d_temp_storage, temp_storage_szb) == false) + if (drvCentralMomentAll__snu(d_intermed, need_shape_moments, d_roicloud, cloud_len, &d_intermed[ORGX], &d_intermed[ORGY], d_prereduce, d_temp_storage, temp_storage_szb) == false) return false; return true; diff --git a/src/nyx/gpu/geomoments_main.cu b/src/nyx/gpu/geomoments_main.cu index b543cb2c..d92dfe93 100644 --- a/src/nyx/gpu/geomoments_main.cu +++ b/src/nyx/gpu/geomoments_main.cu @@ -17,6 +17,7 @@ namespace NyxusGpu // output RealPixIntens* d_realintens_buf, // input + bool need_shape_moments, const Pixel2* d_roicloud, size_t cloud_len, const Pixel2* d_roicontour, @@ -28,7 +29,7 @@ namespace NyxusGpu bool ImageMomentsFeature_calcNormSpatialMoments3(gpureal* d_state); - bool ImageMomentsFeature_calculate (size_t roi_index) + bool GeoMoments2D_calculate (size_t roi_index, bool need_shape_moments) { // context of ROI #roi_index: // @@ -53,6 +54,7 @@ namespace NyxusGpu // out state, // in + need_shape_moments, d_cloud, cloud_len, d_prereduce, @@ -77,6 +79,7 @@ namespace NyxusGpu // out state, // in + need_shape_moments, d_cloud, cloud_len, d_prereduce, @@ -102,6 +105,7 @@ namespace NyxusGpu //==== Weighted intensities if (!ImageMomentsFeature_calc_weighted_intens( d_realintens, // output + need_shape_moments, d_cloud, cloud_len, d_contour, diff --git a/src/nyx/gpu/geomoments_raw.cu b/src/nyx/gpu/geomoments_raw.cu index 53bb2716..299a4aa7 100644 --- a/src/nyx/gpu/geomoments_raw.cu +++ b/src/nyx/gpu/geomoments_raw.cu @@ -19,14 +19,6 @@ namespace NyxusGpu void* d_devreduce_tempstorage, size_t& devreduce_tempstorage_szb); - __device__ double pow_pos_int_raw(double a, int b) - { - double retval = 1.0; - for (int i = 0; i < b; i++) - retval *= a; - return retval; - } - __global__ void kerRawMoment( double* d_prereduce, const Pixel2* d_roicloud, @@ -49,7 +41,7 @@ namespace NyxusGpu localX = x_ - x0, localY = y_ - y0; - d_prereduce[tid] = inten_ * pow_pos_int_raw(localX, p) * pow_pos_int_raw(localY, q); + d_prereduce[tid] = inten_ * int_pow(localX, p) * int_pow(localY, q); } bool drvRawMoment__snu( @@ -113,6 +105,7 @@ namespace NyxusGpu double* d_prereduce32, double* d_prereduce33, // in + int ipow, const Pixel2* d_roicloud, size_t cloudlen) { @@ -121,7 +114,7 @@ namespace NyxusGpu if (tid >= cloudlen) return; - float I = 1, //<--shape moments, not intensity-- = d_roicloud[tid].inten, + float I = int_pow (d_roicloud[tid].inten, ipow), X = d_roicloud[tid].x, // = d_roicloud[tid].x - base_x, Y = d_roicloud[tid].y; // = d_roicloud[tid].y - base_y; @@ -159,12 +152,16 @@ namespace NyxusGpu // out gpureal* d_result, // in + bool need_shape_moments, const Pixel2* d_roicloud, size_t cloudlen, double* d_prereduce, void* d_devreduce_tempstorage, size_t& devreduce_tempstorage_szb) { + // prepare the shape/intensity selector + int ipow = need_shape_moments ? 0 : 1; + // prepare lanes of partial totals double* d_pr00 = d_prereduce, * d_pr01 = &d_prereduce[cloudlen], @@ -191,7 +188,7 @@ namespace NyxusGpu d_pr20, d_pr21, d_pr22, d_pr23, d_pr30, d_pr31, d_pr32, d_pr33, // in - d_roicloud, cloudlen); + ipow, d_roicloud, cloudlen); CHECKERR(cudaDeviceSynchronize()); CHECKERR(cudaGetLastError()); @@ -332,12 +329,13 @@ namespace NyxusGpu // output gpureal* d_intermed, // input + bool need_shape_moments, const Pixel2* d_roicloud, size_t cloud_len, double* d_prereduce, // reduction helper [roi_cloud_len] void* d_temp_storage, size_t& temp_storage_szb) { - if (drvRawMomentAll__snu(d_intermed, d_roicloud, cloud_len, d_prereduce, d_temp_storage, temp_storage_szb) == false) + if (drvRawMomentAll__snu(d_intermed, need_shape_moments, d_roicloud, cloud_len, d_prereduce, d_temp_storage, temp_storage_szb) == false) return false; return true; diff --git a/src/nyx/gpu/geomoments_weighting.cu b/src/nyx/gpu/geomoments_weighting.cu index 4121e99e..ee043aca 100644 --- a/src/nyx/gpu/geomoments_weighting.cu +++ b/src/nyx/gpu/geomoments_weighting.cu @@ -7,6 +7,7 @@ #include "../features/image_matrix.h" #include "gpu.h" +#include "geomoments.cuh" namespace NyxusGpu { @@ -57,6 +58,7 @@ namespace NyxusGpu // output RealPixIntens* d_realintens, // input + int ipow, const Pixel2* d_roicloud, size_t cloud_len, const Pixel2* d_roicontour, @@ -76,20 +78,24 @@ namespace NyxusGpu double dist = std::sqrt(mind2); // weighted intensity - d_realintens[pxIdx] = 1.0 / (dist + WEIGHTING_EPSILON); + d_realintens[pxIdx] = int_pow(d_roicloud[pxIdx].inten, ipow) / (dist + WEIGHTING_EPSILON); } bool ImageMomentsFeature_calc_weighted_intens( // output RealPixIntens* d_realintens_buf, // input + bool need_shape_moments, const Pixel2* d_roicloud, size_t cloud_len, const Pixel2* d_roicontour, size_t contour_len) { + // prepare the shape/intensity selector + int ipow = need_shape_moments ? 0 : 1; + int nb = whole_chunks2(cloud_len, blockSize); - kerCalcWeightedImage3 << < nb, blockSize >> > (d_realintens_buf, d_roicloud, cloud_len, d_roicontour, contour_len); + kerCalcWeightedImage3 << < nb, blockSize >> > (d_realintens_buf, ipow, d_roicloud, cloud_len, d_roicontour, contour_len); cudaError_t ok = cudaDeviceSynchronize(); CHECKERR(ok); diff --git a/src/nyx/reduce_by_feature.cpp b/src/nyx/reduce_by_feature.cpp index 488b425b..eada3c77 100644 --- a/src/nyx/reduce_by_feature.cpp +++ b/src/nyx/reduce_by_feature.cpp @@ -29,7 +29,7 @@ #include "features/gldm.h" #include "features/hexagonality_polygonality.h" #include "features/ngtdm.h" -#include "features/image_moments.h" +#include "features/2d_geomoments.h" #include "features/intensity.h" #include "features/moments.h" #include "features/neighbors.h" @@ -210,24 +210,48 @@ namespace Nyxus } //==== Moments - if (ImageMomentsFeature::required(theFeatureSet)) + + // -- intensity moments + if (Imoms2D_feature::required(theFeatureSet)) + { + #ifndef USE_GPU + STOPWATCH("I-moments/I-moments/GM/#FFFACD", "\t="); + runParallel (Imoms2D_feature::parallel_process_1_batch, nThr, workPerThread, jobSize, &roiLabelsVector, &roiData); + #else + // Did the user opted out from using GPU? + if (theEnvironment.using_gpu() == false) + { + // Route calculation via the regular CPU-multithreaded way + STOPWATCH("I-moments/I-moments/GM/#FFFACD", "\t="); + runParallel (Imoms2D_feature::parallel_process_1_batch, nThr, workPerThread, jobSize, &roiLabelsVector, &roiData); + } + else + { + // Calculate the feature via GPGPU + STOPWATCH("GPU-I-moments/GPU-I-moments/GM/#FFFACD", "\t="); + Imoms2D_feature::gpu_process_all_rois (roiLabelsVector, roiData, 0/*batch_offset*/, roiLabelsVector.size()/*batch_len*/); + } + #endif + } + // -- shape moments + if (Smoms2D_feature::required (theFeatureSet)) { #ifndef USE_GPU - STOPWATCH("Moments/Moments/GM/#FFFACD", "\t="); - runParallel(ImageMomentsFeature::parallel_process_1_batch, nThr, workPerThread, jobSize, &roiLabelsVector, &roiData); + STOPWATCH("S-moments/S-moments/GM/#FFFACD", "\t="); + runParallel (Smoms2D_feature::parallel_process_1_batch, nThr, workPerThread, jobSize, &roiLabelsVector, &roiData); #else // Did the user opted out from using GPU? if (theEnvironment.using_gpu() == false) { // Route calculation via the regular CPU-multithreaded way - STOPWATCH("Moments/Moments/GM/#FFFACD", "\t="); - runParallel(ImageMomentsFeature::parallel_process_1_batch, nThr, workPerThread, jobSize, &roiLabelsVector, &roiData); + STOPWATCH("S-moments/S-moments/GM/#FFFACD", "\t="); + runParallel (Smoms2D_feature::parallel_process_1_batch, nThr, workPerThread, jobSize, &roiLabelsVector, &roiData); } else { - // Calculate the feature via GPU - STOPWATCH("GPU-Moments/GPU-Moments/GM/#FFFACD", "\t="); - ImageMomentsFeature::gpu_process_all_rois(roiLabelsVector, roiData, 0/*batch_offset*/, roiLabelsVector.size()/*batch_len*/); + // Calculate the feature via GPGPU + STOPWATCH("GPU-S-moments/GPU-S-moments/GM/#FFFACD", "\t="); + Smoms2D_feature::gpu_process_all_rois (roiLabelsVector, roiData, 0/*batch_offset*/, roiLabelsVector.size()/*batch_len*/); } #endif } diff --git a/src/nyx/reduce_trivial_rois.cpp b/src/nyx/reduce_trivial_rois.cpp index 4d0e3ff6..6adb94eb 100644 --- a/src/nyx/reduce_trivial_rois.cpp +++ b/src/nyx/reduce_trivial_rois.cpp @@ -33,7 +33,7 @@ #include "features/hexagonality_polygonality.h" #include "features/ngldm.h" #include "features/ngtdm.h" -#include "features/image_moments.h" +#include "features/2d_geomoments.h" #include "features/intensity.h" #include "features/moments.h" #include "features/neighbors.h" @@ -85,7 +85,8 @@ namespace Nyxus || GeodeticLengthThicknessFeature::required(theFeatureSet) || NeighborsFeature::required(theFeatureSet) || RoiRadiusFeature::required(theFeatureSet) - || ImageMomentsFeature::required(theFeatureSet)) + || Imoms2D_feature::required(theFeatureSet) + || Smoms2D_feature::required(theFeatureSet) ) { STOPWATCH("Morphology/Contour/C/#4aaaea", "\t="); runParallel(ContourFeature::reduce, n_threads, work_per_thread, job_size, &L, &roiData); @@ -219,10 +220,11 @@ namespace Nyxus //==== Share ROI data (clouds, contours) with GPU-enabled features - bool doMoms = ImageMomentsFeature::required (theFeatureSet), + bool doImoms = Imoms2D_feature::required(theFeatureSet), + doSmoms = Smoms2D_feature::required(theFeatureSet), doEros = ErosionPixelsFeature::required (theFeatureSet), doGabor = GaborFeature::required (theFeatureSet); - if (doEros || doMoms || doGabor) + if (doEros || doImoms || doSmoms || doGabor) { if (theEnvironment.using_gpu()) { @@ -248,10 +250,16 @@ namespace Nyxus ErosionPixelsFeature::gpu_process_all_rois(L, roiData, off_this_batch, actual_batch_len); } - if (doMoms) + if (doImoms) { - STOPWATCH("GPU-Moments/GPU-Moments/GM/#FFFACD", "\t="); - ImageMomentsFeature::gpu_process_all_rois (L, roiData, off_this_batch, actual_batch_len); + STOPWATCH("GPU-I-moments/GPU-I-moments/GM/#FFFACD", "\t="); + Imoms2D_feature::gpu_process_all_rois (L, roiData, off_this_batch, actual_batch_len); + } + + if (doSmoms) + { + STOPWATCH("GPU-S-moments/GPU-S-moments/GM/#FFFACD", "\t="); + Smoms2D_feature::gpu_process_all_rois (L, roiData, off_this_batch, actual_batch_len); } if (doGabor) @@ -271,10 +279,15 @@ namespace Nyxus STOPWATCH("Morphology/Erosion/Er/#4aaaea", "\t="); runParallel(ErosionPixelsFeature::parallel_process_1_batch, n_threads, work_per_thread, job_size, &L, &roiData); } - if (doMoms) + if (doImoms) + { + STOPWATCH("I-moments/I-moments/GM/#FFFACE", "\t="); + runParallel (Imoms2D_feature::parallel_process_1_batch, n_threads, work_per_thread, job_size, &L, &roiData); + } + if (doSmoms) { - STOPWATCH("Moments/Moments/GM/#FFFACE", "\t="); - runParallel(ImageMomentsFeature::parallel_process_1_batch, n_threads, work_per_thread, job_size, &L, &roiData); + STOPWATCH("S-moments/S-moments/GM/#FFFACE", "\t="); + runParallel (Smoms2D_feature::parallel_process_1_batch, n_threads, work_per_thread, job_size, &L, &roiData); } if (doGabor) { @@ -292,10 +305,16 @@ namespace Nyxus runParallel(ErosionPixelsFeature::parallel_process_1_batch, n_threads, work_per_thread, job_size, &L, &roiData); } - if (ImageMomentsFeature::required(theFeatureSet)) + if (doImoms) + { + STOPWATCH("I-moments/I-moments/GM/#FFFACE", "\t="); + runParallel(Imoms2D_feature::parallel_process_1_batch, n_threads, work_per_thread, job_size, &L, &roiData); + } + + if (doSmoms) { - STOPWATCH("Moments/Moments/GM/#FFFACF", "\t="); - runParallel(ImageMomentsFeature::parallel_process_1_batch, n_threads, work_per_thread, job_size, &L, &roiData); + STOPWATCH("S-moments/S-moments/GM/#FFFACE", "\t="); + runParallel(Smoms2D_feature::parallel_process_1_batch, n_threads, work_per_thread, job_size, &L, &roiData); } if (GaborFeature::required(theFeatureSet)) From 7e7f0ce7ec932fc1c237b26048c8d11ada4d4616 Mon Sep 17 00:00:00 2001 From: Andriy Date: Thu, 19 Sep 2024 12:24:01 -0400 Subject: [PATCH 2/3] + --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 44e8f2b7..9004b42d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,7 +163,7 @@ set(SOURCE src/nyx/features/image_matrix_nontriv.cpp src/nyx/features/2d_geomoments.cpp src/nyx/features/2d_geomoments_basic.cpp - src/nyx/features/2d_geomoments_nt.cpp + src/nyx/features/2d_geomoments_basic_nt.cpp src/nyx/features/intensity.cpp src/nyx/features/intensity_3d.cpp src/nyx/features/neighbors.cpp From f7d199f177563ed3e7b47cda8c542fb8921e41c3 Mon Sep 17 00:00:00 2001 From: Andriy Date: Fri, 20 Sep 2024 05:23:18 -0400 Subject: [PATCH 3/3] ++ --- src/nyx/reduce_trivial_rois.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nyx/reduce_trivial_rois.cpp b/src/nyx/reduce_trivial_rois.cpp index 6adb94eb..75a4cf8f 100644 --- a/src/nyx/reduce_trivial_rois.cpp +++ b/src/nyx/reduce_trivial_rois.cpp @@ -305,13 +305,13 @@ namespace Nyxus runParallel(ErosionPixelsFeature::parallel_process_1_batch, n_threads, work_per_thread, job_size, &L, &roiData); } - if (doImoms) + if (Imoms2D_feature::required(theFeatureSet)) { STOPWATCH("I-moments/I-moments/GM/#FFFACE", "\t="); runParallel(Imoms2D_feature::parallel_process_1_batch, n_threads, work_per_thread, job_size, &L, &roiData); } - if (doSmoms) + if (Smoms2D_feature::required(theFeatureSet)) { STOPWATCH("S-moments/S-moments/GM/#FFFACE", "\t="); runParallel(Smoms2D_feature::parallel_process_1_batch, n_threads, work_per_thread, job_size, &L, &roiData);