8 #define CV_PCA_DATA_AS_ROW 150
12 #include <pcl/common/common.h>
13 #include <pcl/common/transforms.h>
14 #include <pcl/kdtree/kdtree_flann.h>
15 #include <pcl/point_cloud.h>
25 #include <QMainWindow>
26 #include <QMessageBox>
29 #include <unordered_set>
46 #define _USE_MATH_DEFINES
53 #include <opencv2/core/core.hpp>
54 #include <opencv2/highgui/highgui.hpp>
55 #include <opencv2/imgcodecs.hpp>
56 #include <opencv2/imgproc/imgproc.hpp>
57 #include <opencv2/opencv.hpp>
77 ccAutoSeg::ccAutoSeg(QObject* parent)
86 double stddev(std::vector<double>
const& func) {
87 double mean = std::accumulate(func.begin(), func.end(), 0.0) / func.size();
88 double sq_sum = std::inner_product(
89 func.begin(), func.end(), func.begin(), 0.0,
90 [](
double const& x,
double const& y) { return x + y; },
91 [mean](
double const& x,
double const& y) {
92 return (x - mean) * (y - mean);
94 return std::sqrt(sq_sum / (func.size() - 1));
103 timeinfo = localtime(&rawtime);
105 strftime(buffer,
sizeof(buffer),
"%H:%M:%S", timeinfo);
106 std::string str(buffer);
116 pcl::PointCloud<pcl::PointXYZRGB>::Ptr pcl_cloud(
117 new pcl::PointCloud<pcl::PointXYZRGB>);
118 pcl_cloud->width = cloud->
size();
119 pcl_cloud->height = 1;
120 pcl_cloud->points.resize(pcl_cloud->width * pcl_cloud->height);
122 std::vector<int> v(cloud->
size());
123 std::iota(v.begin(), v.end(), 0);
124 std::random_device rd;
125 std::mt19937 gen(rd());
126 std::shuffle(v.begin(), v.end(), rd);
127 v.erase(v.begin(), v.begin() + (
int)
floor(cloud->
size()));
129 for (
size_t i = 0; i < cloud->
size(); i++) {
130 pcl_cloud->points[i].x = cloud->
getPoint(i)->
x;
131 pcl_cloud->points[i].y = cloud->
getPoint(i)->
y;
132 pcl_cloud->points[i].z = cloud->
getPoint(i)->
z;
135 pcl::PointXYZRGB bbMin0, bbMax0;
136 pcl::getMinMax3D(*pcl_cloud, bbMin0, bbMax0);
138 pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformed_cloud(
139 new pcl::PointCloud<pcl::PointXYZRGB>);
140 transformed_cloud->width = cloud->
size();
141 transformed_cloud->height = 1;
142 transformed_cloud->points.resize(transformed_cloud->width *
143 transformed_cloud->height);
146 double area0 = (bbMax0.x - bbMin0.x) * (bbMax0.z - bbMin0.z);
147 for (
int th = -45; th < 46;
149 double thD = (double)th *
M_PI / 180.0;
151 Eigen::Affine3f transform_2 = Eigen::Affine3f::Identity();
154 transform_2.translation() << 0, 0.0, 0.0;
157 transform_2.rotate(Eigen::AngleAxisf(thD, Eigen::Vector3f::UnitY()));
159 pcl::transformPointCloud(*pcl_cloud, *transformed_cloud, transform_2);
161 pcl::PointXYZRGB bbMin, bbMax;
162 pcl::getMinMax3D(*transformed_cloud, bbMin, bbMax);
163 double area = (bbMax.x - bbMin.x) * (bbMax.z - bbMin.z);
169 Eigen::Affine3f transform_inv = transform_2.inverse();
171 pcl::transformPointCloud(*transformed_cloud, *pcl_cloud, transform_inv);
178 pcl::PointCloud<pcl::PointXYZRGB>::Ptr pcl_cloud(
179 new pcl::PointCloud<pcl::PointXYZRGB>);
180 pcl_cloud->width = cloud->
size();
181 pcl_cloud->height = 1;
182 pcl_cloud->points.resize(pcl_cloud->width * pcl_cloud->height);
184 std::vector<int> v(cloud->
size());
185 std::iota(v.begin(), v.end(), 0);
186 std::random_device rd;
187 std::mt19937 gen(rd());
188 std::shuffle(v.begin(), v.end(), rd);
189 v.erase(v.begin(), v.begin() + (
int)
floor(cloud->
size()));
191 for (
size_t i = 0; i < cloud->
size(); i++) {
192 pcl_cloud->points[i].x = cloud->
getPoint(i)->
x;
193 pcl_cloud->points[i].y = cloud->
getPoint(i)->
y;
194 pcl_cloud->points[i].z = cloud->
getPoint(i)->
z;
202 Eigen::Vector4d centroid;
203 pcl::compute3DCentroid(*pcl_cloud, centroid);
205 Eigen::Affine3f t0 = Eigen::Affine3f::Identity();
207 t0.translation() << -centroid[0], -centroid[1], -centroid[2];
209 pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformed0(
210 new pcl::PointCloud<pcl::PointXYZRGB>);
211 transformed0->width = pcl_cloud->size();
212 transformed0->height = 1;
213 transformed0->points.resize(transformed0->width * transformed0->height);
215 pcl::transformPointCloud(*pcl_cloud, *transformed0, t0);
218 Eigen::Affine3f transform0 = Eigen::Affine3f::Identity();
219 transform0.translation() << 0.0, 0.0, 0.0;
220 transform0.rotate(Eigen::AngleAxisf(th0, Eigen::Vector3f::UnitY()));
221 pcl::transformPointCloud(*transformed0, *transformed0, transform0);
224 Eigen::Affine3f t1 = Eigen::Affine3f::Identity();
225 t1.translation() << centroid[0], centroid[1], centroid[2];
226 pcl::transformPointCloud(*transformed0, *transformed0, t1);
230 for (
int i = 0; i < transformed0->size(); i++) {
233 CCVector3 p(transformed0->points[i].x, transformed0->points[i].y,
234 transformed0->points[i].z);
237 uchar rojo = transformed0->points[i].r;
238 uchar verde = transformed0->points[i].g;
239 uchar azul = transformed0->points[i].b;
244 cloud = cloudAligned;
249 std::vector<cv::Point>& idxPxS,
250 std::vector<int>& idxPx1DS,
254 for (
int y = 0; y < corrMatS.rows; y++) {
255 for (
int x = 0; x < corrMatS.cols; x++) {
256 corrMatS.at<
int>(y, x) = cntC;
262 int s = cloud->
size();
264 for (
int i = 0; i < s; i++) {
267 int z =
floor(pointC0->
z);
268 int x =
floor(pointC0->
x);
269 imageBWS.at<
uchar>(z, x) = 255;
273 idxPxS.push_back(Point(z, x));
274 idxPx1DS.push_back(corrMatS.at<
int>(z, x));
282 toSkel = 255 * cv::Mat::ones(I.rows, I.cols, CV_8U) - I;
287 cv::Mat skel(toSkel.size(), CV_8U, cv::Scalar(0));
292 cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3));
297 cv::erode(toSkel, eroded, element);
298 cv::dilate(eroded, temp, element);
299 cv::subtract(toSkel, temp, temp);
300 cv::bitwise_or(skel, temp, skel);
301 eroded.copyTo(toSkel);
303 done = (cv::countNonZero(toSkel) == 0);
305 }
while (!done && (iterations < 100));
313 std::vector<cv::Point> subset;
315 for (
int i = 0; i < idx.size(); i++) {
316 Point x(v.at(idx.at(i)).x, v.at(idx.at(i)).y);
324 std::vector<cv::Point> pixList,
326 for (
int i = 0; i < pixList.size(); i++) {
327 populated.at<
uchar>((pixList.at(i).x), (pixList.at(i).y)) = value;
333 std::vector<cv::Point>
setdiffPixs(std::vector<cv::Point> listNew,
334 std::vector<cv::Point> listOld) {
335 std::vector<cv::Point> setdiffList;
337 for (
int i = 0; i < listOld.size(); i++) {
339 for (
int j = 0; j < listNew.size(); j++) {
340 if (listOld.at(i).x == listNew.at(j).x &&
341 listOld.at(i).y == listNew.at(j).y) {
346 Point x(listOld.at(i).x, listOld.at(i).y);
347 setdiffList.push_back(x);
356 std::vector<cv::Point> listOld) {
357 std::vector<int> commonList;
360 for (
int i = 0; i < listNew.size(); i++) {
361 for (
int j = 0; j < listOld.size(); j++) {
362 if (listNew.at(i).x == listOld.at(j).x &&
363 listNew.at(i).y == listOld.at(j).y) {
364 commonList.push_back(i);
373 std::vector<int> listOld) {
374 std::vector<int> commonList;
378 for (
auto& e : listNew) {
379 for (
auto& ee : listOld) {
381 commonList.push_back(cnt);
392 std::vector<cv::Point>
setxorPixs(std::vector<cv::Point> listNew,
393 std::vector<cv::Point> listOld) {
394 vector<Point> setxorList;
395 vector<int> commonList;
398 for (
int i = 0; i < listNew.size(); i++) {
399 for (
int j = 0; j < listOld.size(); j++) {
400 if (listNew.at(i).x == listOld.at(j).x &&
401 listNew.at(i).y == listOld.at(j).y) {
402 Point x(listNew.at(i).x, listNew.at(i).y);
404 commonList.push_back(i);
410 int nLabels = listNew.size();
411 vector<int> v(nLabels);
412 iota(std::begin(v), std::end(v), 0);
413 vector<int> setxorIdx;
414 std::set_difference(std::begin(v), std::end(v), std::begin(commonList),
415 std::end(commonList), std::back_inserter(setxorIdx));
417 for (
int j = 0; j < setxorIdx.size(); j++) {
418 Point x(listNew.at(setxorIdx.at(j)).x, listNew.at(setxorIdx.at(j)).y);
419 setxorList.push_back(x);
427 std::vector<cv::Point>& pixelList) {
428 std::vector<int> pixelV;
429 for (
int i = 0; i < pixelList.size(); i++) {
430 int val = inputM.at<
uchar>(pixelList.at(i).x, pixelList.at(i).y);
431 pixelV.push_back(val);
437 std::vector<std::vector<cv::Point>>
pixelListMat(cv::Mat inputM,
int nLabels) {
438 std::vector<std::vector<cv::Point>> pixelSegments(nLabels);
439 for (
int i = 0; i < inputM.rows; i++) {
440 for (
int j = 0; j < inputM.cols; j++) {
441 int pixelValue = inputM.at<
int>(i, j);
442 if (pixelValue > 0) {
444 pixelSegments[pixelValue - 1].push_back(
449 return pixelSegments;
454 std::vector<int>
findMatlab(std::vector<double> inputV,
int op,
double thres) {
455 std::vector<int> indices;
458 for (
int i = 0; i < inputV.size(); i++) {
459 if (inputV.at(i) < thres) indices.push_back(i);
463 for (
int i = 0; i < inputV.size(); i++) {
464 if (inputV.at(i) <= thres) indices.push_back(i);
468 for (
int i = 0; i < inputV.size(); i++) {
469 if (inputV.at(i) > thres) indices.push_back(i);
473 for (
int i = 0; i < inputV.size(); i++) {
474 if (inputV.at(i) >= thres) indices.push_back(i);
478 for (
int i = 0; i < inputV.size(); i++) {
479 if (inputV.at(i) == thres) indices.push_back(i);
485 std::vector<int>
findIdx(std::vector<int> inputV,
int thres) {
486 std::vector<int> indices;
488 for (
int i = 0; i < inputV.size(); i++) {
489 if (inputV.at(i) == thres) indices.push_back(i);
499 cv::Mat& dilation_dst) {
500 int dilation_type = 0;
501 if (dilation_elem == 0) {
502 dilation_type = MORPH_RECT;
503 }
else if (dilation_elem == 1) {
504 dilation_type = MORPH_CROSS;
505 }
else if (dilation_elem == 2) {
506 dilation_type = MORPH_ELLIPSE;
508 cv::Mat element = cv::getStructuringElement(
509 dilation_type, Size(2 * dilation_size + 1, 2 * dilation_size + 1),
510 cv::Point(dilation_size, dilation_size));
511 cv::dilate(src, dilation_dst, element);
518 cv::Mat& erosion_dst) {
519 int erosion_type = 0;
520 if (erosion_elem == 0) {
521 erosion_type = MORPH_RECT;
522 }
else if (erosion_elem == 1) {
523 erosion_type = MORPH_CROSS;
524 }
else if (erosion_elem == 2) {
525 erosion_type = MORPH_ELLIPSE;
527 cv::Mat element = cv::getStructuringElement(
528 erosion_type, Size(2 * erosion_size + 1, 2 * erosion_size + 1),
529 cv::Point(erosion_size, erosion_size));
530 cv::erode(src, erosion_dst, element);
536 std::vector<int> bigStones) {
538 int nLabels = pixsLabel.size();
539 std::vector<int> v(nLabels);
540 std::iota(std::begin(v), std::end(v), 0);
542 std::vector<int> noBigStones;
543 std::set_difference(std::begin(v), std::end(v), std::begin(bigStones),
544 std::end(bigStones), std::back_inserter(noBigStones));
547 cv::Mat smallStones = cv::Mat::zeros(labels.size(), CV_8U);
548 for (
int i = 0; i < noBigStones.size(); i++) {
549 for (
int j = 0; j < pixsLabel[noBigStones.at(i)].
size(); j++) {
550 smallStones.at<
uchar>(pixsLabel[noBigStones.at(i)].at(j).x,
551 pixsLabel[noBigStones.at(i)].at(j).y) = 255;
556 cv::Mat input = cv::Mat::zeros(labels.size(), CV_8U);
557 for (
int i = 0; i < bigStones.size(); i++) {
558 for (
int j = 0; j < pixsLabel[bigStones.at(i)].
size(); j++) {
559 input.at<
uchar>(pixsLabel[bigStones.at(i)].at(j).x,
560 pixsLabel[bigStones.at(i)].at(j).y) = 255;
566 int erosion_elem = 2;
567 int erosion_size = 1;
569 erosionCC(erosion_elem, erosion_size, input, output);
572 cv::Mat combined = output + smallStones;
580 std::vector<std::vector<cv::Point>> contours;
581 std::vector<cv::Vec4i> hierarchy;
582 cv::Mat srcBuffer, output;
583 src.copyTo(srcBuffer);
584 cv::findContours(srcBuffer, contours, hierarchy, cv::RETR_CCOMP,
585 cv::CHAIN_APPROX_TC89_KCOS);
587 std::vector<std::vector<cv::Point>> allSegments;
590 for (
size_t i = 0; i < contours.size(); ++i) {
591 cv::drawContours(srcBuffer, contours, i, cv::Scalar(200, 0, 0), 1, 8,
592 hierarchy, 0, Point());
593 cv::Rect brect = cv::boundingRect(contours[i]);
594 cv::rectangle(srcBuffer, brect, cv::Scalar(255, 0, 0));
597 std::vector<cv::Point> segment;
598 for (
unsigned int row = brect.y; row < brect.y + brect.height; ++row) {
599 for (
unsigned int col = brect.x; col < brect.x + brect.width;
601 result = cv::pointPolygonTest(contours[i], Point(col, row),
604 segment.push_back(Point(col, row));
608 allSegments.push_back(segment);
611 output = cv::Mat::zeros(src.size(), CV_8U);
612 int totalSize = output.rows * output.cols;
613 for (
int segmentCount = 0; segmentCount < allSegments.size();
615 std::vector<cv::Point> segment = allSegments[segmentCount];
616 if (segment.size() > threshSize) {
617 for (
int idx = 0; idx < segment.size(); ++idx) {
618 output.at<
uchar>(segment[idx].y, segment[idx].x) = 255;
668 std::vector<std::vector<cv::Point>>& pixsLabel,
671 std::vector<std::vector<Point>>& contours0) {
673 const int connectivity_8 = 8;
676 int nLabels = connectedComponentsWithStats(
677 input, labels, stats, centroids, connectivity_8,
682 std::vector<std::vector<cv::Point>> contours;
683 std::vector<cv::Vec4i> hierarchy;
684 cv::findContours(input, contours0, hierarchy, RETR_TREE,
685 CHAIN_APPROX_SIMPLE);
687 string ty =
type2str(labels.type());
693 cv::Mat edgesNeg = edgesIn.clone();
694 string hola =
type2str(edgesNeg.type());
697 cv::Mat labels, stats;
698 const int connectivity_8 = 8;
703 cv::bitwise_not(edgesIn, edgesIn);
705 int nLabels = cv::connectedComponentsWithStats(
706 edgesIn, labels, stats, centroids, connectivity_8,
710 cv::bitwise_not(edgesIn, edgesIn);
712 int stSize = (int)stats.at<
int>(
715 int cntBiggestSize = 1;
716 for (
int i = 2; i < stats.rows; i++) {
717 int loopSize = (int)stats.at<
int>(i, 4);
719 if (loopSize > stSize) {
727 for (
int i = 0; i < edgesNeg.rows; i++) {
728 for (
int j = 0; j < edgesNeg.cols; j++) {
729 int h = (int)edgesNeg.at<
uchar>(i, j);
730 int l = (int)labels.at<
int>(i, j);
731 if (h == 0 && l == cntBiggestSize) {
742 cv::floodFill(edgesNeg, cv::Point(c, f),
743 CV_RGB(255, 255, 255));
745 cv::bitwise_not(edgesNeg, edgesNeg);
747 filledEdgesOut = (edgesNeg | edgesIn);
753 void fft2(
const cv::Mat in, cv::Mat& complexI) {
755 int m = getOptimalDFTSize(in.rows);
756 int n = getOptimalDFTSize(in.cols);
757 copyMakeBorder(in, padded, 0, m - in.rows, 0, n - in.cols, BORDER_CONSTANT,
760 cv::Mat planes[] = {cv::Mat_<float>(padded),
761 cv::Mat::zeros(padded.size(), CV_32F)};
762 cv::merge(planes, 2, complexI);
763 cv::dft(complexI, complexI);
767 cv::Mat
conjugate(cv::Mat_<std::complex<double>> M1,
bool* flag) {
768 using CP = std::complex<double>;
769 cv::Mat_<CP> M3(M1.rows, M1.cols);
773 double a = M1.at<
CP>(M1.rows - 1, M1.cols - 1).real();
774 for (
int i = 0; i < M1.rows; ++i) {
775 for (
int j = 0; j < M1.cols; ++j) {
777 CP(M1.at<
CP>(i, j).real(), -M1.at<
CP>(i, j).imag());
784 catch (
const std::exception& e) {
793 cv::Mat_<std::complex<double>> M2) {
794 using CP = std::complex<double>;
795 cv::Mat_<CP> M3(M1.rows, M1.cols);
796 for (
int i = 0; i < M3.rows; ++i) {
797 for (
int j = 0; j < M3.cols; ++j) {
799 CP(M1.at<
CP>(i, j).real() * M2.at<
CP>(i, j).real() -
800 M1.at<
CP>(i, j).imag() * M2.at<
CP>(i, j).imag(),
801 M1.at<
CP>(i, j).real() * M2.at<
CP>(i, j).imag() +
802 M1.at<
CP>(i, j).imag() * M2.at<
CP>(i, j).real());
809 void cwt2d(
double sca, cv::Mat
image, cv::Mat& cwtcfs, cv::Mat& bincfs) {
810 cv::Mat I = imread(
"depthMap.bmp", cv::IMREAD_GRAYSCALE);
811 cv::Mat fImage =
image;
814 std::cout <<
"Direct transform...\n";
815 cv::Mat fourierTransform;
816 fft2(fImage, fourierTransform);
819 Size S = fourierTransform.size();
823 int W2 =
floor((W - 1) / 2);
824 int H2 =
floor((H - 1) / 2);
826 std::vector<int> w1(W2 + 1);
827 std::iota(std::begin(w1), std::end(w1), 0);
828 std::vector<int> w2(W2 + 1);
829 std::iota(std::begin(w2), std::end(w2), (W2 - W + 1));
831 std::vector<double> v;
832 v.reserve(w1.size() + w2.size());
833 v.insert(v.end(), w1.begin(), w1.end());
834 v.insert(v.end(), w2.begin(), w2.end());
836 std::vector<double> W_puls(v.size());
837 std::transform(v.begin(), v.end(), W_puls.begin(),
838 [W](
int i) { return i * 2 * M_PI / W; });
840 std::vector<int> h1(H2 + 1);
841 std::iota(std::begin(h1), std::end(h1), 0);
842 std::vector<int> h2(H2 + 1);
843 std::iota(std::begin(h2), std::end(h2), (H2 - H + 1));
845 std::vector<double> v2;
846 v2.reserve(h1.size() + h2.size());
847 v2.insert(v2.end(), h1.begin(), h1.end());
848 v2.insert(v2.end(), h2.begin(), h2.end());
850 std::vector<double> H_puls(v2.size());
851 std::transform(v2.begin(), v2.end(), H_puls.begin(),
852 [H](
int i) { return i * 2 * M_PI / H; });
854 cv::Mat matW = cv::Mat(W_puls);
855 cv::Mat matH = cv::Mat(H_puls);
858 cv::repeat(matW.reshape(1, 1), matH.total(), 1,
860 cv::repeat(matH.reshape(1, 1).t(), 1, matW.total(), yy);
862 double dxxyy =
abs(xx.at<
double>(0, 1) - xx.at<
double>(0, 0)) *
863 (yy.at<
double>(1, 0) - yy.at<
double>(0, 0));
869 cv::Mat nxx = sca * (cos(ang) * xx - sin(ang) * yy);
870 cv::Mat nyy = sca * (sin(ang) * xx + cos(ang) * yy);
881 cv::Mat sum = nxx2 + nyy2;
883 pow(sum, order / 2, sumPow);
885 cv::Mat prod1 = sigmax * nxx;
887 cv::pow(prod1, 2, prod12);
888 cv::Mat prod2 = sigmay * nyy;
890 cv::pow(prod2, 2, prod22);
892 cv::Mat ex = -(prod12 + prod22) / 2;
896 cv::Mat waveft2 = -(2 *
M_PI) * sumPow.mul(ex2);
899 using CP = std::complex<double>;
900 cv::Mat_<CP> mask(Size(waveft2.rows, waveft2.cols));
901 mask = sca * waveft2;
904 cv::Mat mask_conj = mask;
906 mask.convertTo(mask_conj, CV_32F);
909 std::vector<cv::Mat> channels;
913 g = cv::Mat::zeros(Size(mask_conj.cols, mask_conj.rows), CV_32FC1);
914 mask2 = cv::Mat::zeros(Size(mask_conj.cols, mask_conj.rows), CV_32FC2);
916 channels.push_back(mask_conj);
917 channels.push_back(g);
919 cv::merge(channels, mask2);
927 std::cout <<
"Inverse transform...\n";
928 cv::dft(M3, cwtcfs, cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT);
931 cwtcfs.convertTo(bincfs, CV_8U);
937 std::vector<cloudViewer::PointProjectionTools::IndexedCCVector2>
point;
938 std::list<cloudViewer::PointProjectionTools::IndexedCCVector2*> hullPoint2;
940 for (
unsigned i = 0; i < stone->
size(); ++i) {
951 vector<unsigned> Vec;
952 for (
int i = 0; i < (hullPoint2.size()); ++i) {
953 list<cloudViewer::PointProjectionTools::IndexedCCVector2*>::iterator
954 it = hullPoint2.begin();
975 int cnt = Vec.size();
994 std::vector<cloudViewer::PointProjectionTools::IndexedCCVector2>
point;
995 std::list<cloudViewer::PointProjectionTools::IndexedCCVector2*> hullPoint2;
997 for (
unsigned i = 0; i < V.size(); ++i)
1010 vector<unsigned> Vec;
1011 for (
int i = 0; i < (hullPoint2.size()); ++i) {
1012 list<cloudViewer::PointProjectionTools::IndexedCCVector2*>::iterator
1013 it = hullPoint2.begin();
1014 std::advance(it, i);
1022 for (
auto e : Vec) {
1033 int cnt = Vec.size();
1060 f_cloudMortar->
scale(100, 1000, 100);
1062 int rowsM =
ceil(maxBox.
z);
1063 int colsM =
ceil(maxBox.
x);
1065 cv::Mat corrMatM = Mat::zeros(rowsM, colsM, CV_32F);
1066 vector<Point> idxPxM;
1067 vector<int> idxPxM1D;
1068 cv::Mat imageBWS = Mat::zeros(rowsM, colsM, CV_8U);
1070 cloud2binary(f_cloudMortar, corrMatM, idxPxM, idxPxM1D, imageBWS);
1073 Mat skel =
skeleton(imageBWS,
false);
1075 f_cloudMortar->
scale(0.01, 0.001, 0.01);
1078 vector<int> pixelsSkel;
1079 for (
int i = 0; i < skel.rows; i++) {
1080 for (
int j = 0; j < skel.cols; j++) {
1081 unsigned char a = skel.at<
char>(i, j);
1083 int idx = corrMatM.at<
int>(i, j);
1084 pixelsSkel.push_back(idx);
1089 vector<int> idxCloudMortarSkel =
1092 for (
auto e : idxCloudMortarSkel) {
1107 skelM, 0.01, modParams, 0, 0);
1117 pcl::PointCloud<pcl::PointXYZ>::Ptr pcl_cloudStones(
1118 new pcl::PointCloud<pcl::PointXYZ>);
1119 pcl_cloudStones->width = f_cloudStones->
size();
1120 pcl_cloudStones->height = 1;
1121 pcl_cloudStones->points.resize(pcl_cloudStones->width *
1122 pcl_cloudStones->height);
1124 for (
size_t i = 0; i < f_cloudStones->
size(); ++i) {
1125 pcl_cloudStones->points[i].x = f_cloudStones->
getPoint(i)->
x;
1126 pcl_cloudStones->points[i].y = f_cloudStones->
getPoint(i)->
y;
1127 pcl_cloudStones->points[i].z = f_cloudStones->
getPoint(i)->
z;
1130 pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
1132 kdtree.setInputCloud(pcl_cloudStones);
1135 vector<double> distStD, dist3St, distStD2;
1136 vector<double> distStWidth;
1137 vector<double> distStW;
1138 for (
int i = 0; i < f_skelMortar->
size(); i++) {
1139 pcl::PointXYZ searchPoint;
1141 searchPoint.x = f_skelMortar->
getPoint(i)->
x;
1142 searchPoint.y = f_skelMortar->
getPoint(i)->
y;
1143 searchPoint.z = f_skelMortar->
getPoint(i)->
z;
1145 std::vector<int> pointIdxRadiusSearch;
1146 std::vector<float> pointRadiusSquaredDistance;
1149 pcl::PointXYZ nnPoint;
1151 if (kdtree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch,
1152 pointRadiusSquaredDistance) > 0) {
1153 nnPoint.x = pcl_cloudStones->points[pointIdxRadiusSearch[0]].x;
1154 nnPoint.y = pcl_cloudStones->points[pointIdxRadiusSearch[0]].y;
1155 nnPoint.z = pcl_cloudStones->points[pointIdxRadiusSearch[0]].z;
1157 double disty =
abs(searchPoint.y - nnPoint.y);
1158 double distx =
abs(searchPoint.x - nnPoint.x);
1159 double distz =
abs(searchPoint.z - nnPoint.z);
1160 double dist3 = sqrt(distx * distx +
1165 distStD.push_back(disty * 1000);
1166 dist3St.push_back(dist3);
1168 double dist1 = 1000;
1169 double dist2 = 1000;
1170 double dist1y = 1000;
1171 double dist2y = 1000;
1174 for (
size_t j = 0; j < pointIdxRadiusSearch.size(); ++j) {
1177 pcl_cloudStones->points[pointIdxRadiusSearch[j]]
1181 pcl_cloudStones->points[pointIdxRadiusSearch[j]].z);
1184 pcl_cloudStones->points[pointIdxRadiusSearch[j]].y);
1186 sqrt(
abs(distx) *
abs(distx) +
abs(distz) *
abs(distz));
1189 pointIdxRadiusSearch[j]);
1196 if (idxSt == idx1) {
1197 if (dist3 < dist1) dist1 = dist3;
1200 if (idxSt != idx1 & idx2 == -1) {
1205 if (idxSt == idx2) {
1206 if (dist3 < dist2) dist2 = dist3;
1214 if (idx1 > -1 & idx2 == -1 &
1216 distStW.push_back(dist1 * 1000);
1217 distStD2.push_back(dist1y * 1000);
1218 }
else if (idx1 > -1 & idx2 > -1) {
1219 distStW.push_back((dist1 + dist2) * 1000);
1220 distStD2.push_back((dist1y + dist2y) / 2 * 1000);
1228 distStD2.push_back(100);
1229 dist3St.push_back(200);
1231 distStW.push_back(200);
1239 "Mortar relative depth (mm)");
1241 sfIdxD = f_skelMortar->
addScalarField(
"Mortar relative depth (mm)");
1249 for (
unsigned int i = 0; i < distStD2.size(); i++) {
1250 double index =
static_cast<double>(distStD2.at(i));
1262 "Mortar relative width (mm)");
1264 sfIdxW = f_skelMortar->
addScalarField(
"Mortar relative width (mm)");
1272 for (
unsigned int i = 0; i < distStW.size(); i++) {
1273 double index =
static_cast<double>(distStW.at(i));
1281 f_skelMortar->
showSF(
true);
1282 f_skelMortar->
setName(
"Mortar Maps");
1284 return f_skelMortar;
1289 for (
auto e : idx) {
1302 float area = (maxBox.
x - minBox.
x) * (maxBox.
z - minBox.
z);
1303 float density = idx.size() / area;
1316 QList<QAction*> ccAutoSeg::getActions() {
1318 m_action =
new QAction(getName(),
this);
1319 m_action->setToolTip(getDescription());
1320 m_action->setIcon(QIcon(
1321 QString::fromUtf8(
":/CC/plugin/qAutoSeg/cyberbuildIcon.png")));
1324 connect(m_action, &QAction::triggered,
this, &ccAutoSeg::doAction);
1327 return QList<QAction*>{
1332 void ccAutoSeg::doAction() {
1333 if (m_app ==
nullptr) {
1344 struct tm* timeinfo;
1348 timeinfo = localtime(&rawtime);
1350 strftime(buffer,
sizeof(buffer),
"%Y%m%d_%H%M%S", timeinfo);
1351 std::string str(buffer);
1357 time_t my_time = time(
NULL);
1362 if (!piDlg.exec())
return;
1364 double joints = piDlg.jointsSpinBox->value();
1365 double segH = piDlg.segmentHSpinBox->value();
1366 double segV = piDlg.segmentVSpinBox->value();
1368 bool checkAlignment = piDlg.alignmentCheckBox->isChecked();
1369 bool checkSegment = piDlg.segmentCheckBox->isChecked();
1370 bool checkMortar = piDlg.mortarCheckBox->isChecked();
1374 if (checkMortar ==
true && checkSegment ==
false) {
1375 m_app->dispToConsole(
1376 "Segmentation is required for the creation of mortar maps. "
1377 "Please, check both \"Automatic segmentation\" and \"Mortar "
1386 if (!m_app->haveOneSelection() ||
1388 m_app->dispToConsole(
"Select one cloud!",
1393 QFileInfo fileInfo(selectedEntities.front()->getFullPath());
1394 QDir dir(fileInfo.absolutePath());
1395 QString autoSegLogFile = dir.absoluteFilePath(
filename.c_str());
1397 ofstream auto_seg_log;
1402 auto_seg_log << stamp <<
" Importing point cloud" <<
endl;
1405 QString qName = cloud0->
getName();
1406 string cloudName = qName.toLocal8Bit().constData();
1409 string name2 = qFileName.toLocal8Bit().constData();
1412 auto_seg_log << stamp <<
" File \"" << name2 <<
"\" loaded" <<
endl;
1413 auto_seg_log << stamp <<
" Cloud \"" << cloudName <<
"\" imported" <<
endl;
1417 auto_seg_log << stamp <<
" Estimated mortar joints width: " << joints
1419 auto_seg_log << stamp <<
" Segmentation window. X: " << segH
1420 <<
"m and Y: " << segV <<
"m" <<
endl;
1422 auto_seg_log << stamp <<
" Alignment: " << checkAlignment <<
endl;
1423 auto_seg_log << stamp <<
" Segmentation: " << checkSegment <<
endl;
1424 auto_seg_log << stamp <<
" Mortar maps: " << checkMortar <<
endl;
1425 auto_seg_log <<
" Starting process..." <<
endl;
1428 cv::Mat_<double> cldm(cloud0->
size(), 3);
1429 for (
unsigned int i = 0; i < cloud0->
size(); i++) {
1430 cldm.row(i)(0) = cloud0->
getPoint(i)->
x;
1431 cldm.row(i)(1) = cloud0->
getPoint(i)->
y;
1432 cldm.row(i)(2) = cloud0->
getPoint(i)->
z;
1435 cv::Mat_<double> mean;
1438 cv::Vec3d nrm = pca.eigenvectors.row(2);
1439 nrm = nrm / norm(nrm);
1454 std::vector<int> v2(cloud0->
size());
1455 std::iota(v2.begin(), v2.end(), 0);
1457 std::random_device rd;
1458 std::mt19937 gen(rd());
1459 std::shuffle(v2.begin(), v2.end(), rd);
1463 if (v2.size() > 1000000)
1468 for (
int i = 0; i < nbSub; i++) {
1469 v.push_back(v2.at(i));
1472 for (
int i = 0; i < v.size(); i++) {
1485 double th0 =
optRotY(cloud2Rot);
1509 if (checkAlignment ==
true & checkSegment ==
false & checkMortar ==
false) {
1516 auto_seg_log << stamp <<
"Cloud aligned to XZ." <<
endl;
1529 double axX = maxBox.
x - minBox.
x;
1530 double axY = maxBox.
z - minBox.
z;
1537 unsigned int nwinX =
ceil(axX / winX);
1538 unsigned int nwinY =
ceil(axY / winY);
1541 double rwinX = axX / nwinX;
1542 double rwinY = axY / nwinY;
1545 vector<vector<double>> boundaries;
1548 vector<int> global_idx;
1550 for (
unsigned int i = 0; i < nwinX; i++) {
1552 for (
unsigned int j = 0; j < nwinY; j++) {
1553 boundaries.push_back({
X,
X + rwinX + 0.3, Y, Y + rwinY + 0.3});
1562 vector<vector<int>> idxClouds(boundaries.size());
1563 vector<vector<int>> idxCloudsC;
1566 auto_seg_log << stamp <<
" Splitting cloud in patches (" << nwinX * nwinY
1569 for (
unsigned int i = 0; i < cloud0->
size(); i++) {
1570 for (
unsigned int j = 0; j < boundaries.size(); j++) {
1573 if (p.x >= boundaries[j][0] && p.x <= boundaries[j][1] &&
1574 p.z >= boundaries[j][2] &&
1575 p.z <= boundaries[j][3])
1577 idxClouds[j].push_back(i);
1580 global_idx.push_back(i);
1584 for (
auto e : idxClouds)
1585 if (e.size() != 0) idxCloudsC.push_back(e);
1587 idxClouds = idxCloudsC;
1590 auto_seg_log << stamp <<
" Splitting done" <<
endl;
1592 vector<ccPointCloud*> sub_clouds;
1594 auto_seg_log << stamp <<
" Creating subclouds" <<
endl;
1597 for (
unsigned int i = 0; i < idxClouds.size(); i++) {
1599 QString str = QString::fromUtf8(
name.c_str());
1601 if (idxClouds[i].
size() > 0) {
1602 for (
auto e : idxClouds[i]) {
1615 sub_clouds.push_back(win_cloud);
1620 vector<vector<pair<int, int>>> stones;
1623 for (
unsigned int z = 0; z < sub_clouds.size(); ++z) {
1627 auto_seg_log << stamp <<
" Cloud " << z <<
": " << cloud->
size()
1630 if (cloud->
size() > 0) {
1631 string cComment =
"part_" +
to_string(z) +
" has " +
1633 QString qComment = QString::fromUtf8(cComment.c_str());
1634 m_app->dispToConsole(qComment,
1656 int b = cloud->
size();
1658 cloud->
scale(100, 1000, 100);
1662 int rows =
ceil(maxBox2.
z);
1663 int cols =
ceil(maxBox2.
x);
1666 cv::Mat corrMat = cv::Mat::zeros(rows, cols, CV_32F);
1668 for (
int y = 0; y < corrMat.rows; y++) {
1669 for (
int x = 0; x < corrMat.cols; x++) {
1670 corrMat.at<
int>(y, x) = cntC;
1675 vector<Point> idxPx;
1676 vector<int> idxPx1D;
1679 cv::Mat
image = cv::Mat::zeros(rows, cols, CV_32F);
1680 Mat imageR(rows, cols, CV_8U);
1681 Mat imageG(rows, cols, CV_8U);
1682 Mat imageB(rows, cols, CV_8U);
1683 for (
int i = 0; i < b; i++) {
1686 int z =
floor(pointC->
z);
1687 int x =
floor(pointC->
x);
1688 image.at<
float>(z, x) = pointC->
y;
1691 imageR.at<
uchar>(z, x) = colorC.r;
1692 imageG.at<
uchar>(z, x) = colorC.g;
1693 imageB.at<
uchar>(z, x) = colorC.b;
1696 idxPx.push_back(Point(z, x));
1698 idxPx1D.push_back(corrMat.at<
int>(z, x));
1702 std::vector<cv::Mat> channels;
1704 channels.push_back(imageR);
1705 channels.push_back(imageG);
1706 channels.push_back(imageB);
1708 cv::merge(channels, imageC);
1711 cv::Mat imageFilt = cv::Mat::zeros(rows, cols, CV_32F);
1712 cv::medianBlur(
image, imageFilt, 3);
1714 for (
int y = 0; y <
image.rows; y++) {
1715 for (
int x = 0; x <
image.cols; x++) {
1716 if (
image.at<
float>(y, x) == 0) {
1717 image.at<
float>(y, x) = imageFilt.at<
float>(y, x);
1724 std::vector<int> nullCols, nullRows;
1726 for (
int y = 0; y <
image.rows; y++) {
1727 for (
int x = 0; x <
image.cols; x++) {
1728 if (
image.at<
float>(y, x) == 0) {
1729 nullCols.push_back(x);
1730 nullRows.push_back(y);
1736 image.convertTo(imagePlot, CV_8U);
1738 cloud->
scale(0.01, 0.001, 0.01);
1742 auto_seg_log << stamp <<
" Depth and colour maps created" <<
endl;
1745 double scaleCWT = joints * 0.254;
1747 cv::Mat bincfs = cv::Mat::zeros(cwtcfs.size(), CV_8UC1);
1753 cv::Rect myROI(0, 0,
image.cols,
image.rows);
1754 bincfs = bincfs(myROI);
1759 auto_seg_log << stamp <<
" CWT calculated" <<
endl;
1762 for (
int i = 0; i < nullRows.size(); i++) {
1763 bincfs.at<
uchar>(nullRows.at(i), nullCols.at(i)) = 0;
1773 int erosion_elem = 2;
1775 int erosion_size = 1;
1777 erosionCC(erosion_elem, erosion_size, output, erodedM);
1782 int dilation_size = 1;
1784 dilationCC(dilation_elem, dilation_size, erodedM, dilatedM);
1787 auto_seg_log << stamp <<
" CWT post-processing done" <<
endl;
1790 vector<vector<Point>> pixsLabel, contours;
1793 extractInfo(dilatedM, pixsLabel, labels, stats, contours);
1797 vector<double> area(
1800 for (
int i = 1; i < stats.rows; i++) {
1801 area.at(i - 1) = stats.at<
int>(i, CC_STAT_AREA);
1804 double meanArea = std::accumulate(area.begin(), area.end(), 0) /
1808 std::vector<double> diff(area.size());
1809 std::transform(area.begin(), area.end(), diff.begin(),
1810 [meanArea](
double x) { return x - meanArea; });
1811 double sq_sum = std::inner_product(diff.begin(), diff.end(),
1813 double stdevArea = std::sqrt(sq_sum / area.size());
1816 double thres = meanArea + stdevArea;
1817 std::vector<int> bigStones =
findMatlab(area, op, thres);
1821 cv::Mat firstSegmentation;
1822 firstSegmentation =
stonesDivision(pixsLabel, labels, bigStones);
1824 std::vector<std::vector<Point>> pixsLabel2, contours2;
1825 cv::Mat labels2, stats2;
1826 extractInfo(firstSegmentation, pixsLabel2, labels2, stats2,
1830 auto_seg_log << stamp <<
" Big stones divided" <<
endl;
1832 cv::Mat skel =
skeleton(firstSegmentation, 1);
1835 std::vector<Mat> channelsC(3);
1836 cv::split(imageC, channelsC);
1837 cv::Mat mapB = channelsC[0];
1838 cv::Mat mapG = channelsC[1];
1839 cv::Mat mapR = channelsC[2];
1842 std::vector<std::vector<Point>> hull(contours2.size());
1843 for (
int i = 0; i < contours2.size(); i++) {
1844 convexHull(cv::Mat(contours2[i]), hull[i],
false);
1846 std::vector<std::vector<Point>> hull0;
1850 std::vector<std::vector<Point>> pixsHull, contoursHull;
1851 std::vector<std::vector<Point>> pixsHullSt(contours2.size());
1852 cv::Mat labelsHull, statsHull;
1853 cv::Mat drawingAll =
1854 cv::Mat::zeros(firstSegmentation.size(), CV_8UC3);
1857 std::vector<std::vector<Point>> segmentsColor;
1858 std::vector<cv::Mat> matConvexSt;
1859 std::vector<int> pixsLabels(
1860 firstSegmentation.cols * firstSegmentation.rows,
1863 std::vector<int> pixsLabels2(
1864 firstSegmentation.cols * firstSegmentation.rows,
1867 for (
int i = 0; i < contours2.size(); i++)
1870 cv::Mat::zeros(firstSegmentation.size(), CV_8UC1);
1872 Scalar
color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255),
1873 rng.uniform(0, 255));
1874 Scalar color2 = Scalar(255, 255, 255);
1875 drawContours(drawing, hull, i, color2, -1, 8,
1876 std::vector<Vec4i>(), 0,
1879 drawContours(drawingAll, hull, i,
color, -1, 8,
1880 std::vector<Vec4i>(), 0, cv::Point());
1882 extractInfo(drawing, pixsHull, labelsHull, statsHull,
1886 pixsHullSt[i] = pixsHull[0];
1888 for (
int j = 0; j < pixsHull[0].size(); j++) {
1889 int idx = corrMat.at<
int>(pixsHull[0].at(j).x,
1890 pixsHull[0].at(j).y);
1891 if (pixsLabels.at(idx) == -1) {
1893 pixsLabels.at(idx) = i;
1897 pixsLabels2.at(idx) = i;
1901 std::vector<Point> pixelsH = pixsHull[0];
1902 std::vector<int> coeffB =
pixelValues(mapB, pixelsH);
1903 std::vector<int> coeffG =
pixelValues(mapG, pixelsH);
1904 std::vector<int> coeffR =
pixelValues(mapR, pixelsH);
1906 sort(coeffB.begin(), coeffB.end());
1907 double medB = coeffB[coeffB.size() / 2];
1908 sort(coeffG.begin(), coeffG.end());
1909 double medG = coeffG[coeffG.size() / 2];
1910 sort(coeffR.begin(), coeffR.end());
1911 double medR = coeffR[coeffR.size() / 2];
1912 std::vector<double> coeff0 = {medB, medG, medR};
1916 double growthRate = 1000;
1917 cv::Mat convexM, matNew;
1922 auto_seg_log << stamp <<
" Convex hulls defined" <<
endl;
1925 for (
int i = 0; i < contours2.size(); i++)
1927 std::vector<cv::Point> pixels = pixsHullSt[i];
1930 std::vector<int> pixels1d;
1931 for (
auto e : pixels) {
1932 int idx = corrMat.at<
int>(e.x, e.y);
1933 pixels1d.push_back(idx);
1936 std::vector<int> idxCloud;
1937 for (
int j = 0; j < idxPx.size(); j++) {
1938 if (pixsLabels.at(idxPx1D.at(j)) == i)
1939 idxCloud.push_back(j);
1940 if (pixsLabels2.at(idxPx1D.at(j)) ==
1943 idxCloud.push_back(j);
1946 std::vector<std::pair<int, int>> global_SglStoneIdx;
1951 float max_density = 40000;
1952 if (idxCloud.size() < max_size / 10) {
1953 for (
auto e : idxCloud) {
1954 if (e < idxClouds[z].
size())
1955 global_SglStoneIdx.push_back(
1959 auto_seg_log <<
"====> Error :" << z <<
" " << e
1964 stones.push_back(global_SglStoneIdx);
1969 global_SglStoneIdx.clear();
1975 auto_seg_log << stamp <<
" 3D points per segment extracted" <<
endl;
1981 auto_seg_log << stamp
1982 <<
" Point cloud processed. Releasing memory ... "
1994 imageFilt.release();
1995 imagePlot.release();
2010 firstSegmentation.release();
2022 contoursHull.clear();
2024 statsHull.release();
2025 drawingAll.release();
2026 segmentsColor.clear();
2027 matConvexSt.clear();
2039 auto_seg_log << stamp <<
" Stitching stones" <<
endl;
2044 vector<pair<int, int>> allStones;
2046 if (stones.size() > 0) allStones = stones[0];
2048 for (
unsigned int i = 1; i < stones.size(); i++) {
2049 allStones.insert(allStones.end(), stones[i].begin(), stones[i].end());
2052 auto_seg_log << stamp
2053 <<
" Total number of unstitched stones: " << stones.size()
2061 sort(allStones.begin(), allStones.end(),
2062 [](
auto& left,
auto& right) { return left.first < right.first; });
2064 auto_seg_log << stamp <<
" Start looking for whole stones " <<
endl;
2068 while (i < allStones.size()) {
2071 while (j < allStones.size() &&
2072 allStones[i].first == allStones[j].first &&
2073 allStones[i].second != allStones[j].second)
2076 unsigned int oldIdx = allStones[j].second;
2077 unsigned int newIdx = allStones[i].second;
2078 for (
unsigned int k = 0; k < allStones.size(); k++) {
2079 if (allStones[k].second == oldIdx) allStones[k].second = newIdx;
2087 my_time = time(
NULL);
2089 auto_seg_log << stamp <<
" Indices corrected " <<
endl;
2093 allStones.erase(unique(allStones.begin(), allStones.end()),
2097 auto_seg_log << stamp <<
" Repeated pairs removed " <<
endl;
2099 int b = cloud0->
size();
2100 vector<int> allStones_Idx;
2102 vector<int> stoneId;
2103 vector<int> allMortar;
2106 auto_seg_log << stamp <<
" Getting all stones idx " <<
endl;
2108 for (
auto e : allStones) allStones_Idx.push_back(e.first);
2110 sort(allStones_Idx.begin(), allStones_Idx.end());
2113 std::set_difference(global_idx.begin(), global_idx.end(),
2114 allStones_Idx.begin(), allStones_Idx.end(),
2115 std::inserter(allMortar, allMortar.end()));
2118 auto_seg_log << stamp <<
" Mortar idx identified " <<
endl;
2122 for (
auto e : allStones) stoneId.push_back(e.second);
2124 sort(stoneId.begin(), stoneId.end());
2126 stoneId.erase(unique(stoneId.begin(), stoneId.end()), stoneId.end());
2128 vector<vector<int>> vecStones(stoneId.size());
2130 sort(allStones.begin(), allStones.end(),
2131 [](
auto& left,
auto& right) { return left.second < right.second; });
2133 int old_idx = allStones[0].second;
2136 for (
unsigned i = 0; i < allStones.size(); i++) {
2137 if (allStones[i].second == old_idx) {
2138 allStones[i].second = new_idx;
2139 vecStones[new_idx].push_back(allStones[i].first);
2143 old_idx = allStones[i].second;
2144 allStones[i].second = new_idx;
2145 vecStones[new_idx].push_back(allStones[i].first);
2150 allStones_Idx.clear();
2152 for (
auto e : allStones) {
2153 allStones_Idx.push_back(e.first);
2154 stoneId.push_back(e.second);
2158 vector<int> stIdShuffle = stoneId;
2160 sort(stIdShuffle.begin(), stIdShuffle.end());
2162 stIdShuffle.erase(unique(stIdShuffle.begin(), stIdShuffle.end()),
2165 auto rng = std::default_random_engine{};
2166 std::shuffle(stIdShuffle.begin(), stIdShuffle.end(), rng);
2170 auto_seg_log << stamp <<
" Writing final clouds " <<
endl;
2176 if (allStones_Idx.size() > 0) {
2177 for (
auto e : allStones_Idx) {
2190 auto_seg_log << stamp <<
" Stone cloud OK. " << allStones_Idx.size()
2191 <<
" pts. " << vecStones.size() <<
" stones." <<
endl;
2207 if (allStones_Idx.size() > 0) {
2208 for (
unsigned int i = 0; i < stoneId.size(); i++) {
2209 int index =
static_cast<int>(stIdShuffle[stoneId[i]]);
2219 auto_seg_log << stamp <<
" Stone cloud SF OK " <<
endl;
2222 if (allMortar.size() > 0) {
2223 for (
auto e : allMortar) {
2236 auto_seg_log << stamp <<
" Mortar OK. " << allMortar.size() <<
" pts"
2241 if (checkMortar ==
true) {
2243 auto_seg_log <<
" Starting mortar maps generation... " <<
endl;
2245 if (allMortar.size() > 0)
2249 auto_seg_log << stamp <<
" Mortar maps OK " <<
endl;
2251 mortarMaps->
showSF(
true);
2259 if (allMortar.size() > 0) {
2265 if (allStones.size() > 0) {
2271 if (checkMortar ==
true) {
2279 auto_seg_log << stamp <<
" Start of contour generation " <<
endl;
2281 vector<ccPolyline*> contours;
2288 vector<double> stonesSize;
2289 if (vecStones.size() > 0) {
2290 for (
auto ve : vecStones) {
2291 string s_name =
"stone " +
to_string(cntSt);
2292 QString qs_name = QString::fromUtf8(s_name.c_str());
2296 if (ve.size() > 0) {
2298 contoursContainer->
addChild(contour);
2306 double sizeS = (bbMaxS.
x - bbMinS.
x) * (bbMaxS.
z - bbMinS.
z);
2307 stonesSize.push_back(sizeS);
2313 double meanSizeStones =
2314 accumulate(stonesSize.begin(), stonesSize.end(), 0.0) /
2316 double standDev =
stddev(stonesSize);
2319 auto_seg_log << stamp <<
" Average size of stones (BB) "
2320 << meanSizeStones <<
" m2 +-" << standDev <<
" ("
2321 << meanSizeStones * 10000 <<
" cm2)" <<
endl;
2323 sort(stonesSize.begin(), stonesSize.end());
2324 bool evenAmount = (stonesSize.size() % 2 == 0);
2325 int oddAmountIdx =
ceil(stonesSize.size() / 2);
2326 double evenAmountMedian =
2327 (stonesSize[oddAmountIdx - 1] + stonesSize[oddAmountIdx]) / 2;
2328 double medianSizeStones =
2329 evenAmount ? evenAmountMedian : stonesSize[oddAmountIdx];
2332 auto_seg_log << stamp <<
" Median size of stones (BB) "
2333 << medianSizeStones <<
" m2 (" << medianSizeStones * 10000
2338 auto_seg_log << stamp <<
" Contour generation done " <<
endl;
2342 if (allMortar.size() > 0) {
2346 m_app->addToDB(f_cloudStones,
true,
true,
false,
true);
2348 if (allMortar.size() > 0)
2349 m_app->addToDB(f_cloudMortar,
true,
true,
false,
true);
2352 auto_seg_log << stamp <<
" Mortar cloud OK " <<
endl;
2354 m_app->addToDB(contoursContainer,
true,
true,
false,
true);
2356 if (checkMortar ==
true && allMortar.size() > 0)
2357 m_app->addToDB(mortarMaps,
true,
true,
false,
true);
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
float PointCoordinateType
Type of the coordinates of a (N-D) point.
std::shared_ptr< core::Tensor > image
std::vector< float > Vec3d
Dialog for importing a 2D revolution profile (qSRA plugin)
virtual void setVisible(bool state)
Sets entity visibility.
virtual void showColors(bool state)
Sets colors visibility.
virtual void showSF(bool state)
Sets active scalarfield visibility.
static ccGLMatrixTpl< float > FromToRotation(const Vector3Tpl< float > &from, const Vector3Tpl< float > &to)
Creates a transformation matrix that rotates a vector to another.
ccGLMatrixTpl< T > inverse() const
Returns inverse transformation.
Float version of ccGLMatrixTpl.
void setPointSize(unsigned size=0)
Sets point size.
Hierarchical CLOUDVIEWER Object.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
ccHObject * getParent() const
Returns parent object.
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
virtual QString getName() const
Returns object name.
virtual void setName(const QString &name)
Sets object name.
bool removeMetaData(const QString &key)
Removes a given associated meta-data.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
virtual void applyRigidTransformation(const ccGLMatrix &trans) override
Applies a rigid transformation (rotation + translation)
virtual void scale(PointCoordinateType fx, PointCoordinateType fy, PointCoordinateType fz, CCVector3 center=CCVector3(0, 0, 0)) override
Multiplies all coordinates by constant factors (one per dimension)
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
bool reserveTheRGBTable()
Reserves memory to store the RGB colors.
void clear() override
Clears the entity from all its points and features.
virtual ccPointCloud & Translate(const Eigen::Vector3d &translation, bool relative=true) override
Apply translation to the geometry coordinates.
bool hasColors() const override
Returns whether colors are enabled or not.
const ecvColor::Rgb & getPointColor(unsigned pointIndex) const override
Returns color corresponding to a given point.
void addRGBColor(const ecvColor::Rgb &C)
Pushes an RGB color on stack.
ccPointCloud * partialClone(const cloudViewer::ReferenceCloud *selection, int *warnings=nullptr, bool withChildEntities=true) const
Creates a new point cloud object from a ReferenceCloud (selection)
bool reserveThePointsTable(unsigned _numberOfPoints)
Reserves memory to store the points coordinates.
void showVertices(bool state)
Sets whether to display or hide the polyline vertices.
void setColor(const ecvColor::Rgb &col)
Sets the polyline color.
Standard ECV plugin interface.
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
void getBoundingBox(CCVector3 &bbMin, CCVector3 &bbMax) override
unsigned size() const override
ScalarType getPointScalarValue(unsigned pointIndex) const override
const CCVector3 * getPoint(unsigned index) const override
void setClosed(bool state)
Sets whether the polyline is closed or not.
A very simple point cloud (no point duplication)
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
void getBoundingBox(CCVector3 &bbMin, CCVector3 &bbMax) override
Returns the cloud bounding box.
virtual bool reserve(unsigned n)
Reserves some memory for hosting the point references.
A simple scalar field (to be associated to a point cloud)
virtual void computeMinAndMax()
Determines the min and max values.
void setValue(std::size_t index, ScalarType value)
__host__ __device__ int2 abs(int2 v)
QTextStream & endl(QTextStream &stream)
CLOUDVIEWER_HOST_DEVICE Pair< First, Second > make_pair(const First &_first, const Second &_second)
MiniVec< float, N > floor(const MiniVec< float, N > &a)
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
constexpr Rgb cyan(0, MAX, MAX)
std::string to_string(const T &n)
ccPolyline * contourPoly(ccPointCloud *stone)
float getDensity(ccPointCloud *cloud, vector< int > idx)
void dilationCC(int dilation_elem, int dilation_size, cv::Mat &src, cv::Mat &dilation_dst)
void extractInfo(cv::Mat &input, std::vector< std::vector< cv::Point >> &pixsLabel, cv::Mat &labels, cv::Mat &stats, std::vector< std::vector< Point >> &contours0)
cv::Mat stonesDivision(std::vector< std::vector< cv::Point >> pixsLabel, cv::Mat labels, std::vector< int > bigStones)
ccPolyline * contourPoly2(ccPointCloud *cloud0, vector< int > V, QString name)
std::vector< int > findMatlab(std::vector< double > inputV, int op, double thres)
ccPointCloud * getMortarMaps(ccPointCloud *f_cloudStones, ccPointCloud *f_cloudMortar)
void fft2(const cv::Mat in, cv::Mat &complexI)
cv::Mat multiplicationCC(cv::Mat_< std::complex< double >> M1, cv::Mat_< std::complex< double >> M2)
std::vector< int > findIdx(std::vector< int > inputV, int thres)
void erosionCC(int erosion_elem, int erosion_size, cv::Mat &src, cv::Mat &erosion_dst)
std::vector< int > setIntersectIdxPixs1D(std::vector< int > listNew, std::vector< int > listOld)
std::vector< cv::Point > setdiffPixs(std::vector< cv::Point > listNew, std::vector< cv::Point > listOld)
cv::Mat conjugate(cv::Mat_< std::complex< double >> M1, bool *flag)
std::vector< cv::Point > extractVectorFromIdx(std::vector< cv::Point > v, vector< int > idx)
double optRotY(ccPointCloud *&cloud)
void cwt2d(double sca, cv::Mat image, cv::Mat &cwtcfs, cv::Mat &bincfs)
void cloud2binary(ccPointCloud *cloud, cv::Mat &corrMatS, std::vector< cv::Point > &idxPxS, std::vector< int > &idxPx1DS, cv::Mat &imageBWS)
std::vector< std::vector< cv::Point > > pixelListMat(cv::Mat inputM, int nLabels)
void fillEdgeImage(cv::Mat edgesIn, cv::Mat &filledEdgesOut, int z)
cv::Mat skeleton(cv::Mat I, bool flagInv)
#define CV_PCA_DATA_AS_ROW
std::vector< int > setIntersectIdxPixs(std::vector< cv::Point > listNew, std::vector< cv::Point > listOld)
void rotY(ccPointCloud *&cloud, double th0)
cv::Mat threshSegments(cv::Mat &src, double threshSize)
double stddev(std::vector< double > const &func)
string type2str(int type)
std::vector< int > pixelValues(cv::Mat inputM, std::vector< cv::Point > &pixelList)
std::vector< cv::Point > setxorPixs(std::vector< cv::Point > listNew, std::vector< cv::Point > listOld)
void populateMat(cv::Mat &populated, std::vector< cv::Point > pixList, int value)