You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
8.0 KiB
C++
360 lines
8.0 KiB
C++
#include "pch.h"
|
|
#include "coutlinedetector.h"
|
|
#include "GSurface.h"
|
|
#include <QDebug>
|
|
|
|
//#include ".\include\PolygonTreeInterface.h"
|
|
//#include ".\include\InterfaceElements.h"
|
|
|
|
#include "..\..\SSBase\VoronoiMap\PolygonTreeInterface.h"
|
|
#include "..\..\SSBase\VoronoiMap\InterfaceElements.h"
|
|
#include "clipper2\clipper.h"
|
|
|
|
//using namespace std;
|
|
COutlineDetector::COutlineDetector()
|
|
:m_pSurface(nullptr)
|
|
, m_nIterations(3)
|
|
, m_zlower(0)
|
|
, m_zupper(0)
|
|
, m_smoothTimes(0)
|
|
, m_minArea(0)
|
|
{
|
|
}
|
|
|
|
void COutlineDetector::clear()
|
|
{
|
|
// m_pSurface = nullptr;
|
|
m_originalContours.clear();
|
|
m_matMorp.release();
|
|
}
|
|
|
|
|
|
//设置最小轮廓线面积
|
|
void COutlineDetector::setContourMinArea(float area)
|
|
{
|
|
if (area < 0)
|
|
area = 0;
|
|
m_minArea = area;
|
|
}
|
|
//设置输出轮廓线平滑次数
|
|
void COutlineDetector::setContourSmoothTimes(unsigned int times)
|
|
{
|
|
if (times < 1)
|
|
times = 0;
|
|
m_smoothTimes = times;
|
|
}
|
|
|
|
|
|
void COutlineDetector::setSurface(GSurface *pSurf, float zlower, float zupper, unsigned int nIters)
|
|
{
|
|
m_pSurface = pSurf;
|
|
setIterations(nIters);
|
|
setTargetZRange(zlower, zupper);
|
|
}
|
|
|
|
void COutlineDetector::setTargetZRange(float zlower, float zupper)
|
|
{
|
|
m_zlower = zlower;
|
|
m_zupper = zupper;
|
|
}
|
|
|
|
bool COutlineDetector::ProcessImage()
|
|
{
|
|
if (nullptr == m_pSurface)
|
|
return false;
|
|
morphologySolve();
|
|
createContours();
|
|
SmoothContours();
|
|
|
|
return true;
|
|
}
|
|
|
|
void COutlineDetector::multiContourToRealCoords(const Contours& inputContour, Contours & dstContours, int smoothTimes)
|
|
{
|
|
dstContours.resize(inputContour.size());
|
|
for (int i = 0; i < inputContour.size(); i++)
|
|
contourToRealCoords(inputContour[i], dstContours[i], smoothTimes);
|
|
}
|
|
|
|
void COutlineDetector::contourToRealCoords(const Contour& inputContour, Contour& dstContour, int smoothTimes)
|
|
{
|
|
int N = inputContour.size();
|
|
double* x = new double[N];
|
|
double* y = new double[N];
|
|
|
|
float x0 = m_pSurface->X(0);
|
|
float y0 = m_pSurface->Y(0);
|
|
|
|
float dx = m_pSurface->DeltX();
|
|
float dy = m_pSurface->DeltY();
|
|
double tx, ty;
|
|
for (int i = 0; i < N; i++)
|
|
{
|
|
tx = inputContour[i].x;
|
|
ty = inputContour[i].y;
|
|
x[i] = x0 + dx * tx;
|
|
y[i] = y0 + dy * ty;
|
|
}
|
|
|
|
if (N > 4 && smoothTimes > 0)
|
|
{
|
|
ContourUtils::Smooth53(x, N, smoothTimes);
|
|
ContourUtils::Smooth53(y, N, smoothTimes);
|
|
}
|
|
|
|
dstContour.resize(N);
|
|
for (int i = 0; i < N; i++)
|
|
{
|
|
dstContour[i].x = x[i];
|
|
dstContour[i].y = y[i];
|
|
}
|
|
|
|
delete[]x;
|
|
delete[]y;
|
|
}
|
|
|
|
void toPline(Contour& src, CPolyline& dstLine)
|
|
{
|
|
dstLine.Clear();
|
|
for (auto& p : src)
|
|
{
|
|
dstLine.AddPoint(p.x, p.y, 0);
|
|
}
|
|
}
|
|
|
|
void fromPline(CPolyline& src, Contour& dst)
|
|
{
|
|
CPointXYZ pt;
|
|
dst.resize(src.GetSize());
|
|
for (int i = 0; i < src.GetSize(); i++)
|
|
{
|
|
pt = src.GetPoint(i);
|
|
dst[i].x = pt.x0;
|
|
dst[i].y = pt.y0;
|
|
}
|
|
}
|
|
|
|
//生成沉积相轮廓线,局部合并内部包含孔洞的轮廓线
|
|
int COutlineDetector::CreateFaciesContours(void)
|
|
{
|
|
//m_faciesContours.clear();
|
|
m_pgnTree.Clear();
|
|
|
|
std::vector<CPolyline*> polygons;
|
|
|
|
int i = 0;
|
|
char chs[20];
|
|
polygons.reserve(m_originalContours.size());
|
|
|
|
float x0 = m_pSurface->X(0);
|
|
float y0 = m_pSurface->Y(0);
|
|
|
|
float dx = m_pSurface->DeltX();
|
|
float dy = m_pSurface->DeltY();
|
|
//double tx, ty;
|
|
//for (int i = 0; i < N; i++)
|
|
//{
|
|
// tx = inputContour[i].x;
|
|
// ty = inputContour[i].y;
|
|
// x[i] = x0 + dx * tx;
|
|
// y[i] = y0 + dy * ty;
|
|
//}
|
|
|
|
for (auto& p : m_originalContours)
|
|
{
|
|
CPolyline* pl = new CPolyline;
|
|
for (auto& pt : p)
|
|
{
|
|
pl->AddPoint(x0 + dx* pt.x, y0 + dy * pt.y, 0);
|
|
}
|
|
//toPline(p, *pl);
|
|
sprintf(chs, "%d", i);
|
|
pl->SetName(chs);
|
|
pl->setClosed();
|
|
i++;
|
|
polygons.push_back(pl);
|
|
}
|
|
|
|
std::vector<vector<int>> hierarchy;
|
|
hierarchy.resize(m_hierarchy.size(), vector<int>(4, -1));
|
|
|
|
for (i = 0; i < m_hierarchy.size(); i++)
|
|
{
|
|
for (int j = 0; j < 4; j++)
|
|
hierarchy[i][j] = m_hierarchy[i][j];
|
|
}
|
|
|
|
//CPolygonTreeInterface pgnTree;
|
|
m_pgnTree.SetPolygons(polygons);
|
|
m_pgnTree.SetHierarchy(hierarchy);
|
|
|
|
//double deltX = m_pSurface->DeltX();
|
|
//double deltY = m_pSurface->DeltY();
|
|
|
|
double minArea = m_minArea / (dx*dy);
|
|
if (minArea < 1e-4)
|
|
minArea = 1e-4;
|
|
|
|
m_pgnTree.Create(minArea);
|
|
|
|
int N = m_pgnTree.GetResultPolygons().size();
|
|
|
|
//清空临时变量
|
|
for (auto p : polygons)
|
|
delete p;
|
|
return N;
|
|
}
|
|
|
|
void COutlineDetector::setIterations(unsigned int nIterations)
|
|
{
|
|
m_nIterations = nIterations;
|
|
}
|
|
|
|
void COutlineDetector::morphologySolve()
|
|
{
|
|
TraceBorder();
|
|
|
|
cv::Mat srcMat;
|
|
ImageUtils::convertSurfaceToMat(m_pSurface, m_zlower, m_zupper, srcMat); //surface to bin mat
|
|
|
|
m_matSrc = srcMat;
|
|
|
|
cv::Mat bin = srcMat;
|
|
|
|
cv::Mat kernel;
|
|
kernel = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3));//矩形结构元素
|
|
cv::Mat materode, matdilate;
|
|
//膨胀
|
|
dilate(bin, matdilate, kernel, cv::Point(-1, -1), m_nIterations);
|
|
//腐蚀
|
|
erode(matdilate, materode, kernel, cv::Point(-1, -1), m_nIterations + 1);
|
|
//imshow("腐蚀", materode);
|
|
|
|
|
|
|
|
// erode(bin, materode, kernel,Point(-1,-1),m_nIterations);
|
|
// //imshow("腐蚀", materode);
|
|
|
|
// //膨胀
|
|
// dilate(materode, matdilate, kernel, Point(-1, -1), m_nIterations+1);
|
|
// //imshow("膨胀", matdilate);
|
|
// // imwrite("d:/腐蚀膨胀后.bmp", matdilate);
|
|
m_matMorp = matdilate;
|
|
|
|
//由matBorder对越界部分进行修改
|
|
for (int j = 0; j < m_matMorp.rows; j++)
|
|
{
|
|
for (int i = 0; i < m_matMorp.cols; i++)
|
|
{
|
|
|
|
if (0 == m_matBorder.at<uchar>(j, i))
|
|
{
|
|
m_matMorp.at<uchar>(j, i) = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Contours& COutlineDetector::GetOriginalContours(void)
|
|
{
|
|
return m_originalContours;
|
|
}
|
|
//获取沉积相轮廓线
|
|
CPolygonTreeInterface* COutlineDetector::GetFaciesContours(void)
|
|
{
|
|
CPolygonTreeInterface* pIntptr = &m_pgnTree;
|
|
return pIntptr;
|
|
}
|
|
shared_ptr<Contours> COutlineDetector::GetRealContours(void)
|
|
{
|
|
int nCount = m_pgnTree.GetResultPolygons().size();
|
|
auto faciesContours =std::make_shared<Contours>();
|
|
faciesContours->resize(nCount);
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
fromPline(*m_pgnTree.GetResultPolygons().at(i), (*faciesContours)[i]);
|
|
}
|
|
Contours dstvec;
|
|
multiContourToRealCoords(*faciesContours, dstvec, 0);
|
|
return faciesContours;
|
|
}
|
|
|
|
void COutlineDetector::TraceBorder()
|
|
{
|
|
m_border.clear();
|
|
|
|
ImageUtils::convertSurfaceToMat(m_pSurface, m_pSurface->GetRange()[0], m_pSurface->GetRange()[1],
|
|
m_matBorder);
|
|
|
|
std::vector<std::vector<cv::Point>> contours;
|
|
std::vector<cv::Vec4i> hierarchy;
|
|
// hierarchy 四个参数:下一个,前一个,子轮廓,父轮廓 (不存在则为-1)
|
|
cv::findContours(m_matBorder, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_NONE, cv::Point());
|
|
|
|
if (contours.size() > 0)
|
|
{
|
|
m_border.resize(contours[0].size());
|
|
for (int i = 0; i < contours[0].size(); i++)
|
|
{
|
|
m_border[i] = contours[0][i];
|
|
}
|
|
}
|
|
}
|
|
|
|
void COutlineDetector::createContours()
|
|
{
|
|
m_originalContours.clear();
|
|
//m_faciesContours.clear();
|
|
m_pgnTree.Clear();
|
|
std::vector<std::vector<cv::Point>> contours;
|
|
std::vector<cv::Vec4i> hierarchy;
|
|
// hierarchy 四个参数:下一个,前一个,子轮廓,父轮廓 (不存在则为-1)
|
|
cv::findContours(m_matMorp, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE, cv::Point());
|
|
|
|
m_originalContours.resize(contours.size());
|
|
|
|
for (int i = 0; i < contours.size(); i++)
|
|
{
|
|
approxPolyDP(contours[i], m_originalContours[i], 0.3, true);
|
|
}
|
|
|
|
m_hierarchy.assign(hierarchy.begin(), hierarchy.end());
|
|
}
|
|
|
|
void COutlineDetector::FilterContours(float minArea, Contours& ReservedContours)
|
|
{
|
|
double dx = m_pSurface->DeltX();
|
|
double dy = m_pSurface->DeltY();
|
|
double gridArea = dx * dy;
|
|
//对应图片上的面积
|
|
double imArea = minArea / gridArea;
|
|
|
|
if (m_originalContours.empty() || imArea < 1e-4)
|
|
{
|
|
ReservedContours.assign(m_originalContours.begin(), m_originalContours.end());
|
|
return;
|
|
}
|
|
|
|
ReservedContours.reserve(m_originalContours.size());
|
|
|
|
for (auto& p : m_originalContours)
|
|
{
|
|
if (p.size() < 3)
|
|
continue;
|
|
double area = contourArea(p);
|
|
if (area < imArea)
|
|
continue;
|
|
ReservedContours.push_back(p);
|
|
}
|
|
}
|
|
|
|
void COutlineDetector::SmoothContours()
|
|
{
|
|
ContourUtils::SmoothContour(m_originalContours, m_border, m_hierarchy, m_smoothTimes);
|
|
}
|
|
|
|
cv::Mat &COutlineDetector::getResultMat()
|
|
{
|
|
return m_matMorp;
|
|
}
|