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++) {
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++) {
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.
ccHObject * getParent() const
Returns parent object.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
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 scale(PointCoordinateType fx, PointCoordinateType fy, PointCoordinateType fz, CCVector3 center=CCVector3(0, 0, 0)) override
Multiplies all coordinates by constant factors (one per dimension)
ccPointCloud * partialClone(const cloudViewer::ReferenceCloud *selection, int *warnings=nullptr, bool withChildEntities=true) const
Creates a new point cloud object from a ReferenceCloud (selection)
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
virtual ccPointCloud & Translate(const Eigen::Vector3d &translation, bool relative=true) override
Apply translation to the geometry coordinates.
bool reserveTheRGBTable()
Reserves memory to store the RGB colors.
void clear() override
Clears the entity from all its points and features.
virtual void applyRigidTransformation(const ccGLMatrix &trans) override
Applies a rigid transformation (rotation + translation)
bool hasColors() const override
Returns whether colors are enabled or not.
void addRGBColor(const ecvColor::Rgb &C)
Pushes an RGB color on stack.
const ecvColor::Rgb & getPointColor(unsigned pointIndex) const override
Returns color corresponding to a given point.
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)
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)