|
|
#include "coutlinedetector.h"
|
|
|
#include "GSurface.h"
|
|
|
#include <QDebug>
|
|
|
#include "PolygonTreeInterface.h"
|
|
|
#include "InterfaceElements.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 std::vector< std::vector<cv::Point2f> >& inputContour, std::vector< std::vector<cv::Point2f> > & 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 std::vector<cv::Point2f>& inputContour, std::vector<cv::Point2f>& 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)
|
|
|
{
|
|
|
Smooth53(x,N,smoothTimes);
|
|
|
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;
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
bool COutlineDetector::WriteContours( std::vector<std::vector<cv::Point2f>>& contours, const char* path)
|
|
|
{
|
|
|
FILE* fw = fopen(path,"w");
|
|
|
if(nullptr == fw)
|
|
|
return false;
|
|
|
|
|
|
float x, y;
|
|
|
for(int j = 0; j < contours.size(); j ++ )
|
|
|
{
|
|
|
/* if(contours[j].size() < 3)
|
|
|
continue;*/
|
|
|
|
|
|
fprintf(fw,"Pline.%d\n",j);
|
|
|
|
|
|
for(auto& p :contours[j] )
|
|
|
{
|
|
|
x = p.x;
|
|
|
y = p.y;
|
|
|
fprintf(fw,"%.12g,%.12g\n",x,y);
|
|
|
}
|
|
|
|
|
|
auto p = contours[j][0];
|
|
|
x = p.x;
|
|
|
y = p.y;
|
|
|
fprintf(fw,"%.12g,%.12g\n",x,y);
|
|
|
|
|
|
fprintf(fw,"\n");
|
|
|
}
|
|
|
|
|
|
fclose(fw);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// bool COutlineDetector::WriteContours(const char *path)
|
|
|
// {
|
|
|
//
|
|
|
//
|
|
|
// SmoothContours(); //平滑轮廓线
|
|
|
//
|
|
|
// vector<Point2f> cbd;
|
|
|
// CombineContours(cbd);
|
|
|
//
|
|
|
// vector<vector<Point2f>> vv; vv.push_back(cbd);
|
|
|
// WriteContours(vv, "d:/combined_contours.dfd");
|
|
|
//
|
|
|
// //转换为实际坐标
|
|
|
// vector< vector<Point2f>> realCoords;
|
|
|
// realCoords.resize(1);
|
|
|
// contourToRealCoords(cbd,realCoords[0],0);
|
|
|
//
|
|
|
//
|
|
|
// return WriteContours(realCoords,path);
|
|
|
//
|
|
|
// /*
|
|
|
//
|
|
|
// vector<vector<cv::Point2f> > ReservedContours;
|
|
|
//
|
|
|
// FilterContours(m_minArea,ReservedContours);
|
|
|
// vector<vector<cv::Point2f>> contours;
|
|
|
// multiContourToRealCoords(ReservedContours,contours,m_smoothTimes);
|
|
|
//
|
|
|
//
|
|
|
// return WriteContours(contours,path);
|
|
|
//
|
|
|
// */
|
|
|
//
|
|
|
//
|
|
|
//// float x, y;
|
|
|
//// for(int j = 0; j < contours.size(); j ++ )
|
|
|
//// {
|
|
|
//// if(contours[j].size() < 3)
|
|
|
//// continue;
|
|
|
//
|
|
|
//// fprintf(fw,"Pline\n");
|
|
|
//
|
|
|
//// for(auto& p :contours[j] )
|
|
|
//// {
|
|
|
//// x = p.x;
|
|
|
//// y = p.y;
|
|
|
//// fprintf(fw,"%.12g,%.12g\n",x,y);
|
|
|
//// }
|
|
|
//
|
|
|
//// auto p = contours[j][0];
|
|
|
//// x = p.x;
|
|
|
//// y = p.y;
|
|
|
//// fprintf(fw,"%.12g,%.12g\n",x,y);
|
|
|
//
|
|
|
//// fprintf(fw,"\n");
|
|
|
//// }
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
//// float x0 = m_pSurface->X(0);
|
|
|
//// float y0 = m_pSurface->Y(0);
|
|
|
//
|
|
|
//// float dx = m_pSurface->DeltX();
|
|
|
//// float dy = m_pSurface->DeltY();
|
|
|
//
|
|
|
//// float x,y;
|
|
|
//// for(int j = 0; j < m_contours.size(); j ++ )
|
|
|
//// {
|
|
|
//// if(m_contours[j].size() < 3)
|
|
|
//// continue;
|
|
|
//
|
|
|
//// fprintf(fw,"Pline\n");
|
|
|
//
|
|
|
//// for(auto& p :m_contours[j] )
|
|
|
//// {
|
|
|
//// x = x0 + dx* p.x;
|
|
|
//// y = y0 + dy*p.y;
|
|
|
//// fprintf(fw,"%.12g,%.12g\n",x,y);
|
|
|
//// }
|
|
|
//
|
|
|
//// auto p = m_contours[j][0];
|
|
|
//// x = x0 + dx* p.x;
|
|
|
//// y = y0 + dy*p.y;
|
|
|
//// fprintf(fw,"%.12g,%.12g\n",x,y);
|
|
|
//
|
|
|
//// fprintf(fw,"\n");
|
|
|
//// }
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
//// fclose(fw);
|
|
|
// // return true;
|
|
|
// }
|
|
|
//
|
|
|
void toPline(vector<Point2f>& src, CPolyline& dstLine )
|
|
|
{
|
|
|
dstLine.Clear();
|
|
|
for(auto p:src)
|
|
|
{
|
|
|
dstLine.AddPoint(p.x,p.y,0);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void fromPline(CPolyline& src, vector<Point2f>& 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();
|
|
|
|
|
|
vector<CPolyline*> polygons;
|
|
|
|
|
|
int i = 0;
|
|
|
char chs[20];
|
|
|
polygons.reserve(m_originalContours.size());
|
|
|
for (auto& p : m_originalContours)
|
|
|
{
|
|
|
CPolyline* pl = new CPolyline;
|
|
|
toPline(p, *pl);
|
|
|
sprintf(chs, "%d", i);
|
|
|
pl->SetName(chs);
|
|
|
pl->setClosed();
|
|
|
i++;
|
|
|
polygons.push_back(pl);
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
pgnTree.SetPolygons(polygons);
|
|
|
pgnTree.SetHierarchy(hierarchy);
|
|
|
|
|
|
double dx = m_pSurface->DeltX();
|
|
|
double dy = m_pSurface->DeltY();
|
|
|
|
|
|
double minArea = m_minArea / (dx*dy);
|
|
|
if(minArea < 1e-4)
|
|
|
minArea = 1e-4;
|
|
|
|
|
|
|
|
|
|
|
|
pgnTree.Create(minArea);
|
|
|
|
|
|
int N = pgnTree.GetResultPolygons().size();
|
|
|
m_faciesContours.resize(N);
|
|
|
for (int i = 0; i < N; i++)
|
|
|
{
|
|
|
fromPline(*pgnTree.GetResultPolygons().at(i), m_faciesContours[i]);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//清空临时变量
|
|
|
for (auto p : polygons)
|
|
|
delete p;
|
|
|
|
|
|
|
|
|
return N;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
// void COutlineDetector::CombineContours(std::vector<Point2f> &dstContour)
|
|
|
// {
|
|
|
//
|
|
|
// vector<CPolyline*> polygons;
|
|
|
//
|
|
|
// int i = 0;
|
|
|
// char chs[20];
|
|
|
// polygons.reserve(m_originalContours.size());
|
|
|
// for(auto& p: m_originalContours)
|
|
|
// {
|
|
|
// CPolyline* pl = new CPolyline;
|
|
|
// toPline(p,*pl);
|
|
|
// sprintf(chs,"%d",i);
|
|
|
// pl->SetName(chs);
|
|
|
// pl->setClosed();
|
|
|
// i++;
|
|
|
// polygons.push_back(pl);
|
|
|
// }
|
|
|
//
|
|
|
// 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;
|
|
|
// pgnTree.SetPolygons(polygons);
|
|
|
// pgnTree.SetHierarchy(hierarchy);
|
|
|
//
|
|
|
// double dx = m_pSurface->DeltX();
|
|
|
// double dy = m_pSurface->DeltY();
|
|
|
//
|
|
|
// double minArea = m_minArea/(dx*dy);
|
|
|
//
|
|
|
//
|
|
|
// pgnTree.Create(minArea);
|
|
|
//
|
|
|
// CPolyline& pc = pgnTree.GetCombinedPolygon();
|
|
|
//
|
|
|
// fromPline(pc,dstContour);
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
// //清空临时变量
|
|
|
// for(auto p:polygons)
|
|
|
// delete p;
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
//// pgnTree.GetHierarchy().resize(m_hierarchy.size());
|
|
|
//
|
|
|
//// for(int i = 0; i < m_hierarchy.size(); i ++ )
|
|
|
//// {
|
|
|
//// pgnTree.GetHierarchy()[i].resize(4);
|
|
|
//// for(int j = 0; j <4 ; j ++ )
|
|
|
//// pgnTree.GetHierarchy()[i][j] = m_hierarchy[i][j];
|
|
|
//// }
|
|
|
//
|
|
|
//
|
|
|
//// for(int i = 0; i < m_contours.size(); i ++ )
|
|
|
//// {
|
|
|
//// CPolyline* pc = new CPolyline;
|
|
|
//// for(auto& p: m_contours[i] )
|
|
|
//// pc->AddPoint(p.x,p.y,0);
|
|
|
//
|
|
|
//// pgnTree.GetPolygons().push_back(pc);
|
|
|
//
|
|
|
//// }
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
// }
|
|
|
//
|
|
|
|
|
|
bool COutlineDetector::WriteContours(std::vector<std::vector<Point> > &contours, const char* path)
|
|
|
{
|
|
|
|
|
|
FILE* fw = fopen(path,"w");
|
|
|
if(nullptr == fw)
|
|
|
return false;
|
|
|
|
|
|
float x, y;
|
|
|
for(int j = 0; j < contours.size(); j ++ )
|
|
|
{
|
|
|
if(contours[j].size() < 3)
|
|
|
continue;
|
|
|
|
|
|
fprintf(fw,"Pline.%d\n",j);
|
|
|
|
|
|
for(auto& p :contours[j] )
|
|
|
{
|
|
|
x = p.x;
|
|
|
y = p.y;
|
|
|
fprintf(fw,"%.12g,%.12g\n",x,y);
|
|
|
}
|
|
|
|
|
|
auto p = contours[j][0];
|
|
|
x = p.x;
|
|
|
y = p.y;
|
|
|
fprintf(fw,"%.12g,%.12g\n",x,y);
|
|
|
|
|
|
fprintf(fw,"\n");
|
|
|
}
|
|
|
|
|
|
fclose(fw);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void COutlineDetector::setIterations(unsigned int nIterations)
|
|
|
{
|
|
|
m_nIterations = nIterations;
|
|
|
}
|
|
|
|
|
|
void COutlineDetector::morphologySolve()
|
|
|
{
|
|
|
|
|
|
TraceBorder();
|
|
|
|
|
|
Mat srcMat ;
|
|
|
convertSurfaceToMat(m_pSurface,m_zlower,m_zupper, srcMat); //surface to bin mat
|
|
|
|
|
|
|
|
|
// imshow("bordermat",m_matBorder);
|
|
|
// waitKey(0);
|
|
|
|
|
|
m_matSrc = srcMat;
|
|
|
|
|
|
Mat bin = srcMat;
|
|
|
|
|
|
Mat kernel;
|
|
|
kernel = getStructuringElement(MORPH_CROSS, Size(3, 3));//矩形结构元素
|
|
|
Mat materode, matdilate;
|
|
|
//膨胀
|
|
|
dilate(bin, matdilate, kernel, Point(-1, -1), m_nIterations);
|
|
|
//腐蚀
|
|
|
erode(matdilate, materode, kernel,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;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
//五点三次平滑 n 必须大于4
|
|
|
bool COutlineDetector::Smooth53(double* val, int n, int stimes)
|
|
|
{
|
|
|
if (n < 5 || stimes < 1) return false;
|
|
|
|
|
|
int i, k; //k为平滑次数
|
|
|
double *xx = new double[n];
|
|
|
|
|
|
for (k = 0; k < stimes; k ++)
|
|
|
{
|
|
|
xx[0] = 69 * val[0] + 4 * val[1] - 6 * val[2] + 4 * val[3] - val[4];
|
|
|
xx[0] = xx[0] / 70;
|
|
|
xx[1] = 2 * val[0] + 27 * val[1] + 12 * val[2] - 8 * val[3];
|
|
|
xx[1] = (xx[1] + 2 * val[4]) / 35;
|
|
|
|
|
|
for (i = 2; i <= n - 3; i++)
|
|
|
{
|
|
|
xx[i] = -3 * val[i - 2] + 12 * val[i - 1] + 17 * val[i];
|
|
|
xx[i] = (xx[i] + 12 * val[i + 1] - 3 * val[i + 2]) / 35;
|
|
|
}
|
|
|
|
|
|
xx[n - 2] = 2 * val[n - 5] - 8 * val[n - 4] + 12 * val[n - 3];
|
|
|
xx[n - 2] = (xx[n - 2] + 27 * val[n - 2] + 2 * val[n - 1]) / 35;
|
|
|
xx[n - 1] = -val[n - 5] + 4 * val[n - 4] - 6 * val[n - 3];
|
|
|
xx[n - 1] = (xx[n - 1] + 4 * val[n - 2] + 69 * val[n - 1]) / 70;
|
|
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
val[i] = xx[i];
|
|
|
}
|
|
|
|
|
|
delete []xx;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void COutlineDetector::SmoothContours()
|
|
|
{
|
|
|
int N = m_originalContours.size();
|
|
|
|
|
|
for(int i = 0; i < N; i ++ )
|
|
|
{
|
|
|
//一级轮廓线
|
|
|
if(-1 == m_hierarchy[i][3] )
|
|
|
SmoothRootContour(m_originalContours[i],m_smoothTimes);
|
|
|
else
|
|
|
SmoothContour(m_originalContours[i],m_smoothTimes);
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
std::vector<std::vector<cv::Point2f>>& COutlineDetector::GetOriginalContours(void)
|
|
|
{
|
|
|
|
|
|
return m_originalContours;
|
|
|
|
|
|
}
|
|
|
//获取沉积相轮廓线
|
|
|
std::vector<std::vector<cv::Point2f>>& COutlineDetector::GetFaciesContours(void)
|
|
|
{
|
|
|
return m_faciesContours;
|
|
|
}
|
|
|
|
|
|
|
|
|
void COutlineDetector::SmoothRootContour(std::vector<cv::Point2f>& inputContour, int nTimes)
|
|
|
{
|
|
|
|
|
|
|
|
|
if(nTimes < 1 || inputContour.size() < 4)
|
|
|
return;
|
|
|
|
|
|
|
|
|
int N = inputContour.size();
|
|
|
|
|
|
|
|
|
//查找inputContour在边界上的部分
|
|
|
|
|
|
int istart = 0;
|
|
|
int iend = 0;
|
|
|
int i = 0;
|
|
|
vector<Point2f> subline;
|
|
|
while(i < N)
|
|
|
{
|
|
|
if( !isPtOnBorder(inputContour[i])) //找到不在边界上的首点
|
|
|
{
|
|
|
|
|
|
istart = i;
|
|
|
for( i = istart +1; i < N; i ++ )
|
|
|
{
|
|
|
if( N-1 == i )
|
|
|
{
|
|
|
iend = N-1;
|
|
|
break;
|
|
|
}
|
|
|
else if(isPtOnBorder(inputContour[i]))
|
|
|
{
|
|
|
iend = i-1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if(istart > 0)
|
|
|
istart --;
|
|
|
if(iend < N-1)
|
|
|
iend ++;
|
|
|
|
|
|
if(iend - istart > 3) //至少5个点
|
|
|
{
|
|
|
//平滑不在边界线上的局部曲线[istart,iend]
|
|
|
subline.clear();
|
|
|
subline.reserve(iend-istart +1);
|
|
|
for(int k = istart; k <= iend; k ++ )
|
|
|
subline.push_back(inputContour[k]);
|
|
|
|
|
|
SmoothContour(subline,nTimes);
|
|
|
//将平滑后的局部曲线替换原曲线
|
|
|
int t = 0;
|
|
|
for(int k = istart; k <= iend; k ++ )
|
|
|
inputContour[k] = subline[t++];
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
bool COutlineDetector::isPtOnBorder(const Point &pt)
|
|
|
{
|
|
|
for(auto& p:m_border)
|
|
|
{
|
|
|
if(fabs(pt.x - p.x) < 0.5 && fabs(pt.y-p.y) < 0.5)
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
void COutlineDetector::SmoothContour( std::vector<cv::Point2f>& inputContour, int nTimes)
|
|
|
{
|
|
|
if(nTimes < 1 || inputContour.size() < 4)
|
|
|
return;
|
|
|
|
|
|
int N = inputContour.size();
|
|
|
double* x = new double[N];
|
|
|
double* y = new double[N];
|
|
|
|
|
|
double tx,ty;
|
|
|
for(int i = 0; i < N; i ++ )
|
|
|
{
|
|
|
tx = inputContour[i].x;
|
|
|
ty = inputContour[i].y;
|
|
|
x[i] = tx;
|
|
|
y[i] = ty;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(N > 4 && nTimes > 0)
|
|
|
{
|
|
|
Smooth53(x,N,nTimes);
|
|
|
Smooth53(y,N,nTimes);
|
|
|
}
|
|
|
|
|
|
|
|
|
for(int i = 0; i < N; i ++ )
|
|
|
{
|
|
|
inputContour[i].x = x[i];
|
|
|
inputContour[i].y = y[i];
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
delete []x;
|
|
|
delete []y;
|
|
|
}
|
|
|
|
|
|
void COutlineDetector::TraceBorder()
|
|
|
{
|
|
|
m_border.clear();
|
|
|
|
|
|
convertSurfaceToMat(m_pSurface,m_pSurface->GetRange()[0],m_pSurface->GetRange()[1],
|
|
|
m_matBorder);
|
|
|
|
|
|
vector<vector<Point>> contours;
|
|
|
vector<Vec4i> hierarchy;
|
|
|
// hierarchy 四个参数:下一个,前一个,子轮廓,父轮廓 (不存在则为-1)
|
|
|
findContours(m_matBorder, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, 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();
|
|
|
|
|
|
vector<vector<Point>> contours;
|
|
|
vector<Vec4i> hierarchy;
|
|
|
// hierarchy 四个参数:下一个,前一个,子轮廓,父轮廓 (不存在则为-1)
|
|
|
findContours(m_matMorp, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
|
|
|
|
|
|
|
|
|
// //查看轮廓线
|
|
|
// Mat tmpMat;
|
|
|
// cvtColor(m_matMorp,tmpMat,COLOR_GRAY2RGB);
|
|
|
|
|
|
// drawContours(tmpMat,contours,-1,Scalar(0,0,255));
|
|
|
// namedWindow("tmpMat",WINDOW_NORMAL);
|
|
|
// imshow("tmpMat",tmpMat);
|
|
|
// waitKey(0);
|
|
|
|
|
|
|
|
|
////begin test
|
|
|
// WriteContours(contours,"d:/outcontours.dfd");
|
|
|
|
|
|
// FILE * fw = fopen("d:/hierarchy.txt","w");
|
|
|
// int i = 0;
|
|
|
// for(auto p: hierarchy)
|
|
|
// {
|
|
|
// fprintf(fw,"%d:%d,%d,%d,%d\n",i++,p[0],p[1],p[2],p[3]);
|
|
|
// }
|
|
|
|
|
|
// fclose(fw);
|
|
|
////end test
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// vector<vector<Point>> dstcontous;
|
|
|
// dstcontous.resize(contours.size());
|
|
|
m_originalContours.resize(contours.size() );
|
|
|
|
|
|
for (int i = 0; i < contours.size(); i ++ )
|
|
|
{
|
|
|
approxPolyDP(contours[i], m_originalContours[i], 1, true);
|
|
|
|
|
|
}
|
|
|
|
|
|
m_hierarchy.assign(hierarchy.begin(),hierarchy.end() );
|
|
|
|
|
|
// m_hierarchy.clear();
|
|
|
|
|
|
// //去除首个曲线(总轮廓线)
|
|
|
// m_hierarchy.reserve(hierarchy.size()-1);
|
|
|
// for(int i = 1; i < hierarchy.size(); i ++ )
|
|
|
// {
|
|
|
// cv::Vec4i tmp = hierarchy[i];
|
|
|
// for(int j = 0; j < 4; j ++ )
|
|
|
// {
|
|
|
// tmp[j] -= 1;
|
|
|
// if(tmp[j] < -1)
|
|
|
// tmp[j] = -1;
|
|
|
// }
|
|
|
|
|
|
// m_hierarchy.push_back(tmp);
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// drawContours(m_matSrc, m_contours, -1, Scalar(255, 0, 0));
|
|
|
|
|
|
// namedWindow("轮廓线",WINDOW_NORMAL);
|
|
|
// imshow("轮廓线",m_matSrc);
|
|
|
|
|
|
|
|
|
// //imshow("轮廓", big);
|
|
|
// imwrite("d:/轮廓线.bmp", img);
|
|
|
// //WriteContours("d:/等值线.dfd", contours, 10, 10);
|
|
|
|
|
|
|
|
|
// waitKey(0);
|
|
|
|
|
|
|
|
|
// TraceBorder();//追踪边界轮廓线
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
void COutlineDetector::FilterContours(float minArea, std::vector<std::vector<cv::Point2f>>& 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);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
Mat &COutlineDetector::getResultMat()
|
|
|
{
|
|
|
return m_matMorp;
|
|
|
}
|
|
|
|
|
|
void COutlineDetector::convertSurfaceToMat(GSurface *pSrcSurf, float zlower, float zupper, Mat &dstMat)
|
|
|
{
|
|
|
int nx = pSrcSurf->XNum()-1;
|
|
|
int ny = pSrcSurf->YNum() - 1;
|
|
|
|
|
|
|
|
|
// Mat构造:行数,列数,存储结构,数据,step每行多少字节
|
|
|
dstMat = cv::Mat::zeros(ny,nx, CV_8UC1) ; //缺省黑色
|
|
|
|
|
|
float v;
|
|
|
zlower -= 1e-4;
|
|
|
zupper += 1e-4;
|
|
|
for(int j = 0; j < ny; j ++)
|
|
|
{
|
|
|
for(int i = 0; i < nx; i ++)
|
|
|
{
|
|
|
v = pSrcSurf->Z(i,j);
|
|
|
if(v > zlower && v < zupper)
|
|
|
{
|
|
|
dstMat.at<uchar>(j,i) = 255; // 对指定的像素赋值为白色
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
bool COutlineDetector::convertMatToSurface(Mat& mat, float x0, float y0, float deltX, float deltY, GSurface* pDstSurf)
|
|
|
{
|
|
|
|
|
|
int nx = mat.cols;
|
|
|
int ny = mat.rows;
|
|
|
if(nx < 2 || ny < 2)
|
|
|
return false;
|
|
|
|
|
|
pDstSurf->Create(nx,ny,x0,y0,deltX,deltY);
|
|
|
|
|
|
|
|
|
switch (mat.type())
|
|
|
{
|
|
|
case CV_8UC1:
|
|
|
|
|
|
for(int j = 0; j < ny; j ++)
|
|
|
{
|
|
|
uchar* p = mat.ptr<uchar>(j);
|
|
|
for(int i = 0; i < nx; i ++ )
|
|
|
{
|
|
|
pDstSurf->setZ(i,j,(unsigned int)p[i]);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
case CV_32FC1: //float
|
|
|
|
|
|
for(int j = 0; j < ny; j ++)
|
|
|
{
|
|
|
float* p = mat.ptr<float>(j);
|
|
|
for(int i = 0; i < nx; i ++ )
|
|
|
{
|
|
|
pDstSurf->setZ(i,j,(float)p[i]);
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
return false;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pDstSurf->CalcRange();
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
bool COutlineDetector::ConvertMatToQImage(cv::Mat & mat, QImage & image, QImage::Format fmt )
|
|
|
{
|
|
|
|
|
|
if (mat.empty()) {
|
|
|
qDebug() << "load image fail!";
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
switch (mat.type())
|
|
|
{
|
|
|
case CV_8UC1:
|
|
|
{
|
|
|
image = QImage(mat.cols, mat.rows, QImage::Format_Indexed8);
|
|
|
//set the color table
|
|
|
image.setColorCount(256);
|
|
|
for (int i = 0; i < 256; i++)
|
|
|
image.setColor(i, qRgb(i, i, i));
|
|
|
|
|
|
//copy input mat
|
|
|
uchar* pSrc = mat.data;
|
|
|
for (int row = 0; row < mat.rows; row++)
|
|
|
{
|
|
|
uchar* pDest = image.scanLine(row);
|
|
|
memcpy(pDest, pSrc, mat.cols);
|
|
|
pSrc += mat.step;
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
}
|
|
|
case CV_8UC3:
|
|
|
image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
|
|
|
image = image.rgbSwapped(); // BRG转为RGB
|
|
|
// Qt5.14增加了Format_BGR888
|
|
|
// image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.cols * 3, QImage::Format_BGR888);
|
|
|
break;
|
|
|
case CV_8UC4:
|
|
|
image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
|
|
|
break;
|
|
|
case CV_16UC4:
|
|
|
image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGBA8888);// Format_RGBA64);
|
|
|
image = image.rgbSwapped(); // BRG转为RGB
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if (!image.isNull())
|
|
|
image = image.convertToFormat(fmt);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
bool COutlineDetector::ConvertQImageToMat(const QImage &image, cv::Mat& mat)
|
|
|
{
|
|
|
|
|
|
switch (image.format())
|
|
|
{
|
|
|
case QImage::Format_Grayscale8: // 灰度图,每个像素点1个字节(8位)
|
|
|
// Mat构造:行数,列数,存储结构,数据,step每行多少字节
|
|
|
mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
|
|
|
break;
|
|
|
case QImage::Format_ARGB32: // uint32存储0xAARRGGBB,pc一般小端存储低位在前,所以字节顺序就成了BGRA
|
|
|
case QImage::Format_RGB32: // Alpha为FF
|
|
|
case QImage::Format_ARGB32_Premultiplied:
|
|
|
mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
|
|
|
break;
|
|
|
case QImage::Format_RGB888: // RR,GG,BB字节顺序存储
|
|
|
mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
|
|
|
// opencv需要转为BGR的字节顺序
|
|
|
cv::cvtColor(mat, mat, cv::COLOR_RGB2BGR);
|
|
|
break;
|
|
|
|
|
|
case QImage::Format_Indexed8:
|
|
|
mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.bits(), image.bytesPerLine());
|
|
|
break;
|
|
|
//case QImage::Format_RGBA64: // uint64存储,顺序和Format_ARGB32相反,RGBA
|
|
|
// mat = cv::Mat(image.height(), image.width(), CV_16UC4, (void*)image.constBits(), image.bytesPerLine());
|
|
|
// // opencv需要转为BGRA的字节顺序
|
|
|
// cv::cvtColor(mat, mat, cv::COLOR_RGBA2BGRA);
|
|
|
// break;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
|