#pragma once #include "stdafx.h" #include #include #include #include "OTSImageProcess.h" #include "OTSImageProcessParam.h" #include #include "OTSMorphology.h" #include "../OTSLog/COTSUtilityDllFunExport.h" #include "FieldMgr.h" using namespace cv; using namespace std; namespace OTSIMGPROC { // Re-magnification const int nImage_Size = 3; //make matrix filled with 255 const int nBlackColor = 255; //make binary processing parameter 128 const int nProcessParam = 100; //picture size const int nPictureSize = 128; // added to filtered pixels const double delta = 0; using namespace std; namespace { /***** 求两点间距离*****/ float getDistance(Point pointO, Point pointA) { float distance; distance = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2); distance = sqrtf(distance); return distance; } /***** 点到直线的距离:P到AB的距离*****/ //P为线外一点,AB为线段两个端点 float getDist_P2L(Point pointP, Point pointA, Point pointB) { //求直线方程 int A = 0, B = 0, C = 0; A = pointA.y - pointB.y; B = pointB.x - pointA.x; C = pointA.x*pointB.y - pointA.y*pointB.x; //代入点到直线距离公式 float distance = 0; distance = ((float)abs(A*pointP.x + B * pointP.y + C)) / ((float)sqrtf(A*A + B * B)); return distance; } int Side(Point P1, Point P2, Point point) { /*Point P1 = line.P1; Point P2 = line.P2;*/ return ((P2.y - P1.y) * point.x + (P1.x - P2.x) * point.y + (P2.x*P1.y - P1.x*P2.y)); } void FindInnerCircleInContour(vector contour, Point ¢er, int &radius) { Rect r = boundingRect(contour); int nL = r.x, nR = r.br().x; //轮廓左右边界 int nT = r.y, nB = r.br().y; //轮廓上下边界 double dist = 0; double maxdist = 0; for (int i = nL; i < nR; i++) //列 { for (int j = nT; j < nB; j++) //行 { //计算轮廓内部各点到最近轮廓点的距离 dist = pointPolygonTest(contour, Point(i, j), true); if (dist > maxdist) { //求最大距离,只有轮廓最中心的点才距离最大 maxdist = dist; center = Point(i, j); } } } radius = maxdist; //圆半径 } BOOL GetParticleAverageChord(std::vector listEdge, double a_PixelSize, double &dPartFTD) { // safety check double nx = 0, ny = 0; Moments mu; mu = moments(listEdge, false); nx = mu.m10 / mu.m00; ny = mu.m01 / mu.m00; //circle(cvcopyImg, Point(nx, ny), 1, (255), 1); Point ptCenter = Point((int)nx, (int)ny); // coordinate transformation Point ptPosition; int radiusNum = 0; // get ferret diameter double sumFltDiameter = 0; int interval; int edgePointNum = listEdge.size(); if (edgePointNum > 10) { interval = edgePointNum / 10;//get one line per 10 degree aproxemately } else { interval = 1; } for (int i = 0; i < edgePointNum; i++) { Point pt = listEdge[i]; ptPosition.x = abs(pt.x - ptCenter.x); ptPosition.y = abs(pt.y - ptCenter.y); if (i % interval == 0)//calculate one line per 10 point ,so to speed up.don't calculate all the diameter. { double r1 = sqrt(pow(ptPosition.x, 2) + pow(ptPosition.y, 2)); sumFltDiameter += r1; radiusNum += 1; //line(cvImageData, ptCenter, pt, Scalar(nBlackColor), nThickness, nLineType); } } if (radiusNum == 0) { dPartFTD = 0; } else { dPartFTD = a_PixelSize * sumFltDiameter / radiusNum * 2; } //imshow("feret center", cvImageData); return TRUE; } void linearSmooth5(WORD wordIn[], WORD wordOut[], int N = 255)//smooth algorithm { double in[256]; double out[256]; double smoothCurveData[256]; for (int i = 0; i < 256; i++) { in[i] = (double)wordIn[i]; } int i; if (N < 5) { for (i = 0; i <= N - 1; i++) { out[i] = in[i]; } } else { out[0] = (3.0 * in[0] + 2.0 * in[1] + in[2] - in[4]) / 5.0; out[1] = (4.0 * in[0] + 3.0 * in[1] + 2 * in[2] + in[3]) / 10.0; for (i = 2; i <= N - 3; i++) { out[i] = (in[i - 2] + in[i - 1] + in[i] + in[i + 1] + in[i + 2]) / 5.0; } out[N - 2] = (4.0 * in[N - 1] + 3.0 * in[N - 2] + 2 * in[N - 3] + in[N - 4]) / 10.0; out[N - 1] = (3.0 * in[N - 1] + 2.0 * in[N - 2] + in[N - 3] - in[N - 5]) / 5.0; } for (int i = 0; i < N; i++) { wordOut[i] = (WORD)out[i]; } } void GetMatricsParticlesFromRawParticle(COTSParticlePtr a_pOTSPart,int imageWidth,int imageHeight, double a_PixelSize, int xrayStep, COTSParticleList& matricsParts) { auto originalSegs = a_pOTSPart->GetFeature()->GetSegmentsList(); std::map segsOnTheSameHeight; for (auto s : originalSegs) { segsOnTheSameHeight[s->GetHeight()].push_back(s); } auto rect = a_pOTSPart->GetParticleRect(); std::vector matrixPs; int colnum = ceil((double)rect.Width() / xrayStep + 0.5); if (colnum % 2 == 0) colnum += 1;//let the number to be an odd number.Then we can make the middle point in the center of the particle exactly. int rownum = ceil((double)rect.Height() / xrayStep + 0.5); if (rownum % 2 == 0) rownum += 1; CPoint theFirst = CPoint(rect.left-(colnum*xrayStep-rect.Width())/2 + xrayStep / 2, rect.top-(rownum*xrayStep-rect.Height())/2 + xrayStep / 2); for (int i = 0; i < rownum; i++) { for (int j = 0; j < colnum; j++) { double x =(double) theFirst.x + (double)j * xrayStep; double y = (double)theFirst.y + (double)i * xrayStep; CPoint thePoint = CPoint(x, y); matrixPs.push_back(thePoint); } } a_pOTSPart->SetXrayMatrixPoints(matrixPs); for (auto point : matrixPs) { COTSParticlePtr part = COTSParticlePtr(new COTSParticle()); COTSSegmentsList segs; for (int i = 0; i < xrayStep; i++) { COTSSegmentPtr seg = COTSSegmentPtr(new COTSSegment()); seg->SetStart(point.x - xrayStep / 2); seg->SetLength(xrayStep); seg->SetHeight(point.y - xrayStep / 2 + i); auto originalSegs = segsOnTheSameHeight[seg->GetHeight()]; int currentH = seg->GetHeight(); int segStart = seg->GetStart(); int segEnd = seg->GetEnd(); for (int i = 0; i < originalSegs.size();i++)//judge if the seg is in the original particle scope. { auto rseg = originalSegs[i]; int rsegStart = rseg->GetStart(); int rsegEnd = rseg->GetEnd(); if (segStart > rsegEnd || rsegStart > segEnd)//there's no intersection.is not a valid seg for this original segment. { continue; } if (segStart>=rsegStart && segEnd <= rsegEnd)//contained in the original segment,is a valid seg. { segs.push_back(seg); continue; } else if (segStart>= rsegStart&& segEnd >= rsegEnd)// intersect in the head end.Modify the end of the seg . { COTSSegmentPtr newseg = COTSSegmentPtr(new COTSSegment()); newseg->SetStart(segStart); newseg->SetEnd(rsegEnd); newseg->SetHeight(currentH); segs.push_back(newseg); continue; } else if (segStart<= rsegStart&& segEnd >= rsegEnd) { COTSSegmentPtr newseg = COTSSegmentPtr(new COTSSegment()); newseg->SetStart(rsegStart); newseg->SetEnd(rsegEnd); newseg->SetHeight(currentH); segs.push_back(newseg); continue; } else if (segStart<= rsegStart&& rsegEnd >= segEnd) { COTSSegmentPtr newseg = COTSSegmentPtr(new COTSSegment()); newseg->SetStart(rsegStart); newseg->SetEnd(segEnd); newseg->SetHeight(currentH); segs.push_back(newseg); continue; } } } if (segs.size() > 0) { part->GetFeature()->SetSegmentsList(segs); part->CalXRayPos(); part->SetFieldId(a_pOTSPart->GetFieldId()); part->SetAnalysisId(a_pOTSPart->GetAnalysisId()); matricsParts.push_back(part); } } } void BlurImage(CBSEImgPtr inImg) { int rows, cols; cols = inImg->GetWidth(); rows = inImg->GetHeight(); BYTE* pPixel = inImg->GetImageDataPointer(); Mat cvcopyImg = Mat(rows, cols, CV_8UC1, pPixel); //Mat blurImg; //medianBlur(cvcopyImg, cvcopyImg, 11);//get rid of the noise point. //cv::bilateralFilter cv::GaussianBlur(cvcopyImg, cvcopyImg, Size(5, 5), 2); //inImg->SetImageData(cvcopyImg.data, width, height); /*outImg = inImg;*/ } Mat GetMatDataFromBseImg(CBSEImgPtr inImg) { int rows, cols; cols = inImg->GetWidth(); rows = inImg->GetHeight(); BYTE* pPixel = inImg->GetImageDataPointer(); Mat cvcopyImg = Mat(rows, cols, CV_8UC1, pPixel); return cvcopyImg; } CBSEImgPtr GetBSEImgFromMat(Mat inImg) { CBSEImgPtr bse = CBSEImgPtr(new CBSEImg(CRect(0, 0, inImg.cols, inImg.rows))); BYTE* pPixel = inImg.data; bse->SetImageData(pPixel, inImg.cols, inImg.rows); return bse; } /*********************************************************** 增强算法的原理在于先统计每个灰度值在整个图像中所占的比例 然后以小于当前灰度值的所有灰度值在总像素中所占的比例,作为增益系数 对每一个像素点进行调整。由于每一个值的增益系数都是小于它的所有值所占 的比例和。所以就使得经过增强之后的图像亮的更亮,暗的更暗。 ************************************************************/ void ImageStretchByHistogram(const Mat& src, Mat& dst) { //判断传入参数是否正常 if (!(src.size().width == dst.size().width)) { cout << "error" << endl; return; } double p[256], p1[256], num[256]; memset(p, 0, sizeof(p)); memset(p1, 0, sizeof(p1)); memset(num, 0, sizeof(num)); int height = src.size().height; int width = src.size().width; long wMulh = height * width; //统计每一个灰度值在整个图像中所占个数 for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { uchar v = src.at(y, x); num[v]++; } } //使用上一步的统计结果计算每一个灰度值所占总像素的比例 for (int i = 0; i < 256; i++) { p[i] = num[i] / wMulh; } //计算每一个灰度值,小于当前灰度值的所有灰度值在总像素中所占的比例 //p1[i]=sum(p[j]); j<=i; for (int i = 0; i < 256; i++) { for (int k = 0; k <= i; k++) p1[i] += p[k]; } //以小于当前灰度值的所有灰度值在总像素中所占的比例,作为增益系数对每一个像素点进行调整。 for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { uchar v = src.at(y, x); dst.at(y, x) = p1[v] * 255 + 0.5; } } return; } //调整图像对比度 Mat AdjustContrastY(const Mat& img) { Mat out = Mat::zeros(img.size(), CV_8UC1); Mat workImg = img.clone(); //对图像进行对比度增强 ImageStretchByHistogram(workImg, out); return Mat(out); } } COTSImageProcess::COTSImageProcess() { } COTSImageProcess::~COTSImageProcess() { } // ReZoom the picture with re-magnification BOOL COTSImageProcess::ReZoom(CString InPutPath, CString OutPutPath) { Mat cvSrcImg; string strInputPath; strInputPath = CStringA(InPutPath); // Pictures loop in folder std::vector ImageFolder; cv::glob(strInputPath, ImageFolder); if (ImageFolder.size() == 0) { return FALSE; } for (unsigned int nImgNum = 0; nImgNum < ImageFolder.size(); ++nImgNum) { cvSrcImg = cv::imread(ImageFolder[nImgNum], CV_LOAD_IMAGE_GRAYSCALE); // Image convolution operation //// convolution kernel float kernel[] = { -1, -1 , -1, -1 , 0, -1, -1 , -1 , -1 }; cv::Mat ker = cv::Mat(nImage_Size, nImage_Size, CV_32F, &kernel); cv::Mat cvDstImg = cv::Mat(cvSrcImg.size(), cvSrcImg.type()); // anchor of the kernel cv::Point anchor(-1, -1); cv::filter2D(cvSrcImg, cvDstImg, CV_32F, ker, anchor, delta, cv::THRESH_TRUNC); // Maximum Pixel Value cvDstImg = abs(cvDstImg); double minVal, maxVal; minMaxLoc(cvDstImg, &minVal, &maxVal); // Grayscale image int nReduce; Mat onesImg = Mat::ones(cvDstImg.rows, cvDstImg.cols, CV_32F) * (int)minVal; absdiff(cvDstImg, onesImg, cvDstImg); nReduce = (int)maxVal - minVal; cvDstImg = cvDstImg * nBlackColor / nReduce; // Output image convert data to int cvDstImg.convertTo(cvDstImg, CV_8U); // Process the picture to 128 pixels resize(cvDstImg, cvDstImg, Size(nPictureSize, nPictureSize)); threshold(cvDstImg, cvDstImg, nProcessParam, nBlackColor, CV_THRESH_BINARY); string strOutPutPath; strOutPutPath = CStringA(OutPutPath); imwrite(strOutPutPath , cvDstImg); } return TRUE; } BOOL COTSImageProcess::RemoveBSEImageBG(CBSEImgPtr m_pBSEImg, COTSImageProcessParamPtr a_pImgProcessParam,COTSFieldDataPtr m_pFieldData) { ASSERT(m_pFieldData); ASSERT(m_pBSEImg); ASSERT(a_pImgProcessParam); int nWidthImg = m_pBSEImg->GetWidth(); int nHeightImg = m_pBSEImg->GetHeight(); m_pFieldData->Width = nWidthImg; m_pFieldData->Height = nHeightImg; long nImgSize = nWidthImg * nHeightImg; BYTE* pSrcImg = m_pBSEImg->GetImageDataPointer(); BYTE* pTempImg = new BYTE[nImgSize]; CRect r = CRect(0, 0, nWidthImg, nHeightImg); CBSEImgPtr imgNoBGBinary = CBSEImgPtr(new CBSEImg(r)); long nNumParticle = 0; RemoveBackGround(m_pBSEImg, a_pImgProcessParam, imgNoBGBinary,nNumParticle); BYTE* pPixel = imgNoBGBinary->GetImageDataPointer(); long nPtStart = a_pImgProcessParam->GetParticleGray().GetStart(); long nPtEnd = a_pImgProcessParam->GetParticleGray().GetEnd(); if (nNumParticle == 0) { COTSParticleList listParticleEmpty; listParticleEmpty.clear(); m_pFieldData->SetParticleList(listParticleEmpty); } else { // get the area image Mat blurImg; Mat srcImg = Mat(nHeightImg, nWidthImg, CV_8UC1, pPixel); //medianBlur(srcImg, blurImg, 3);//smooth the edge COTSParticleList listParticleOut; if (!GetParticles(0,0,nWidthImg, nHeightImg, srcImg.data, listParticleOut)) { COTSParticleList listParticleEmpty; listParticleEmpty.clear(); m_pFieldData->SetParticleList(listParticleEmpty); } // form a image only have particles on COTSSegmentsList listImage; for (auto pParticle : listParticleOut) { COTSFeaturePtr pFeature = pParticle->GetFeature(); COTSSegmentsList listSegment = pFeature->GetSegmentsList(); long nPixelNum = 0; long nPixelAll = 0; int nStartS = 0; int nHeightS = 0; int nLengthS = 0; for (auto pSegment : listSegment) { // update image list COTSSegmentPtr pSegNew = COTSSegmentPtr(new COTSSegment(*pSegment.get())); listImage.push_back(pSegNew); // get particle average gray nStartS = pSegment->GetStart(); nHeightS = pSegment->GetHeight(); nLengthS = pSegment->GetLength(); nPixelNum += (long)nLengthS; if (nHeightS > nHeightImg) { LogErrorTrace(__FILE__, __LINE__, _T("seg height is wrong.")); return FALSE; } if ((nStartS + nLengthS - 1) > nWidthImg) { LogErrorTrace(__FILE__, __LINE__, _T("seg starst and length is wrong.")); return FALSE; } for (unsigned int i = 0; i < nLengthS; i++) { if ((nStartS + i) > nWidthImg) { LogErrorTrace(__FILE__, __LINE__, _T("seg start is wrong.")); return FALSE; } else if (nHeightS > nHeightImg) { LogErrorTrace(__FILE__, __LINE__, _T("seg height is wrong.")); return FALSE; } long nValueTemp = (long)*(pSrcImg + nHeightS * nWidthImg + nStartS + i); nPixelAll += nValueTemp; } } BYTE nAveGray = (BYTE)(nPixelAll / nPixelNum); pParticle->SetAveGray(nAveGray); pParticle->SetActualArea(nPixelNum); } m_pFieldData->SetParticleList(listParticleOut); } delete[]pTempImg; return TRUE; } BOOL COTSImageProcess::RemoveBGByFindContour(CBSEImgPtr m_pBSEImg, COTSImageProcessParamPtr a_pImageProcessParam, COTSFieldDataPtr m_pFieldData) { ASSERT(m_pFieldData); ASSERT(m_pBSEImg); ASSERT(a_pImageProcessParam); int nWidthImg = m_pBSEImg->GetWidth(); int nHeightImg = m_pBSEImg->GetHeight(); m_pFieldData->Width = nWidthImg; m_pFieldData->Height = nHeightImg; long nImgSize = nWidthImg * nHeightImg; BYTE* pSrcImg = m_pBSEImg->GetImageDataPointer(); BYTE* pTempImg = new BYTE[nImgSize]; CRect r = CRect(0, 0, nWidthImg, nHeightImg); CBSEImgPtr imgNoBGBinary = CBSEImgPtr(new CBSEImg(r)); long nNumParticle = 0; RemoveBackGround(m_pBSEImg, a_pImageProcessParam, imgNoBGBinary, nNumParticle); BYTE* pPixel = imgNoBGBinary->GetImageDataPointer(); long nPtStart = a_pImageProcessParam->GetParticleGray().GetStart(); long nPtEnd = a_pImageProcessParam->GetParticleGray().GetEnd(); if (nNumParticle == 0) { COTSParticleList listParticleEmpty; listParticleEmpty.clear(); m_pFieldData->SetParticleList(listParticleEmpty); } else { // get the area image Mat cvcopyImg = Mat(nHeightImg, nWidthImg, CV_8UC1, pPixel); vector>contours; findContours(cvcopyImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); COTSParticleList listParticleOut; for (size_t i = 0; i < contours.size(); i++) { Rect rectMax = boundingRect(contours[i]); Mat rectROI = cvcopyImg(rectMax).clone(); //exclude the point which intersect into this bounding box but is not in this contour. for (int nX = 0; nX < rectROI.rows; nX++) { for (int nY = 0; nY < rectROI.cols; nY++) { double localPos = pointPolygonTest(contours[i], Point2f(nX + rectMax.x, nY + rectMax.y), false); if (localPos == -1) { rectROI.data[nX, nY] = 0;//set the value to 0,so we won't consider it when we find segment and feature in this ROI. } } } GetParticles(rectMax.x, rectMax.y, rectMax.width, rectMax.height, rectROI.data, listParticleOut); } // form a image only have particles on //COTSSegmentsList listImage; for (auto pParticle : listParticleOut) { COTSFeaturePtr pFeature = pParticle->GetFeature(); COTSSegmentsList listSegment = pFeature->GetSegmentsList(); long nPixelNum = 0; long nPixelAll = 0; int nStartS = 0; int nHeightS = 0; int nLengthS = 0; for (auto pSegment : listSegment) { // get particle average gray nStartS = pSegment->GetStart(); nHeightS = pSegment->GetHeight(); nLengthS = pSegment->GetLength(); nPixelNum += (long)nLengthS; for (unsigned int i = 0; i < nLengthS; i++) { long nValueTemp = (long)*(pSrcImg + nHeightS * nWidthImg + nStartS + i); nPixelAll += nValueTemp; } } BYTE nAveGray = (BYTE)(nPixelAll / nPixelNum); pParticle->SetAveGray(nAveGray); pParticle->SetActualArea(nPixelNum); } m_pFieldData->SetParticleList(listParticleOut); } delete[]pTempImg; return TRUE; } BOOL COTSImageProcess::RemoveBGByCVconnectivities(CBSEImgPtr inBSEImg, COTSImageProcessParamPtr a_pImageProcessParam,double a_pixelSize, COTSFieldDataPtr m_pFieldData) { ASSERT(m_pFieldData); ASSERT(inBSEImg); ASSERT(a_pImageProcessParam); int nWidthImg = inBSEImg->GetWidth(); int nHeightImg = inBSEImg->GetHeight(); m_pFieldData->Width = nWidthImg; m_pFieldData->Height = nHeightImg; long nImgSize = nWidthImg * nHeightImg; BYTE* pSrcImg = inBSEImg->GetImageDataPointer(); BYTE* pTempImg = new BYTE[nImgSize]; CRect r = CRect(0, 0, nWidthImg, nHeightImg); CBSEImgPtr imgNoBGBinary = CBSEImgPtr(new CBSEImg(r)); long nNumParticle = 0; RemoveBackGround(inBSEImg, a_pImageProcessParam, imgNoBGBinary, nNumParticle); BYTE* pPixel = imgNoBGBinary->GetImageDataPointer(); long nPtStart = a_pImageProcessParam->GetParticleGray().GetStart(); long nPtEnd = a_pImageProcessParam->GetParticleGray().GetEnd(); if (nNumParticle == 0) { COTSParticleList listParticleEmpty; listParticleEmpty.clear(); m_pFieldData->SetParticleList(listParticleEmpty); } else { // get the area image Mat cvcopyImg = Mat(nHeightImg, nWidthImg, CV_8UC1, pPixel); //Mat blurImg; //medianBlur(cvcopyImg, blurImg, 5);//get rid of the noise point. Mat labels = Mat::zeros(cvcopyImg.size(), CV_32S); Mat stats, centroids; int number = connectedComponentsWithStats(cvcopyImg, labels, stats, centroids, 8, CV_32S); double rMin = a_pImageProcessParam->GetIncArea().GetStart()/2.0; double rMax = a_pImageProcessParam->GetIncArea().GetEnd()/2.0; double partAreaMin = rMin * rMin * 3.14159; double partAreaMax = rMax * rMax * 3.14159; COTSParticleList listParticleOut; for (size_t i = 1; i < number; i++) { int center_x = centroids.at(i, 0); int center_y = centroids.at(i, 1); //矩形边框 int x = stats.at(i, CC_STAT_LEFT); int y = stats.at(i, CC_STAT_TOP); int w = stats.at(i, CC_STAT_WIDTH); int h = stats.at(i, CC_STAT_HEIGHT); int area = stats.at(i, CC_STAT_AREA); double actualArea = area * a_pixelSize * a_pixelSize; if (actualArea >= partAreaMin && actualArea < partAreaMax) { Rect rectMax = Rect(x, y, w, h); Mat rectROI = labels(rectMax).clone(); Mat imageROI = Mat::zeros(rectMax.size(), cvcopyImg.type()); //exclude the point which intersect into this bounding box but is not in this group. int label = i; for (int row = 0; row < rectROI.rows; row++) { for (int col = 0; col < rectROI.cols; col++) { int v = rectROI.at(row, col); if (v == label) { imageROI.at(row, col) = 255;//set the value to 255,so we won't consider other pixel when we find segment and feature in this ROI. } } } COTSParticleList roiParts; if (GetOneParticleFromROI(rectMax.x, rectMax.y, rectMax.width, rectMax.height, imageROI.data, roiParts)) { if (roiParts.size() > 0) { COTSParticlePtr roiPart = roiParts[0];//we will find only one part in the roi. roiPart->SetXRayPos(CPoint(center_x, center_y)); CRect r = CRect(x, y, x + w, y + h); roiPart->SetParticleRect(r); roiPart->SetActualArea(actualArea); roiPart->SetPixelArea(area); listParticleOut.push_back(roiPart); } } } } int nTagId; for (auto pParticle : listParticleOut) { COTSFeaturePtr pFeature = pParticle->GetFeature(); COTSSegmentsList listSegment = pFeature->GetSegmentsList(); long nPixelNum = 0; long nPixelAll = 0; int nStartS = 0; int nHeightS = 0; int nLengthS = 0; for (auto pSegment : listSegment) { // get particle average gray nStartS = pSegment->GetStart(); nHeightS = pSegment->GetHeight(); nLengthS = pSegment->GetLength(); nPixelNum += (long)nLengthS; for (unsigned int i = 0; i < nLengthS; i++) { long nValueTemp = (long)*(pSrcImg + nHeightS * nWidthImg + nStartS + i); nPixelAll += nValueTemp; } } BYTE nAveGray = (BYTE)(nPixelAll / nPixelNum); pParticle->SetAveGray(nAveGray); } m_pFieldData->SetParticleList(listParticleOut); } delete[]pTempImg; return TRUE; } BOOL COTSImageProcess::GetParticlesBySpecialGrayRange(CBSEImgPtr a_pBSEImg, CIntRangePtr a_grayRange,CDoubleRangePtr a_diameterRange,double a_pixelSize, COTSFieldDataPtr m_pFieldData) { ASSERT(m_pFieldData); ASSERT(a_pBSEImg); ASSERT(a_grayRange); int nWidthImg = a_pBSEImg->GetWidth(); int nHeightImg = a_pBSEImg->GetHeight(); m_pFieldData->Width = nWidthImg; m_pFieldData->Height = nHeightImg; long nImgSize = nWidthImg * nHeightImg; BYTE* pSrcImg = a_pBSEImg->GetImageDataPointer(); BYTE* pTempImg = new BYTE[nImgSize]; CRect r = CRect(0, 0, nWidthImg, nHeightImg); CBSEImgPtr imgNoBGBinary = CBSEImgPtr(new CBSEImg(r)); long nNumParticle = 0; GetSpecialGrayRangeImage(a_pBSEImg, a_grayRange, imgNoBGBinary, nNumParticle); BYTE* pPixel = imgNoBGBinary->GetImageDataPointer(); if (nNumParticle == 0) { COTSParticleList listParticleEmpty; listParticleEmpty.clear(); m_pFieldData->SetParticleList(listParticleEmpty); } else { // get the area image Mat cvcopyImg = Mat(nHeightImg, nWidthImg, CV_8UC1, pPixel); Mat labels = Mat::zeros(cvcopyImg.size(), CV_32S); Mat stats, centroids; int number = connectedComponentsWithStats(cvcopyImg, labels, stats, centroids, 8, CV_32S); double rStart = a_diameterRange->GetStart() / 2.0; double rEnd = a_diameterRange->GetEnd() / 2.0; double areaStart = rStart * rStart * 3.14159; double areaEnd = rEnd * rEnd * 3.14159; COTSParticleList listParticleOut; for (size_t i = 1; i < number; i++) { int center_x = centroids.at(i, 0); int center_y = centroids.at(i, 1); //矩形边框 int x = stats.at(i, CC_STAT_LEFT); int y = stats.at(i, CC_STAT_TOP); int w = stats.at(i, CC_STAT_WIDTH); int h = stats.at(i, CC_STAT_HEIGHT); int area = stats.at(i, CC_STAT_AREA); double actualArea = area * a_pixelSize * a_pixelSize; if (actualArea >= areaStart && actualArea < areaEnd) { Rect rectMax = Rect(x, y, w, h); Mat rectROI = labels(rectMax).clone(); Mat imageROI = Mat::zeros(rectMax.size(), cvcopyImg.type()); //exclude the point which intersect into this bounding box but is not in this group. int label = i; for (int row = 0; row < rectROI.rows; row++) { for (int col = 0; col < rectROI.cols; col++) { int v = rectROI.at(row, col); if (v == label) { imageROI.at(row, col) = 255; } } } COTSParticleList roiParts; if (!GetOneParticleFromROI(rectMax.x, rectMax.y, rectMax.width, rectMax.height, imageROI.data, roiParts)) { continue; } if (roiParts.size() > 0) { COTSParticlePtr roiPart = roiParts[0]; roiPart->SetXRayPos(CPoint(center_x, center_y)); CRect r = CRect(x, y, x + w, y + h); roiPart->SetParticleRect(r); roiPart->SetActualArea(actualArea); roiPart->SetPixelArea(area); listParticleOut.push_back(roiPart); } } } // form a image only have particles on //COTSSegmentsList listImage; for (auto pParticle : listParticleOut) { int area = pParticle->GetActualArea(); double pActualArea = area ; COTSFeaturePtr pFeature = pParticle->GetFeature(); COTSSegmentsList listSegment = pFeature->GetSegmentsList(); long nPixelNum = 0; long nPixelAll = 0; int nStartS = 0; int nHeightS = 0; int nLengthS = 0; for (auto pSegment : listSegment) { // get particle average gray nStartS = pSegment->GetStart(); nHeightS = pSegment->GetHeight(); nLengthS = pSegment->GetLength(); nPixelNum += (long)nLengthS; for (unsigned int i = 0; i < nLengthS; i++) { long nValueTemp = (long)*(pSrcImg + nHeightS * nWidthImg + nStartS + i); nPixelAll += nValueTemp; } } BYTE nAveGray = (BYTE)(nPixelAll / nPixelNum); pParticle->SetAveGray(nAveGray); } m_pFieldData->SetParticleList(listParticleOut); } delete[]pTempImg; return TRUE; } CIntRangePtr COTSImageProcess::CalBackground(CBSEImgPtr m_pBSEImg) { auto ranges = CalcuGrayLevelRange(m_pBSEImg); return ranges[0]; } std::vector COTSImageProcess::CalcuGrayLevelRange(CBSEImgPtr m_pBSEImg) { CIntRangePtr pBackground = CIntRangePtr(new CIntRange()); WORD originChartData[MAXBYTE]; WORD firstSmoothChart[MAXBYTE]; WORD secondSmooth[MAXBYTE]; //1. get chart data m_pBSEImg->SetChartData(); memcpy(originChartData, m_pBSEImg->GetBSEChart(), sizeof(WORD) * MAXBYTE); originChartData[0] = 0; originChartData[254] = 0; linearSmooth5(originChartData, firstSmoothChart, MAXBYTE); linearSmooth5(firstSmoothChart, secondSmooth, MAXBYTE); //linearSmooth5(secondSmooth, secondSmooth, MAXBYTE); /*linearSmooth5(secondSmooth, secondSmooth, MAXBYTE); linearSmooth5(secondSmooth, secondSmooth, MAXBYTE);*/ //2. get down edge int nLengthEdge = MAXBYTE + 2; WORD n_aBSEChart[MAXBYTE + 2]; memset(n_aBSEChart, 0, sizeof(WORD) * nLengthEdge); std::map> peakMap;// hold all the peaks in this spectrum which are sorted by there area. std::vector currentUpSeries; std::vector currentPeakSeries; // make sure the wave begin with up edge and end with down edge n_aBSEChart[0] = 0; n_aBSEChart[nLengthEdge - 1] = 0; memcpy(&n_aBSEChart[1], &secondSmooth, sizeof(WORD) * MAXBYTE); int nLengthCom = MAXBYTE + 1; // up edge for (int i = 0; i < nLengthCom; i++) { if (n_aBSEChart[i] <= n_aBSEChart[i + 1])//this is a upward edge { if (currentPeakSeries.size() > 0) { int seriesSize = currentPeakSeries.size(); long area = 0; for (int i = 0; i < seriesSize; i++) { area = area + n_aBSEChart[currentPeakSeries[i]]; } peakMap[area] = currentPeakSeries; currentPeakSeries.clear(); } currentUpSeries.push_back(i + 1);// save all the continuous up edge } else//this is a downward edge { // encounter a downward edge means upward edge series end, if (currentUpSeries.size() > 0) { currentPeakSeries = currentUpSeries; currentUpSeries.clear(); } currentPeakSeries.push_back(i + 1); } } if (currentPeakSeries.size() > 0) { int seriesSize = currentPeakSeries.size(); long area = 0; for (int i = 0; i < seriesSize; i++) { area = area + n_aBSEChart[currentPeakSeries[i]]; } peakMap[area] = currentPeakSeries; currentPeakSeries.clear(); } std::vector ranges; std::map>::reverse_iterator it; for (it=peakMap.rbegin();it!=peakMap.rend();it++) { CIntRangePtr pRange = CIntRangePtr(new CIntRange()); pRange->SetStart(it->second[0]); pRange->SetEnd(it->second[it->second.size()-1]); ranges.push_back(pRange); } return ranges; } void COTSImageProcess::GetSpecialGrayRangeImage(CBSEImgPtr a_pImgIn, CIntRangePtr a_SpecialGrayRange, CBSEImgPtr a_pBinImgOut, long& foundedPixelNum) { // the background pixel will be 0,and the other part will be 255. ASSERT(a_pImgIn); int nWidthImg = a_pImgIn->GetWidth(); int nHeightImg = a_pImgIn->GetHeight(); long nImgSize = nWidthImg * nHeightImg; BYTE* pTempImg = new BYTE[nImgSize]; BYTE* pSrcImg = a_pImgIn->GetImageDataPointer(); BYTE* pPixel = new byte[nImgSize]; long nBGStart; long nBGEnd; long nNumParticle = 0; nBGStart = a_SpecialGrayRange->GetStart(); nBGEnd = a_SpecialGrayRange->GetEnd(); // delete background for (unsigned int i = 0; i < nImgSize; i++) { if (pSrcImg[i] >= nBGStart && pSrcImg[i] <= nBGEnd) { pPixel[i] = 255; nNumParticle++; } else { pPixel[i] = 0; } } BErode3(pPixel, pTempImg, 5, nHeightImg, nWidthImg); BDilate3(pTempImg, pPixel, 5, nHeightImg, nWidthImg); a_pBinImgOut->SetImageData(pPixel, nWidthImg, nHeightImg); foundedPixelNum = nNumParticle; delete[] pTempImg; return; } void COTSImageProcess::RemoveBackGround(CBSEImgPtr a_pImgIn, COTSImageProcessParamPtr a_pImageProcessParam, CBSEImgPtr a_pBinImgOut,long& foundedPixelNum) { // the background pixel will be 0,and the other part will be 255. ASSERT(a_pImgIn); ASSERT(a_pImageProcessParam); int nWidthImg = a_pImgIn->GetWidth(); int nHeightImg = a_pImgIn->GetHeight(); long nImgSize = nWidthImg * nHeightImg; BYTE* pTempImg = new BYTE[nImgSize]; BYTE* pSrcImg = a_pImgIn->GetImageDataPointer(); BYTE* pPixel = new byte[nImgSize]; long nBGStart; long nBGEnd; long nPartStart; long nPartEnd; long nNumParticle = 0; if (a_pImageProcessParam->GetBGRemoveType() == OTS_BGREMOVE_TYPE::MANUAL) { nBGStart = a_pImageProcessParam->GetBGGray().GetStart(); nBGEnd = a_pImageProcessParam->GetBGGray().GetEnd(); nPartStart = a_pImageProcessParam->GetParticleGray().GetStart(); nPartEnd = a_pImageProcessParam->GetParticleGray().GetEnd(); // delete background for (unsigned int i = 0; i < nImgSize; i++) { if (pSrcImg[i] >= nBGStart && pSrcImg[i] <= nBGEnd) { pPixel[i] = 0; } else { pPixel[i] = 255; nNumParticle++; } if (pSrcImg[i]nPartEnd) { pPixel[i] = 0; } } int errodDilateParam = a_pImageProcessParam->GetErrodDilateParam(); if (errodDilateParam > 0) { BErode3(pPixel, pTempImg, errodDilateParam, nHeightImg, nWidthImg); BDilate3(pTempImg, pPixel, errodDilateParam, nHeightImg, nWidthImg); } } else { auto range = CalBackground(a_pImgIn); nBGStart = range->GetStart(); nBGEnd = range->GetEnd(); switch (a_pImageProcessParam->GetAutoBGRemoveType()) { case OTS_AUTOBGREMOVE_TYPE::DOWNWARD: for (unsigned int i = 0; i < nImgSize; i++) { if (pSrcImg[i] <= nBGEnd) { pPixel[i] = 0; } else { pPixel[i] = 255; nNumParticle++; } } break; case OTS_AUTOBGREMOVE_TYPE::UPWARD: for (unsigned int i = 0; i < nImgSize; i++) { if (pSrcImg[i] >= nBGStart) { pPixel[i] = 0; } else { pPixel[i] = 255; nNumParticle++; } } break; case OTS_AUTOBGREMOVE_TYPE::MIDDLE: for (unsigned int i = 0; i < nImgSize; i++) { if (pSrcImg[i] >= nBGStart && pSrcImg[i] <= nBGEnd) { pPixel[i] = 0; } else { pPixel[i] = 255; nNumParticle++; } } break; default: break; } int errodDilateParam = a_pImageProcessParam->GetErrodDilateParam(); if (errodDilateParam > 0) { BErode3(pPixel, pTempImg, errodDilateParam, nHeightImg, nWidthImg); BDilate3(pTempImg, pPixel, errodDilateParam, nHeightImg, nWidthImg); } } a_pBinImgOut->SetImageData(pPixel,nWidthImg,nHeightImg); foundedPixelNum = nNumParticle; delete[] pTempImg; return ; } BOOL COTSImageProcess::GetParticles(long left, long top, long a_nWidth, long a_nHeight, const BYTE* a_pPixel, COTSParticleList& a_listParticles) { ASSERT(a_pPixel); if (!a_pPixel) { return FALSE; } //a_listParticles.clear(); COTSParticleList findedParts; COTSSegmentsList listSegment; listSegment.clear(); //1. get segment line by line if (!GetSegmentList(left, top, a_nWidth, a_nHeight, a_pPixel, listSegment)) { return FALSE; } if ((int)listSegment.size() == 0) { return FALSE; } //2. save the temp feature COTSFeatureList listFeature; listFeature.clear(); if (!GetFeatureList(listSegment, listFeature))//get every feature for all the particle,the complete feature. { return FALSE; } if ((int)listFeature.size() == 0) { return FALSE; } /*COTSParticleList listParticles; listParticles.clear();*/ if (!ChangeFeaturelist(listFeature, findedParts)) { return FALSE; } for (auto f : findedParts) { a_listParticles.push_back(f); } return TRUE; } BOOL COTSImageProcess::GetOneParticleFromROI(long left, long top, long a_nWidth, long a_nHeight, const BYTE* a_pPixel, COTSParticleList& a_listParticles) { ASSERT(a_pPixel); if (!a_pPixel) { return FALSE; } //a_listParticles.clear(); COTSParticleList findedParts; COTSSegmentsList listSegment; listSegment.clear(); //1. get segment line by line if (!GetSegmentList(left, top, a_nWidth, a_nHeight, a_pPixel, listSegment)) { return FALSE; } if ((int)listSegment.size() == 0) { return FALSE; } //2. save the temp feature COTSFeatureList listFeature; listFeature.clear(); COTSFeaturePtr fea = COTSFeaturePtr(new COTSFeature()); fea->SetSegmentsList(listSegment); listFeature.push_back(fea); if ((int)listFeature.size() == 0) { return FALSE; } if (!ChangeFeaturelist(listFeature, findedParts)) { return FALSE; } for (auto f : findedParts) { a_listParticles.push_back(f); } return TRUE; } BOOL COTSImageProcess::GetSegmentList(long left, long top, long a_nWidth, long a_nHeight, const BYTE* a_pPixel, COTSSegmentsList& a_listSegments) { ASSERT(a_pPixel); long nImgSize = a_nWidth * a_nHeight; a_listSegments.clear(); //1. get segment line by line long nLine, nm, nn; long nStart = 0, nLength = 0; for (nLine = 0; nLine < a_nHeight; nLine++) { for (nm = 0; nm < a_nWidth; nm += (nLength + 1)) { nLength = 0; // get start if (*(a_pPixel + nLine * a_nWidth + nm) != 0) { nStart = nm; nLength++; //get length for (nn = nm + 1; nn < a_nWidth; nn++) { // check if segment is over, break if (nLength != 0) { if (*(a_pPixel + nLine * a_nWidth + nn) == 0) break; } if (*(a_pPixel + nLine * a_nWidth + nn) != 0) { nLength++; } } // generate segment COTSSegmentPtr pSegment = COTSSegmentPtr(new COTSSegment(nLine + top, nStart + left, nLength)); a_listSegments.push_back(pSegment); } else { continue; } } } if ((int)a_listSegments.size() == 0) { //LogErrorTrace(__FILE__, __LINE__, _T("no particle is found.")); return FALSE; } return TRUE; } BOOL COTSImageProcess::GetFeatureList(COTSSegmentsList& a_listSegments, COTSFeatureList& a_listFeatures) { COTSSegmentsList listSegmentNew; std::map mapOneLineSegments; for each (auto s in a_listSegments) { mapOneLineSegments[s->GetHeight()].push_back(s);//sorting all the segments base on the line number. } std::map::iterator lineItr = mapOneLineSegments.begin();//find the highest line while (lineItr != mapOneLineSegments.end()) { for (auto s = lineItr->second.begin(); s < lineItr->second.end(); )//find one segment of this line. { COTSSegmentPtr bottomSeg = *s; listSegmentNew.clear(); listSegmentNew.push_back(*s); s = lineItr->second.erase(s); std::map::iterator tempItr = lineItr; tempItr++; for (; tempItr != mapOneLineSegments.end(); tempItr++)//find all other lines of segments { if (tempItr->first - bottomSeg->GetHeight() > 1) { break; } for (auto nextLineSegment = tempItr->second.begin(); nextLineSegment < tempItr->second.end();)//find next line's all segments { if (((*nextLineSegment)->GetStart() - (bottomSeg->GetStart() + bottomSeg->GetLength())) > 1) { break; } if (bottomSeg->UpDownConection(**nextLineSegment)) { listSegmentNew.push_back(*nextLineSegment); bottomSeg = *nextLineSegment; nextLineSegment = tempItr->second.erase(nextLineSegment); break; } if (tempItr->second.size() > 0) { nextLineSegment++; } else { break; } } } COTSFeaturePtr pFeature = COTSFeaturePtr(new COTSFeature()); pFeature->SetSegmentsList(listSegmentNew); //check if this new feature is connected with other found feature. COTSSegmentPtr topSeg = listSegmentNew[0];//find the toppest segment of this new feature. COTSSegmentPtr bottomSegment = listSegmentNew[listSegmentNew.size() - 1];//find the lowest segment of this new feature. bool haveMerged = false; for each (auto f in a_listFeatures) { for (auto seg : f->GetSegmentsList()) { if (bottomSegment->UpDownConection(*seg) || topSeg->UpDownConection(*seg)) { COTSSegmentsList segs = f->GetSegmentsList(); for (auto s : listSegmentNew) { segs.push_back(s); } f->SetSegmentsList(segs); haveMerged = true; break; } } if (haveMerged) { break; } } if (!haveMerged) { a_listFeatures.push_back(pFeature); } if (lineItr->second.size() == 0) { break; } } lineItr++; } return true; } BOOL COTSImageProcess::ChangeFeaturelist(COTSFeatureList& a_listFeatures, COTSParticleList& a_listParticle) { for (auto pFeature : a_listFeatures) { COTSParticlePtr pParticle = COTSParticlePtr(new COTSParticle()); pParticle->SetFeature(pFeature); a_listParticle.push_back(pParticle); } if ((int)a_listParticle.size() == 0) { return FALSE; } return TRUE; } BOOL COTSImageProcess::CalcuParticleImagePropertes(COTSParticlePtr a_pOTSPart, double a_PixelSize) { //--------- convert this particle data to image data,construct an image only with this particle.------ const int nExpand_Size = 3; const int nWhiteColor = 0; const int nThickness = 1; // lineType Type of the line const int nLineType = 8; // get rectangle of the particle CRect rect = a_pOTSPart->GetParticleRect(); if (a_pOTSPart->GetActualArea() < 30 * a_PixelSize)// the particle is too small that openCV can't calculate a width value of it. Then we take the upright rect of the particle as it's minArea rect. { double w = 0, h = 0; w = (double)rect.Width()*a_PixelSize; h = (double)rect.Height()*a_PixelSize; a_pOTSPart->SetDMax(MAX(w, h)); a_pOTSPart->SetDMin(MIN(w, h)); a_pOTSPart->SetDMean((w + h) / 2); a_pOTSPart->SetFeretDiameter((w + h) / 2); a_pOTSPart->SetDElong(MAX(w, h)); a_pOTSPart->SetPerimeter((w+h)*2); a_pOTSPart->SetDPerp(MIN(w, h)); a_pOTSPart->SetDInscr(MIN(w, h)); return true; } // calculate the particle image data size, expand 3 pixel at the edge Mat particleImage = Mat::zeros(rect.Height() + nExpand_Size , rect.Width() + nExpand_Size , CV_8U); // get the segment list COTSSegmentsList listSegment = a_pOTSPart->GetFeature()->GetSegmentsList(); for (auto pSegment : listSegment) { int nStart = pSegment->GetStart() - rect.left + nExpand_Size; int nEnd = pSegment->GetStart() + pSegment->GetLength() - rect.left - 1 + nExpand_Size; int nHeight = pSegment->GetHeight() - rect.top + nExpand_Size; line(particleImage, Point(nStart, nHeight), Point(nEnd, nHeight), Scalar(nBlackColor), nThickness, nLineType); } //--------abstract the contour of the particle. Mat cvcopyImg; //medianBlur(particleImage, cvcopyImg, 5);//smooth the edge vector>contours; findContours(particleImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); if (contours.size()==0)// the particle is too odd that openCV can't find a contour of it. Then we take the upright rect of the particle as it's minArea rect. { double w = 0, h = 0; w = (double)rect.Width()*a_PixelSize; h = (double)rect.Height()*a_PixelSize; a_pOTSPart->SetDMax(MAX(w, h)); a_pOTSPart->SetDMin(MIN(w, h)); a_pOTSPart->SetDMean((w + h) / 2); a_pOTSPart->SetFeretDiameter((w + h) / 2); a_pOTSPart->SetDElong(MAX(w, h)); a_pOTSPart->SetPerimeter((w + h) * 2); a_pOTSPart->SetDPerp(MIN(w, h)); a_pOTSPart->SetDInscr(MIN(w, h)); return true; } int imaxcontour = 0, imax = 0; for (unsigned int i = 0; i < contours.size(); i++) { int itmp = contourArea(contours[i]); if (imaxcontour < itmp) { imax = i; imaxcontour = itmp; } } vector listEdge = contours[imax]; vector>Outcontours; Outcontours.push_back(listEdge); //---------calculate the minimium rectangle auto rRect = cv::minAreaRect(listEdge); Point2f p[4]; rRect.points(p); int D_MIN =getDistance(p[0], p[1]); int D_MinRecLen = 0;//minareaRect's length(the longger side). for (int j = 0; j <= 2; j++) { //line(cvContourImg, p[j], p[(j + 1) % 4], Scalar(100, 100, 0), 2); int d = getDistance(p[j], p[j + 1]); if (d < D_MIN) { D_MIN = d; } if (d > D_MinRecLen) { D_MinRecLen = d; } } a_pOTSPart->SetDMin(D_MIN*a_PixelSize); double angle; if (rRect.size.width> rRect.size.height) // w > h { angle = abs(rRect.angle); } else { angle = 90.0 + abs(rRect.angle); } a_pOTSPart->SetOrientation(angle); //----------calculate the perimeter double d = arcLength(listEdge, true); a_pOTSPart->SetPerimeter(d*a_PixelSize); //-----------calculate the Max Diameter. Find the min enclosing circle first ,then find the two farthest circle connected point. Point2f center; float radius; minEnclosingCircle(listEdge, center, radius); //circle(cvContourImg, center, radius, Scalar(100), 2); std::vector outContour = listEdge; std::vector rst; for (unsigned int k = 0; k < outContour.size(); k++) { Point p = outContour[k]; double d = sqrt(pow((p.x - center.x), 2) + pow((p.y - center.y), 2)); if (fabs(d - radius) < 0.01) { rst.push_back(p); } } double D_MAX = 0; Point lineDmax[2]; for (unsigned int m = 0; m < rst.size(); m++) { Point p = rst[m]; for (unsigned int n = m + 1; n < rst.size(); n++) { Point p1 = rst[n]; double d = sqrt(powf((p.x - p1.x), 2) + powf((p.y - p1.y), 2)); if (d > D_MAX) { D_MAX = d; lineDmax[0] = p; lineDmax[1] = p1; } } } a_pOTSPart->SetDMax(D_MAX*a_PixelSize); //--------calculate the D_PERP property using the D_MAX's two endpoints. std::vector curve1; std::vector curve2; for (unsigned int i = 0; i < outContour.size(); i++) { Point pt = outContour[i]; bool start = false; int clockwise = Side(lineDmax[0], lineDmax[1], pt);// devide these points into two group ,separate into the two sides. if (clockwise > 0) { curve1.push_back(pt); } else { curve2.push_back(pt); } } double d_perp1 = 0, d_perp2 = 0; for (unsigned int i = 0; i < curve1.size(); i++) { double d = getDist_P2L(curve1[i], lineDmax[0], lineDmax[1]); if (d > d_perp1) { d_perp1 = d; } } for (unsigned int i = 0; i < curve2.size(); i++) { double d = getDist_P2L(curve2[i], lineDmax[0], lineDmax[1]); if (d > d_perp2) { d_perp2 = d; } } a_pOTSPart->SetDPerp((d_perp1 + d_perp2)*a_PixelSize); //----------find the diameter of max inscribed circle int r; Point inscribeCirclecenter; FindInnerCircleInContour(outContour, inscribeCirclecenter, r); //--------------------------------------------------------calculate the xraypos ! CRect rec = a_pOTSPart->GetParticleRect(); a_pOTSPart->SetXRayPos(CPoint(inscribeCirclecenter.x - nExpand_Size + rec.left - 1, inscribeCirclecenter.y - nExpand_Size + rec.top - 1)); a_pOTSPart->SetDInscr(r * 2 * a_PixelSize); //---------------calculate the image other caracater: length/width realArea/minRectangeArea etc. we can use these propertes to do forward process. double minRectArea = D_MIN * D_MinRecLen*a_PixelSize*a_PixelSize;//最小外接矩形面积 double fillRatio = a_pOTSPart->GetActualArea() / minRectArea;//实际面积与最小外接矩形面积比,that's the fill rate. double lengthWidthRatio; lengthWidthRatio = (double)D_MinRecLen / D_MIN;//长宽比 //decide if this shape is a strip shape :if the lenthWidthRatio>2 then it is. if the lengthWidthRatio<2 and the areaRatio<0.5 then it is. bool isStripShape = false; double curveLength = 0; double D_MEAN=0; Moments mu; mu = moments(listEdge, false); int nx = mu.m10 / mu.m00; int ny = mu.m01 / mu.m00; //circle(cvcopyImg, Point(nx, ny), 1, (255), 1); Point ptCenter = Point((int)nx, (int)ny); if (pointPolygonTest(listEdge, ptCenter, false) != 1)// the center point doesn't contain in the contour, we think it as curve shape. { isStripShape = true; } /*if (lengthWidthRatio >= 2 )// in PartA software this is true,but IncA because of the GB definition the everage feret diameter is always the mean value of all the chord. { isStripShape = true; }*/ if (fillRatio <= 0.4)// only when the fill rate is very low,we think it as a curve shape,then we choose the mean width as the feret diameter. { isStripShape = true; } if (isStripShape) { curveLength = a_pOTSPart->GetPerimeter()/2 - a_pOTSPart->GetDInscr()/2;// thinking this particle as a strip rectangle.the width is the max inscribe circle diameter/2. if (curveLength < D_MAX) { curveLength = D_MAX; } if (curveLength < MIN_DOUBLE_VALUE || a_pOTSPart->GetActualArea()GetActualArea() / curveLength; } a_pOTSPart->SetDMean(D_MEAN*a_PixelSize); a_pOTSPart->SetFeretDiameter(D_MEAN*a_PixelSize); a_pOTSPart->SetDElong (curveLength*a_PixelSize); } else//it's a ball shape particle { curveLength = D_MAX; double ftd = 0, maxD = 0, minD = 0, dratio = 0; GetParticleAverageChord(outContour, a_PixelSize, ftd); a_pOTSPart->SetDMean(ftd); a_pOTSPart->SetFeretDiameter(ftd); a_pOTSPart->SetDElong(curveLength*a_PixelSize); } return true; } BOOL COTSImageProcess::SplitRawParticleIntoMatricsParticle(COTSParticlePtr a_pOTSPart,int imageWidth,int imageHeight, double a_PixelSize, double a_XrayStep) { //--------- convert this particle data to image data,construct an image only with this particle.------ const int nExpand_Size = 3; const int nWhiteColor = 0; const int nThickness = 1; // lineType Type of the line const int nLineType = 8; // get rectangle of the particle CRect rect = a_pOTSPart->GetParticleRect(); if (a_pOTSPart->GetActualArea() < 30 * a_PixelSize)// the particle is too small that openCV can't calculate a width value of it. Then we take the upright rect of the particle as it's minArea rect. { double w = 0, h = 0; w = (double)rect.Width() * a_PixelSize; h = (double)rect.Height() * a_PixelSize; a_pOTSPart->SetDMax(MAX(w, h)); a_pOTSPart->SetDMin(MIN(w, h)); a_pOTSPart->SetDMean((w + h) / 2); a_pOTSPart->SetFeretDiameter((w + h) / 2); a_pOTSPart->SetDElong(MAX(w, h)); a_pOTSPart->SetPerimeter((w + h) * 2); a_pOTSPart->SetDPerp(MIN(w, h)); a_pOTSPart->SetDInscr(MIN(w, h)); return true; } if (a_XrayStep > 0) { COTSParticleList matricsParts; int xrayStep = a_XrayStep;// *a_PixelSize; GetMatricsParticlesFromRawParticle(a_pOTSPart, imageWidth,imageHeight,a_PixelSize, xrayStep, matricsParts); a_pOTSPart->SetSubParticles(matricsParts); } //----------- } BOOL COTSImageProcess::SplitRawParticleIntoGreyScaleParticle(COTSParticlePtr a_pOTSPart,CDoubleRangePtr ecdRange, double a_PixelSize ,CBSEImgPtr fieldImg) { //--------- convert this particle data to image data,construct an image only with this particle.------ const int nExpand_Size = 3; const int nWhiteColor = 0; const int nThickness = 1; // lineType Type of the line const int nLineType = 8; // get rectangle of the particle CRect rect = a_pOTSPart->GetParticleRect(); if (a_pOTSPart->GetActualArea() < 5 * a_PixelSize)// the particle is too small that openCV can't calculate a width value of it. Then we take the upright rect of the particle as it's minArea rect. { double w = 0, h = 0; w = (double)rect.Width() * a_PixelSize; h = (double)rect.Height() * a_PixelSize; a_pOTSPart->SetDMax(MAX(w, h)); a_pOTSPart->SetDMin(MIN(w, h)); a_pOTSPart->SetDMean((w + h) / 2); a_pOTSPart->SetFeretDiameter((w + h) / 2); a_pOTSPart->SetDElong(MAX(w, h)); a_pOTSPart->SetPerimeter((w + h) * 2); a_pOTSPart->SetDPerp(MIN(w, h)); a_pOTSPart->SetDInscr(MIN(w, h)); return true; } // calculate the particle image data size, expand 3 pixel at the edge CBSEImgPtr onePartImg = CBSEImgPtr(new CBSEImg(CRect(0,0, fieldImg->GetWidth(), fieldImg->GetHeight()))); // get the segment list COTSSegmentsList listSegment = a_pOTSPart->GetFeature()->GetSegmentsList(); for (auto pSegment : listSegment) { for (int i = 0; i < pSegment->GetLength(); i++) { int x = pSegment->GetStart() + i; int y = pSegment->GetHeight(); int bseValue = fieldImg->GetBSEValue(x,y); onePartImg->SetBSEValue(x, y,bseValue); } } BlurImage(onePartImg); std::vector rngs = CalcuGrayLevelRange(onePartImg); COTSFieldDataPtr partData = COTSFieldDataPtr(new COTSFieldData()); std::map> partAreaMap; for (int i = 0; i < rngs.size(); i++) { partAreaMap.clear(); GetParticlesBySpecialGrayRange(onePartImg, rngs[i], ecdRange, a_PixelSize, partData); for (auto p : partData->GetParticleList())//sorting and filtering { /*if (p->GetActualArea() > 50) {*/ partAreaMap[p->GetPixelArea()].push_back(p); //} } if(partAreaMap.size()>0) { auto theBiggestPart = partAreaMap.rbegin()->second[0]; theBiggestPart->CalXRayPos(); std::map>::reverse_iterator it; auto partsegs = theBiggestPart->GetFeature()->GetSegmentsList(); it = partAreaMap.rbegin()++; for (; it != partAreaMap.rend(); it++) { for (auto sameAreaP : it->second) { auto segs = sameAreaP->GetFeature()->GetSegmentsList(); for (auto s : segs) { partsegs.push_back(s); } } } theBiggestPart->GetFeature()->SetSegmentsList(partsegs, true); theBiggestPart->CalCoverRect(); theBiggestPart->SetFieldId(a_pOTSPart->GetFieldId()); theBiggestPart->SetAnalysisId(a_pOTSPart->GetAnalysisId()); a_pOTSPart->AddSubParticle(theBiggestPart); } } return 0; } BOOL COTSImageProcess::SplitRawParticleIntoWaterShedParticle(COTSParticlePtr a_pOTSPart, double a_PixelSize, CBSEImgPtr fieldImg) { //--------- convert this particle data to image data,construct an image only with this particle.------ const int nExpand_Size = 3; const int nWhiteColor = 0; const int nThickness = 1; // lineType Type of the line const int nLineType = 8; // get rectangle of the particle CRect rect = a_pOTSPart->GetParticleRect(); if (a_pOTSPart->GetActualArea() < 5 * a_PixelSize)// the particle is too small that openCV can't calculate a width value of it. Then we take the upright rect of the particle as it's minArea rect. { double w = 0, h = 0; w = (double)rect.Width() * a_PixelSize; h = (double)rect.Height() * a_PixelSize; a_pOTSPart->SetDMax(MAX(w, h)); a_pOTSPart->SetDMin(MIN(w, h)); a_pOTSPart->SetDMean((w + h) / 2); a_pOTSPart->SetFeretDiameter((w + h) / 2); a_pOTSPart->SetDElong(MAX(w, h)); a_pOTSPart->SetPerimeter((w + h) * 2); a_pOTSPart->SetDPerp(MIN(w, h)); a_pOTSPart->SetDInscr(MIN(w, h)); return true; } // calculate the particle image data size, expand 3 pixel at the edge CBSEImgPtr onePartImg = CBSEImgPtr(new CBSEImg(CRect(0, 0, fieldImg->GetWidth(), fieldImg->GetHeight()))); CBSEImgPtr rawOnePartImg = CBSEImgPtr(new CBSEImg(CRect(0, 0, fieldImg->GetWidth(), fieldImg->GetHeight()))); // get the segment list /*for (int i = 0; i < fieldImg->GetWidth(); i++) { for (int j = 0; j < fieldImg->GetHeight(); j++) { rawOnePartImg->SetBSEValue(i, j, 255); } }*/ COTSSegmentsList listSegment = a_pOTSPart->GetFeature()->GetSegmentsList(); for (auto pSegment : listSegment) { for (int i = 0; i < pSegment->GetLength(); i++) { int x = pSegment->GetStart() + i; int y = pSegment->GetHeight(); int bseValue = fieldImg->GetBSEValue(x, y); onePartImg->SetBSEValue(x, y, bseValue); rawOnePartImg->SetBSEValue(x, y, bseValue); } } //ImshowImage(rawOnePartImg); //ImshowChartData(onePartImg); BlurImage(onePartImg); Mat partMat = GetMatDataFromBseImg(onePartImg); Canny(partMat, partMat, 10, 300,3); /* cv::imshow("ddd2", partMat); cv::waitKey();*/ //查找轮廓 vector> contours; vector hierarchy; findContours(partMat, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); //Mat imageContours = Mat::zeros(partMat.size(), CV_8UC1); //轮廓 Mat marks(partMat.size(), CV_32S); marks = Scalar::all(0); int index = 0; int compCount =10; for (; index >= 0; index = hierarchy[index][0], compCount++) { //对marks进行标记,对不同区域的轮廓进行编号,相当于设置注水点,有多少轮廓,就有多少注水点 //marks与imageContours差别就是在颜色的赋值上,marks是不同轮廓赋予不同的值,imageContours是轮廓赋值白色 //要绘制轮廓的图像; 所有输入的轮廓,每个轮廓被保存成一个point向量; index指定要绘制轮廓的编号,如果是负数,则绘制所有的轮廓; //绘制轮廓所用的颜色; 绘制轮廓的线的粗细,如果是负数,则轮廓内部被填充; //绘制轮廓的线的连通性; 关于层级的可选参数,只有绘制部分轮廓时才会用到 drawContours(marks, contours, index, Scalar::all(compCount+1 ), 1, 8, hierarchy); //drawContours(imageContours, contours, index, Scalar(255), 1, 8, hierarchy); } /*cv::imshow("ddd", marks); cv::waitKey();*/ auto rawData = GetMatDataFromBseImg(rawOnePartImg); /*cv::imshow("ddd3", rawData); cv::waitKey();*/ Mat imageGray3; cvtColor(rawData, imageGray3, CV_GRAY2RGB);//灰度转换 watershed(imageGray3, marks); //分水岭算法实现 /*cv::imshow("ddd", marks); cv::waitKey();*/ Mat PerspectiveImage = Mat::zeros(imageGray3.size(), CV_8UC1); for (int i = 0; i < marks.rows; i++) //maks是区域图 { for (int j = 0; j < marks.cols; j++) { int index = marks.at(i, j); if (marks.at(i, j) == -1) { PerspectiveImage.at(i, j) = 0; } else { PerspectiveImage.at(i, j) = index; } } } onePartImg->SetImageData(PerspectiveImage.data,marks.cols,marks.rows); std::vector rngs; for (int i = 10; i< compCount; i++) { rngs.push_back(CIntRangePtr(new CIntRange(i, i))); } CDoubleRangePtr ecdRange = CDoubleRangePtr(new CDoubleRange(0, 1000)); COTSFieldDataPtr partData = COTSFieldDataPtr(new COTSFieldData()); std::map> partAreaMap; for (int i = 0; i < rngs.size(); i++) { partAreaMap.clear(); GetParticlesBySpecialGrayRange(onePartImg, rngs[i], ecdRange, a_PixelSize, partData); for (auto p : partData->GetParticleList())//sorting and filtering { auto r1=a_pOTSPart->GetParticleRect(); auto pnt = p->GetParticleRect().CenterPoint(); if (pnt.x > r1.left && pnt.xr1.top && pnt.y < r1.top + r1.Height()) { partAreaMap[p->GetPixelArea()].push_back(p); } /*if (p->GetActualArea() > 50) {*/ //partAreaMap[p->GetPixelArea()].push_back(p); //} } if (partAreaMap.size() > 0) { auto theBiggestPart = partAreaMap.rbegin()->second[0]; theBiggestPart->CalXRayPos(); std::map>::reverse_iterator it; auto partsegs = theBiggestPart->GetFeature()->GetSegmentsList(); it = partAreaMap.rbegin()++; for (; it != partAreaMap.rend(); it++) { for (auto sameAreaP : it->second) { auto segs = sameAreaP->GetFeature()->GetSegmentsList(); for (auto s : segs) { partsegs.push_back(s); } } } theBiggestPart->GetFeature()->SetSegmentsList(partsegs, true); theBiggestPart->CalCoverRect(); theBiggestPart->SetFieldId(a_pOTSPart->GetFieldId()); theBiggestPart->SetAnalysisId(a_pOTSPart->GetAnalysisId()); a_pOTSPart->AddSubParticle(theBiggestPart); } } return 0; } void COTSImageProcess::ImshowImage(CBSEImgPtr img) { BYTE* data = img->GetImageDataPointer(); //Mat cvImg; cv::Size s; s.width = img->GetImageSize().cx; s.height = img->GetImageSize().cy; Mat cvImg=Mat::zeros(s, CV_8U); cvImg.data = data; cv::imshow("dd", cvImg); cv::waitKey(); } void COTSImageProcess::ImshowChartData(CBSEImgPtr img) { img->SetChartData(); WORD* data = img->GetBSEChart(); //Mat cvImg; cv::Size s; s.width = 255; s.height = 100; Mat cvImg = Mat::zeros(s, CV_8U); //cvImg.data = data; WORD nBSEChart[MAXBYTE]; //1. get chart data linearSmooth5(data, nBSEChart, MAXBYTE); for (int i=1;i<255;i++) { line(cvImg, Point(i, 100-nBSEChart[i]), Point(i+1, 100-nBSEChart[i+1]), Scalar(nBlackColor), 1, 8); } cv::imshow("chart", cvImg); cv::waitKey(); } BOOL COTSImageProcess::MergeBigBoundaryParticles(COTSFieldDataList allFields,double pixelSize,int scanFieldSize, CSize ResolutionSize, COTSParticleList& mergedParts) { class BorderPart { typedef std::shared_ptr CBorderPartPtr; BorderPart(COTSParticlePtr p) { myPart = p; headerParticle = NULL; } public: COTSParticlePtr myPart; COTSParticle* headerParticle;//used to merge particles ,if this particle has been merged then this pointer will point to the first particle of these merged particles or else it's NULL. static std::vector ConvertPartToBorderPart(COTSParticleList parts) { std::vector borderParts; for (auto p : parts) { borderParts.push_back(CBorderPartPtr(new BorderPart(p))); } return borderParts; } }; auto FldMgr = new CFieldMgr(scanFieldSize, ResolutionSize); std::map mapMergeParticles;//hold up all the boundary connected particles. the pair's first is also the member of these particles. std::map mapMergedSegments;//hold up all the segment's corresponding clone in the connected particles. for (auto centerfld : allFields) { // find neighbor field on the left. auto leftFld = FldMgr->FindNeighborField(allFields, centerfld, SORTING_DIRECTION::LEFT); if (leftFld != nullptr) { auto lParts = centerfld->GetLeftBorderedBigParticles(); auto rParts = leftFld->GetRightBorderedBigParticles(); auto leftParts = BorderPart::ConvertPartToBorderPart(lParts); auto rightParts = BorderPart::ConvertPartToBorderPart(rParts); for (auto leftp : leftParts) { for (auto rightp : rightParts) { if (leftp->myPart->IsConnected(rightp->myPart.get(), centerfld->Width, centerfld->Height, (int)SORTING_DIRECTION::LEFT)) { if (leftp->headerParticle != NULL) { if (rightp->headerParticle == NULL) { rightp->headerParticle = leftp->headerParticle; mapMergeParticles[leftp->headerParticle].push_back(rightp->myPart); } } else { if (rightp->headerParticle != NULL) { leftp->headerParticle = rightp->myPart.get(); mapMergeParticles[rightp->myPart.get()].push_back(leftp->myPart); } else { leftp->headerParticle = leftp->myPart.get(); rightp->headerParticle = leftp->myPart.get(); mapMergeParticles[leftp->myPart.get()].push_back(rightp->myPart); } } } } } } //find neighbor field on the upward auto upFld = FldMgr->FindNeighborField(allFields, centerfld, SORTING_DIRECTION::UP); if (upFld != nullptr) { auto topBorderParts = centerfld->GetTopBorderedBigParticles(); auto bottomBorderParts = upFld->GetBottomBorderedBigParticles(); auto upParts = BorderPart::ConvertPartToBorderPart(topBorderParts); auto downParts = BorderPart::ConvertPartToBorderPart(bottomBorderParts); for (auto upprt : upParts) { for (auto downprt : downParts) { if (upprt->myPart->IsConnected(downprt->myPart.get(), centerfld->Width, centerfld->Height, (int)SORTING_DIRECTION::UP)) { if (upprt->headerParticle != NULL) { if (downprt->headerParticle == NULL) { downprt->headerParticle = upprt->headerParticle; mapMergeParticles[upprt->headerParticle].push_back(downprt->myPart); } } else { if (downprt->headerParticle != NULL) { upprt->headerParticle = downprt->headerParticle; mapMergeParticles[downprt->myPart.get()].push_back(upprt->myPart); } else { upprt->headerParticle = upprt->myPart.get(); downprt->headerParticle = upprt->myPart.get(); mapMergeParticles[upprt->myPart.get()].push_back(downprt->myPart); } } } } } } //find neighbor field on the downward. auto downFld = FldMgr->FindNeighborField(allFields, centerfld,SORTING_DIRECTION::DOWN); if (downFld != nullptr) { auto bottomParts = centerfld->GetBottomBorderedBigParticles(); auto topParts = downFld->GetTopBorderedBigParticles(); auto downParts = BorderPart::ConvertPartToBorderPart(bottomParts); auto upParts= BorderPart::ConvertPartToBorderPart(topParts); for (auto downprt : downParts) { for (auto upprt : upParts) { if (downprt->myPart->IsConnected(upprt->myPart.get(), centerfld->Width, centerfld->Height, (int)SORTING_DIRECTION::DOWN)) { if (downprt->headerParticle != NULL) { if (upprt->headerParticle == NULL) { upprt->headerParticle = downprt->headerParticle; mapMergeParticles[downprt->headerParticle].push_back(upprt->myPart); } } else { if (upprt->headerParticle != NULL) { downprt->headerParticle = upprt->headerParticle; mapMergeParticles[upprt->headerParticle].push_back(downprt->myPart); } else { downprt->headerParticle = downprt->myPart.get(); upprt->headerParticle = downprt->myPart.get(); mapMergeParticles[downprt->myPart.get()].push_back(upprt->myPart); } } } } } } //find neighbor field on the right. auto rightFld = FldMgr->FindNeighborField(allFields, centerfld, SORTING_DIRECTION::RIGHT); if (rightFld != nullptr) { auto rParts = centerfld->GetRightBorderedBigParticles(); auto lParts = rightFld->GetLeftBorderedBigParticles(); auto rightParts = BorderPart::ConvertPartToBorderPart(rParts); auto leftParts = BorderPart::ConvertPartToBorderPart(lParts); for (auto rightprt : rightParts) { for (auto leftprt : leftParts) { if (rightprt->myPart->IsConnected(leftprt->myPart.get(), centerfld->Width, centerfld->Height, (int)SORTING_DIRECTION::RIGHT)) { if (rightprt->headerParticle != NULL) { if (leftprt->headerParticle == NULL) { leftprt->headerParticle = rightprt->headerParticle; mapMergeParticles[rightprt->headerParticle].push_back(leftprt->myPart); } } else { if (leftprt->headerParticle != NULL) { rightprt->headerParticle = leftprt->headerParticle; mapMergeParticles[leftprt->headerParticle].push_back(rightprt->myPart); } else { rightprt->headerParticle = rightprt->myPart.get(); leftprt->headerParticle = rightprt->myPart.get(); mapMergeParticles[rightprt->myPart.get()].push_back(leftprt->myPart); } } } } } } } static int partTagId; for (auto pair : mapMergeParticles) { struct EleAreaPercentage { EleAreaPercentage(double p, CElementChemistryPtr e) { areaPercentage = p; eleData = e; } double areaPercentage; CElementChemistryPtr eleData; }; auto newPart = COTSParticlePtr(new COTSParticle()); COTSSegmentsList newSegs; auto p = pair.first; newPart->SetAbsolutePos(p->GetAbsolutPos()); //firstly,we sum up all the merged particles's area and get the represent string. std::string partsStr = std::to_string(p->GetFieldId()) + ":" + std::to_string(p->GetAnalysisId()); double allPartArea = p->GetActualArea();//Get the first particle's area. for (auto other : pair.second)// Get the total area of all these particles for the use of ele calcu. { partsStr += "," + std::to_string(other->GetFieldId()) + ":" + std::to_string(other->GetAnalysisId());//Get the subparticles string such as "1:1,2:1" etc. allPartArea += other->GetActualArea();//Get other particle's area } // calculate all the new segment's position. std::vector allSubParts; allSubParts.push_back(p); for (auto other : pair.second)// Get the total area of all these particles for the use of ele calcu. { allSubParts.push_back(other.get()); } for (auto subp : allSubParts) { int fid = subp->GetFieldId(); CPoint myFldPos; for (auto f : allFields)//find this particle's filed. { if (f->GetId() == fid) { myFldPos = f->GetPosition(); } } int fldWidth = allFields[0]->Width; int fldHeight = allFields[0]->Height; CPoint fldLeftUpPos = CPoint(myFldPos.x + fldWidth / 2 , myFldPos.y + fldHeight / 2 ); for (auto s : subp->GetFeature()->GetSegmentsList()) { COTSSegmentPtr newseg = COTSSegmentPtr(new COTSSegment()); newseg->SetStart(s->GetStart() + fldLeftUpPos.x); newseg->SetHeight((0 - s->GetHeight()) + fldLeftUpPos.y);//the coordinate system of segment in a field is different with the OTS coordinate system.OTS system's y axis is upward positive ,yet the field is downward positive. newseg->SetLength(s->GetLength()); newSegs.push_back(newseg); } } COTSFeaturePtr newFeature = COTSFeaturePtr(new COTSFeature()); newFeature->SetSegmentsList(newSegs); newPart->SetFeature(newFeature); newPart->CalCoverRect(); //second, we get all the element data and their area percentage . std::map> mapEleData; CPosXrayPtr pXray1 = p->GetXrayInfo(); if (pXray1 != nullptr) { for (auto ele : pXray1->GetElementQuantifyData()) { mapEleData[ele->GetName().GetBuffer()].push_back(EleAreaPercentage(p->GetActualArea() / allPartArea, ele)); } } for (auto other : pair.second) { auto otherXray = other->GetXrayInfo(); if (otherXray != nullptr) { for (auto eledata : otherXray->GetElementQuantifyData()) { mapEleData[eledata->GetName().GetBuffer()].push_back(EleAreaPercentage(other->GetActualArea() / allPartArea, eledata)); } } } // third,we calculate all the element's new percentage data and get a new element chemistry list. CElementChemistriesList newCheList; for (auto eledata : mapEleData) { CElementChemistryPtr newEleche = CElementChemistryPtr(new CElementChemistry()); newEleche->SetName(CString(eledata.first.c_str())); double newPercentage = 0; for (auto d : eledata.second) { newPercentage += d.areaPercentage * d.eleData->GetPercentage(); } newEleche->SetPercentage(newPercentage); newCheList.push_back(newEleche); } CPosXrayPtr xray(new CPosXray()); xray->SetElementQuantifyData(newCheList); newPart->SetXrayInfo(xray); newPart->SetConnectedParticlesSequentialString(partsStr); newPart->SetActualArea(allPartArea); partTagId++; newPart->SetParticleId(partTagId); newPart->SetAnalysisId(partTagId); std::string name = p->TypeName(); newPart->TypeName(name); newPart->TypeColor(p->TypeColor()); mergedParts.push_back(newPart); } return true; } }