|
|
@@ -10,6 +10,7 @@
|
|
|
#include "../OTSLog/COTSUtilityDllFunExport.h"
|
|
|
#include "FieldMgr.h"
|
|
|
#include "BaseFunction.h"
|
|
|
+#include "GreyPeak.h"
|
|
|
|
|
|
|
|
|
namespace OTSIMGPROC
|
|
|
@@ -18,6 +19,45 @@ namespace OTSIMGPROC
|
|
|
using namespace std;
|
|
|
|
|
|
const int nBlackColor = 255;
|
|
|
+ namespace
|
|
|
+ {
|
|
|
+
|
|
|
+ cv::Mat GetMatDataFromParticles(COTSParticleList parts, int width, int height)
|
|
|
+ {
|
|
|
+ int rows, cols;
|
|
|
+ cols = width;
|
|
|
+ rows = height;
|
|
|
+ BYTE* pPixel = new BYTE[width * height];
|
|
|
+ Mat cvcopyImg = Mat(rows, cols, CV_8UC1, pPixel);
|
|
|
+ cvcopyImg = Scalar::all(0);
|
|
|
+ for (auto p : parts)
|
|
|
+ {
|
|
|
+ auto area = p->GetPixelArea();
|
|
|
+ if (area > 100)
|
|
|
+ {
|
|
|
+ auto fea = p->GetFeature();
|
|
|
+ auto segs = fea->GetSegmentsList();
|
|
|
+ for (auto seg : segs)
|
|
|
+ {
|
|
|
+ auto row = seg->GetHeight();
|
|
|
+ for (int i = 0; i < seg->GetLength(); i++)
|
|
|
+ {
|
|
|
+ auto col = seg->GetStart() + i;
|
|
|
+ cvcopyImg.at<char>(row, col) = 255;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ return cvcopyImg;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
|
@@ -57,7 +97,7 @@ namespace OTSIMGPROC
|
|
|
CRect r = CRect(0, 0, nWidthImg, nHeightImg);
|
|
|
CBSEImgPtr imgNoBGBinary = CBSEImgPtr(new CBSEImg(r));
|
|
|
|
|
|
- RemoveBackGround(inBSEImg, m_imageProcessParam, imgNoBGBinary/*, nNumParticle*/);
|
|
|
+ BinaryProcess(inBSEImg, m_imageProcessParam, imgNoBGBinary/*, nNumParticle*/);
|
|
|
|
|
|
|
|
|
|
|
|
@@ -240,7 +280,7 @@ namespace OTSIMGPROC
|
|
|
|
|
|
long nNumParticle = 0;
|
|
|
|
|
|
- GetSpecialGrayRangeImage(a_pBSEImg, a_grayRange, imgNoBGBinary, nNumParticle);
|
|
|
+ GetSpecialGrayRangeImage(a_pBSEImg, *a_grayRange, imgNoBGBinary, nNumParticle);
|
|
|
|
|
|
|
|
|
|
|
|
@@ -490,6 +530,185 @@ namespace OTSIMGPROC
|
|
|
//-----------
|
|
|
}
|
|
|
|
|
|
+ BOOL COTSImageProcess::SplitRawImageIntoParticlesByWaterShed(CBSEImgPtr fieldImg, double a_PixelSize, COTSFieldDataPtr outFldData)
|
|
|
+ {
|
|
|
+ int nWidthImg = fieldImg->GetWidth();
|
|
|
+ int nHeightImg = fieldImg->GetHeight();
|
|
|
+ outFldData->Width = nWidthImg;
|
|
|
+ outFldData->Height = nHeightImg;
|
|
|
+
|
|
|
+ CRect r = CRect(0, 0, nWidthImg, nHeightImg);
|
|
|
+ CBSEImgPtr imgNoBGBinary = CBSEImgPtr(new CBSEImg(r));
|
|
|
+
|
|
|
+ COTSParticleList listMainParticle;
|
|
|
+ BinaryProcess(fieldImg, m_imageProcessParam, imgNoBGBinary);
|
|
|
+
|
|
|
+
|
|
|
+ CDoubleRange areaRng = m_imageProcessParam->GetIncArea();
|
|
|
+ GetParticlesFromBinaryImage(imgNoBGBinary, areaRng, a_PixelSize, listMainParticle);
|
|
|
+
|
|
|
+ outFldData->SetParticleList(listMainParticle);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ CBSEImgPtr noBgImg = CBSEImgPtr(new CBSEImg(fieldImg->GetImageRect()));
|
|
|
+ RemoveBackGround(fieldImg, noBgImg);
|
|
|
+
|
|
|
+ BlurImage(noBgImg);
|
|
|
+
|
|
|
+ std::vector<CPoint> seeds;
|
|
|
+ seeds.clear();
|
|
|
+ FindSeedsByGrayScale(noBgImg, a_PixelSize, seeds);
|
|
|
+
|
|
|
+ Mat matImg = GetMatDataFromBseImg(noBgImg);
|
|
|
+
|
|
|
+ Mat marks(matImg.size(), CV_32S);
|
|
|
+
|
|
|
+ marks = Scalar::all(0);
|
|
|
+
|
|
|
+ for (int index = 0; index < seeds.size(); index++)
|
|
|
+ {
|
|
|
+
|
|
|
+ auto p = seeds[index];
|
|
|
+
|
|
|
+ marks.at<INT32>(p.y, p.x) = index + 10;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ Mat imageGray3;
|
|
|
+
|
|
|
+
|
|
|
+ cv::cvtColor(matImg, imageGray3, cv::COLOR_GRAY2RGB);//灰度转换 opencv4
|
|
|
+ cv::watershed(imageGray3, marks);
|
|
|
+
|
|
|
+
|
|
|
+ auto matBinNobg = GetMatDataFromParticles(listMainParticle, nWidthImg, nHeightImg);
|
|
|
+
|
|
|
+ //the first "long" is the index of particle,the second "long" is the row number of the segment, the third "long" is the sequence of the pixel.
|
|
|
+ std::map<long, std::map<long, std::set<long>>> pixelMap;
|
|
|
+
|
|
|
+ for (int i = 0; i < marks.rows; i++)
|
|
|
+ {
|
|
|
+ for (int j = 0; j < marks.cols; j++)
|
|
|
+ {
|
|
|
+ if (matBinNobg.at<char>(i, j) == 0)
|
|
|
+ {
|
|
|
+ marks.at<int>(i, j) = 0;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ long index = marks.at<int>(i, j);
|
|
|
+
|
|
|
+ if (index == -1)//if this pixel is on the border,then it will be absorbed by it's neighbor.
|
|
|
+ {
|
|
|
+ if (i + 1 < marks.rows && marks.at<int>(i + 1, j) != -1 && matBinNobg.at<char>(i + 1, j) != 0)
|
|
|
+ {
|
|
|
+ index = marks.at<int>(i + 1, j);
|
|
|
+ }
|
|
|
+ else if (j + 1 < marks.cols && marks.at<int>(i, j + 1) != -1 && matBinNobg.at<char>(i, j + 1) != 0)
|
|
|
+ {
|
|
|
+ index = marks.at<int>(i, j + 1);
|
|
|
+ }
|
|
|
+ else if (i > 0 && marks.at<int>(i - 1, j) != -1 && matBinNobg.at<char>(i - 1, j) != 0)
|
|
|
+ {
|
|
|
+ index = marks.at<int>(i - 1, j);
|
|
|
+ }
|
|
|
+ else if (j > 0 && marks.at<int>(i, j - 1) != -1 && matBinNobg.at<char>(i, j - 1) != 0)
|
|
|
+ {
|
|
|
+ index = marks.at<int>(i, j - 1);
|
|
|
+ }
|
|
|
+ marks.at<int>(i, j) = index;
|
|
|
+ }
|
|
|
+
|
|
|
+ pixelMap[index][i].insert(j);
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ COTSParticleList listParticleOut;
|
|
|
+ for (auto it = pixelMap.begin(); it != pixelMap.end(); it++)
|
|
|
+ {
|
|
|
+ if (it->first == -1) continue;
|
|
|
+ if (it->first == 0) continue;
|
|
|
+ auto pixelsegs = it->second;
|
|
|
+ COTSParticlePtr newGrain = COTSParticlePtr(new COTSParticle());
|
|
|
+ COTSFeaturePtr newFea = COTSFeaturePtr(new COTSFeature());
|
|
|
+ for (auto pixelseg : pixelsegs)
|
|
|
+ {
|
|
|
+ auto start = (*pixelseg.second.begin());
|
|
|
+ for (auto pix = pixelseg.second.begin(); pix != pixelseg.second.end(); pix++)
|
|
|
+ {
|
|
|
+ auto curNode = pix;
|
|
|
+ ++curNode;
|
|
|
+ if ((curNode) != pixelseg.second.end())
|
|
|
+ {
|
|
|
+ if (*curNode - *pix > 1)
|
|
|
+ {
|
|
|
+ COTSSegmentPtr seg = COTSSegmentPtr(new COTSSegment());
|
|
|
+
|
|
|
+ seg->SetStart(start);
|
|
|
+ seg->SetEnd(*pix);
|
|
|
+ seg->SetHeight(pixelseg.first);
|
|
|
+ newFea->AddSegment(seg);
|
|
|
+
|
|
|
+ start = *curNode;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ COTSSegmentPtr seg = COTSSegmentPtr(new COTSSegment());
|
|
|
+
|
|
|
+ seg->SetStart(start);
|
|
|
+ seg->SetEnd(*pix);
|
|
|
+ seg->SetHeight(pixelseg.first);
|
|
|
+ newFea->AddSegment(seg);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ newGrain->SetFeature(newFea);
|
|
|
+
|
|
|
+
|
|
|
+ newGrain->CalXRayPos();
|
|
|
+
|
|
|
+ CPoint pos = newGrain->GetXRayPos();
|
|
|
+
|
|
|
+ for (auto mp : listMainParticle)
|
|
|
+ {
|
|
|
+
|
|
|
+ auto fieldOTSRect = outFldData->GetOTSRect();
|
|
|
+ CPoint leftTop = fieldOTSRect.GetTopLeft();
|
|
|
+
|
|
|
+ CRect rectInSinglefld = mp->GetParticleRect();
|
|
|
+ CPoint OTSLeftTop = CPoint(leftTop.x + rectInSinglefld.left * a_PixelSize, leftTop.y - rectInSinglefld.top * a_PixelSize);
|
|
|
+ CPoint OTSRightBottom = CPoint(leftTop.x + rectInSinglefld.right * a_PixelSize, leftTop.y - rectInSinglefld.bottom * a_PixelSize);
|
|
|
+
|
|
|
+ COTSRect recInOTSCord = COTSRect(OTSLeftTop, OTSRightBottom);
|
|
|
+ mp->SetOTSRect(recInOTSCord);
|
|
|
+ mp->SetFieldId(outFldData->GetId());
|
|
|
+ if (mp->IfContain(pos))
|
|
|
+ {
|
|
|
+ CRect rectInSinglefld = newGrain->GetParticleRect();
|
|
|
+ CPoint OTSLeftTop = CPoint(leftTop.x + rectInSinglefld.left * a_PixelSize, leftTop.y - rectInSinglefld.top * a_PixelSize);
|
|
|
+ CPoint OTSRightBottom = CPoint(leftTop.x + rectInSinglefld.right * a_PixelSize, leftTop.y - rectInSinglefld.bottom * a_PixelSize);
|
|
|
+
|
|
|
+ COTSRect recInOTSCord = COTSRect(OTSLeftTop, OTSRightBottom);
|
|
|
+ newGrain->SetFieldId(mp->GetFieldId());
|
|
|
+ newGrain->SetOTSRect(recInOTSCord);
|
|
|
+ mp->AddSubParticle(newGrain);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
CIntRangePtr COTSImageProcess::CalBackground(CBSEImgPtr m_pBSEImg)
|
|
|
{
|
|
|
auto ranges = CalcuGrayLevelRange(m_pBSEImg);
|
|
|
@@ -600,7 +819,7 @@ namespace OTSIMGPROC
|
|
|
return ranges;
|
|
|
|
|
|
}
|
|
|
- void COTSImageProcess::GetSpecialGrayRangeImage(CBSEImgPtr a_pImgIn, CIntRangePtr a_SpecialGrayRange, CBSEImgPtr a_pBinImgOut, long& foundedPixelNum)
|
|
|
+ void COTSImageProcess::GetSpecialGrayRangeImage(CBSEImgPtr a_pImgIn, CIntRange a_SpecialGrayRange, CBSEImgPtr a_pBinImgOut, long& foundedPixelNum)
|
|
|
{
|
|
|
// the background pixel will be 0,and the other part will be 255.
|
|
|
ASSERT(a_pImgIn);
|
|
|
@@ -626,8 +845,8 @@ namespace OTSIMGPROC
|
|
|
|
|
|
long nNumParticle = 0;
|
|
|
|
|
|
- nBGStart = a_SpecialGrayRange->GetStart();
|
|
|
- nBGEnd = a_SpecialGrayRange->GetEnd();
|
|
|
+ nBGStart = a_SpecialGrayRange.GetStart();
|
|
|
+ nBGEnd = a_SpecialGrayRange.GetEnd();
|
|
|
|
|
|
|
|
|
// delete background
|
|
|
@@ -658,7 +877,7 @@ namespace OTSIMGPROC
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
- void COTSImageProcess::RemoveBackGround(CBSEImgPtr a_pImgIn, COTSImageProcessParamPtr a_pImageProcessParam, CBSEImgPtr a_pBinImgOut/*,long& foundedPixelNum*/)
|
|
|
+ void COTSImageProcess::BinaryProcess(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);
|
|
|
@@ -685,7 +904,7 @@ namespace OTSIMGPROC
|
|
|
long nPartStart;
|
|
|
long nPartEnd;
|
|
|
long nNumParticle = 0;
|
|
|
- if (a_pImageProcessParam->GetBGRemoveType() == OTS_BGREMOVE_TYPE::MANUAL)
|
|
|
+ if (a_pImageProcessParam->GetBGRemoveType() == OTS_BGREMOVE_TYPE::MANUAL || a_pImageProcessParam->GetBGRemoveType() == OTS_BGREMOVE_TYPE::WaterShed)
|
|
|
{
|
|
|
nBGStart = a_pImageProcessParam->GetBGGray().GetStart();
|
|
|
nBGEnd = a_pImageProcessParam->GetBGGray().GetEnd();
|
|
|
@@ -706,11 +925,7 @@ namespace OTSIMGPROC
|
|
|
else
|
|
|
{
|
|
|
|
|
|
- /*auto range = CalBackground(a_pImgIn);
|
|
|
- nBGStart = range->GetStart();
|
|
|
-
|
|
|
- nBGEnd = range->GetEnd();*/
|
|
|
-
|
|
|
+
|
|
|
|
|
|
switch (a_pImageProcessParam->GetAutoBGRemoveType())
|
|
|
{
|
|
|
@@ -741,12 +956,78 @@ namespace OTSIMGPROC
|
|
|
}
|
|
|
a_pBinImgOut->SetImageData(pPixel,nWidthImg,nHeightImg);
|
|
|
|
|
|
- //foundedPixelNum = nNumParticle;
|
|
|
- //foundedPixelNum = 100;
|
|
|
+
|
|
|
|
|
|
|
|
|
return ;
|
|
|
}
|
|
|
+ void COTSImageProcess::RemoveBackGround(CBSEImgPtr a_pImgIn, CBSEImgPtr a_pBinImgOut)
|
|
|
+ {
|
|
|
+ // the background pixel will be 0,and the other part will be 255.
|
|
|
+ ASSERT(a_pImgIn);
|
|
|
+
|
|
|
+
|
|
|
+ ASSERT(m_imageProcessParam);
|
|
|
+ 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 (m_imageProcessParam->GetBGRemoveType() == OTS_BGREMOVE_TYPE::MANUAL|| m_imageProcessParam->GetBGRemoveType() == OTS_BGREMOVE_TYPE::WaterShed)
|
|
|
+ {
|
|
|
+ nBGStart = m_imageProcessParam->GetBGGray().GetStart();
|
|
|
+ nBGEnd = m_imageProcessParam->GetBGGray().GetEnd();
|
|
|
+ nPartStart = m_imageProcessParam->GetParticleGray().GetStart();
|
|
|
+ nPartEnd = m_imageProcessParam->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] = pSrcImg[i];
|
|
|
+ nNumParticle++;
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ if (pSrcImg[i]<nPartStart || pSrcImg[i]>nPartEnd)
|
|
|
+ {
|
|
|
+ pPixel[i] = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ a_pBinImgOut->SetImageData(pPixel, nWidthImg, nHeightImg);
|
|
|
+
|
|
|
+
|
|
|
+ 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);
|
|
|
@@ -1026,6 +1307,344 @@ namespace OTSIMGPROC
|
|
|
|
|
|
return TRUE;
|
|
|
}
|
|
|
+
|
|
|
+ BOOL COTSImageProcess::GetParticlesFromBinaryImage(CBSEImgPtr m_pBSEImg, CDoubleRange a_diameterRange, double a_pixelSize, COTSParticleList& listParticleOut)
|
|
|
+ {
|
|
|
+ int height, width;
|
|
|
+ height = m_pBSEImg->GetHeight();
|
|
|
+ width = m_pBSEImg->GetWidth();
|
|
|
+
|
|
|
+ BYTE* pPixel = m_pBSEImg->GetImageDataPointer();
|
|
|
+ Mat nobgMat = Mat(height, width, CV_8UC1, pPixel);
|
|
|
+
|
|
|
+
|
|
|
+ Mat labels = Mat::zeros(nobgMat.size(), CV_32S);
|
|
|
+ Mat stats, centroids;
|
|
|
+ int number = connectedComponentsWithStats(nobgMat, 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<double>(i, 0);
|
|
|
+ int center_y = centroids.at<double>(i, 1);
|
|
|
+ //矩形边框
|
|
|
+ int x = stats.at<int>(i, CC_STAT_LEFT);
|
|
|
+ int y = stats.at<int>(i, CC_STAT_TOP);
|
|
|
+ int w = stats.at<int>(i, CC_STAT_WIDTH);
|
|
|
+ int h = stats.at<int>(i, CC_STAT_HEIGHT);
|
|
|
+ int area = stats.at<int>(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(), nobgMat.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<int>(row, col);
|
|
|
+
|
|
|
+ if (v == label)
|
|
|
+ {
|
|
|
+ imageROI.at<uchar>(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);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+ }
|
|
|
+ void COTSImageProcess::findPeakAndValley(const vector<int>& v, vector<int>& peakPositions, vector<int>& valleyPositions)
|
|
|
+ {
|
|
|
+ vector<int> diff_v(v.size() - 1, 0);
|
|
|
+ // 计算V的一阶差分和符号函数trend
|
|
|
+ for (vector<int>::size_type i = 0; i != diff_v.size(); i++)
|
|
|
+ {
|
|
|
+ if (v[i + 1] - v[i] > 0)
|
|
|
+ diff_v[i] = 1;
|
|
|
+ else if (v[i + 1] - v[i] < 0)
|
|
|
+ diff_v[i] = -1;
|
|
|
+ else
|
|
|
+ diff_v[i] = 0;
|
|
|
+ }
|
|
|
+ // 对Trend作了一个遍历
|
|
|
+ for (int i = diff_v.size() - 1; i >= 0; i--)
|
|
|
+ {
|
|
|
+ if (diff_v[i] == 0 && i == diff_v.size() - 1)
|
|
|
+ {
|
|
|
+ diff_v[i] = 1;
|
|
|
+ }
|
|
|
+ else if (diff_v[i] == 0)
|
|
|
+ {
|
|
|
+ if (diff_v[i + 1] >= 0)
|
|
|
+ diff_v[i] = 1;
|
|
|
+ else
|
|
|
+ diff_v[i] = -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (vector<int>::size_type i = 0; i != diff_v.size() - 1; i++)
|
|
|
+ {
|
|
|
+ if (diff_v[i + 1] - diff_v[i] == -2)
|
|
|
+ peakPositions.push_back(i + 1);
|
|
|
+ if (diff_v[i + 1] - diff_v[i] == 2)
|
|
|
+ valleyPositions.push_back(i + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ std::vector<CIntRange> COTSImageProcess::GetValidGreyLevelRanges(CBSEImgPtr pBSEImg)
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+ WORD originChartData[MAXBYTE];
|
|
|
+
|
|
|
+
|
|
|
+ //1. get chart data
|
|
|
+ pBSEImg->SetChartData();
|
|
|
+
|
|
|
+ memcpy(originChartData, pBSEImg->GetBSEChart(), sizeof(WORD) * MAXBYTE);
|
|
|
+ originChartData[0] = 0;
|
|
|
+
|
|
|
+ std::vector<int> greyChart;
|
|
|
+ for (int i = 0; i < MAXBYTE; i++)
|
|
|
+ {
|
|
|
+ greyChart.push_back((int)originChartData[i]);
|
|
|
+ }
|
|
|
+ std::vector<int> peaks;
|
|
|
+ std::vector<int> valleys;
|
|
|
+ findPeakAndValley(greyChart, peaks, valleys);
|
|
|
+
|
|
|
+ if ((peaks.size() - valleys.size()) == 1)
|
|
|
+ {
|
|
|
+ valleys.push_back(254);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ std::map<int, MyGreyPeak*> peakMap;// hold all the peaks in this spectrum which are sorted by there area.
|
|
|
+
|
|
|
+ MyGreyPeak* lastRng = NULL;
|
|
|
+ MyGreyPeak* firstRng = NULL;
|
|
|
+
|
|
|
+ for (int i = 0; i < peaks.size(); i++)
|
|
|
+ {
|
|
|
+ MyGreyPeak* gr = new MyGreyPeak();
|
|
|
+ if (i == 0)
|
|
|
+ {
|
|
|
+ gr->start = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ gr->start = valleys[i - 1];
|
|
|
+ }
|
|
|
+
|
|
|
+ gr->end = valleys[i];
|
|
|
+ for (int j = gr->start; j < gr->end; j++)
|
|
|
+ {
|
|
|
+ gr->area += originChartData[j];
|
|
|
+ }
|
|
|
+
|
|
|
+ gr->peakPos = peaks[i];
|
|
|
+ gr->peakValue = originChartData[peaks[i]];
|
|
|
+ gr->valleyValue = valleys[i];
|
|
|
+ if (firstRng == NULL)
|
|
|
+ {
|
|
|
+ firstRng = gr;
|
|
|
+ lastRng = gr;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ gr->preRng = lastRng;
|
|
|
+ lastRng->nextRng = gr;
|
|
|
+ }
|
|
|
+
|
|
|
+ lastRng = gr;
|
|
|
+
|
|
|
+ peakMap[gr->start] = gr;
|
|
|
+
|
|
|
+ }
|
|
|
+ int validGreyLevelNum = 0;//statistic the none zero grey level number
|
|
|
+ long partArea = 0;
|
|
|
+ for (int i = 0; i < 255; i++)
|
|
|
+ {
|
|
|
+ if (originChartData[i] != 0)
|
|
|
+ {
|
|
|
+ validGreyLevelNum += 1;
|
|
|
+ partArea += originChartData[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ auto curRange = firstRng;
|
|
|
+ int maxPeakValue = curRange->peakValue;
|
|
|
+ while (curRange != NULL)
|
|
|
+ {
|
|
|
+ if (curRange->peakValue > maxPeakValue)
|
|
|
+ {
|
|
|
+ maxPeakValue = curRange->peakValue;
|
|
|
+ }
|
|
|
+ curRange = curRange->nextRng;
|
|
|
+ }
|
|
|
+ curRange = firstRng;
|
|
|
+ while (curRange != NULL)
|
|
|
+ {
|
|
|
+ curRange->maxPeakvalue = maxPeakValue;
|
|
|
+ curRange->allNoneZeroGreyLevelNum = validGreyLevelNum;
|
|
|
+ curRange = curRange->nextRng;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ MyGreyPeak::MergeGreyPeaks(firstRng);
|
|
|
+
|
|
|
+ std::vector<CIntRange> ranges;
|
|
|
+ auto curRange1 = firstRng;
|
|
|
+ while (curRange1 != NULL)
|
|
|
+ {
|
|
|
+
|
|
|
+ CIntRange pRange;
|
|
|
+ pRange.SetStart(curRange1->start);
|
|
|
+ pRange.SetEnd(curRange1->end);
|
|
|
+ ranges.push_back(pRange);
|
|
|
+ curRange1 = curRange1->nextRng;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ranges;
|
|
|
+
|
|
|
+ }
|
|
|
+ BOOL COTSImageProcess::FindSeedsByGrayScale(CBSEImgPtr fieldImg, double a_PixelSize, std::vector<CPoint>& OutSeeds)
|
|
|
+ {
|
|
|
+ ASSERT(fieldImg);
|
|
|
+
|
|
|
+
|
|
|
+ ASSERT(m_imageProcessParam);
|
|
|
+ int nWidthImg = fieldImg->GetWidth();
|
|
|
+ int nHeightImg = fieldImg->GetHeight();
|
|
|
+
|
|
|
+ long nImgSize = nWidthImg * nHeightImg;
|
|
|
+
|
|
|
+ std::vector<CIntRange> validPeaks = GetValidGreyLevelRanges(fieldImg);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ CRect r = CRect(0, 0, nWidthImg, nHeightImg);
|
|
|
+
|
|
|
+ CBSEImgPtr imgNoBGBinary = CBSEImgPtr(new CBSEImg(r));
|
|
|
+
|
|
|
+ for (int i = 0; i < validPeaks.size(); i++)
|
|
|
+ {
|
|
|
+ CIntRange pRange = validPeaks[i];
|
|
|
+ if (pRange.GetStart() == 0)//prevent the 0 grey pixels being recognized as particle.
|
|
|
+ {
|
|
|
+ pRange.SetStart(3);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ long nNumParticle = 0;
|
|
|
+
|
|
|
+ GetSpecialGrayRangeImage(fieldImg, pRange, imgNoBGBinary, nNumParticle);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (nNumParticle == 0)
|
|
|
+ {
|
|
|
+
|
|
|
+ continue;
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ // get the area image
|
|
|
+
|
|
|
+
|
|
|
+ Mat matImg = GetMatDataFromBseImg(imgNoBGBinary);
|
|
|
+ Mat labels = Mat::zeros(matImg.size(), CV_32S);
|
|
|
+ Mat stats, centroids;
|
|
|
+ int number = connectedComponentsWithStats(matImg, labels, stats, centroids, 8, CV_32S);
|
|
|
+ auto incsize = m_imageProcessParam->GetIncArea();
|
|
|
+ double rStart = incsize.GetStart() / 2.0;
|
|
|
+ double rEnd = incsize.GetEnd() / 2.0;
|
|
|
+ double pixelarea = a_PixelSize * a_PixelSize;
|
|
|
+ double areaStart = rStart* rStart * 3.14159*pixelarea;
|
|
|
+ double areaEnd = rEnd* rEnd * 3.14159*pixelarea;
|
|
|
+ /*double areaStart = 0;
|
|
|
+ double areaEnd = 1000;*/
|
|
|
+
|
|
|
+
|
|
|
+ for (size_t i = 1; i < number; i++)
|
|
|
+ {
|
|
|
+ int center_x = centroids.at<double>(i, 0);
|
|
|
+ int center_y = centroids.at<double>(i, 1);
|
|
|
+
|
|
|
+ int area = stats.at<int>(i, CC_STAT_AREA);
|
|
|
+
|
|
|
+ double actualArea = area * a_PixelSize * a_PixelSize;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (actualArea >= areaStart && actualArea < areaEnd)
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+ CPoint seed = CPoint(center_x, center_y);
|
|
|
+ OutSeeds.push_back(seed);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
BOOL COTSImageProcess::CalcuParticleImagePropertes(COTSParticlePtr a_pOTSPart, double a_PixelSize)
|
|
|
{
|