[C++] 纯文本查看 复制代码
double IsDefAreaEx(unsigned char* pBuffer, const int& nDetectIndex, CAreaLinesEx* pInput, CAreaLinesEx* pSample /*= nullptr*/, double lfGSD /*= 1.0*/)
{
//输出用
double dResult = 0.0;
int nPartialRGBIndex = pInput->GetPartialRGB();
//获得基础参数
double dArea = pInput->GetArea();
double dRectArea = pInput->BoundingRectArea();
double dVariance = pInput->GetVarianceRef();
if (dArea < 1e-5 || dRectArea < 1e-5)
{
return 0.0;
}
//计算区域的部分参数
CAreaLinesEx ale(*pInput); //必须备份,不然会改变原来的值
CAreaRect arc = ale.GetBoundingRect();
int left = arc.left;
int down = arc.down;
int buffer_width = arc.Width();
int buffer_height = arc.Height();
if (buffer_width > 10000 || buffer_height > 10000)
{
return dResult;
}
std::vector<std::vector<cv::Point>> vContours;
//当前区域索引
int nFindIndex = -1;
//直方图统计的宽度
double dHistWidth = 1.0;
//区域边界,检测直线的数目
int nFindLines = 0;
std::vector<cv::Vec4i> lines;
//绿植无需检测
if (nDetectIndex != 1)
{
//偏移区域
ale.Offset(-arc.left, -arc.down, true);
memset(pBuffer, 0, buffer_width * buffer_height * sizeof(unsigned char));
ale.WriteBoundBuffer(pBuffer, buffer_width, buffer_height);
cv::Mat mSrcGray = COpencvUser::TransBufferToMat(pBuffer, buffer_width, buffer_height, 1, 1, false);
//外扩两个像素,方便检测边缘直线
cv::Mat mSrcGrayExpand = cv::Mat::zeros(cv::Size(mSrcGray.cols + 4, mSrcGray.rows + 4), mSrcGray.type());
mSrcGray.copyTo(mSrcGrayExpand(cv::Rect(2,2, mSrcGray.cols, mSrcGray.rows)));
mSrcGray = mSrcGrayExpand;
size_t nAreaCount = COpencvUser::GetContours(mSrcGray.clone(), vContours);
if (nAreaCount)
{
double dMaxArea = 0.0;
for (size_t i = 0; i < nAreaCount; ++i)
{
if (vContours[i].size() < 4)
{
continue;
}
double dContourArea = cv::contourArea(vContours[i]);
if (nFindIndex != -1)
{
if (dContourArea > dMaxArea)
{
dMaxArea = dContourArea;
nFindIndex = i;
}
}
else
{
dMaxArea = dContourArea;
nFindIndex = i;
}
}
}
//在区域中搜寻直线
//cv::Mat mShow;
//const int nRProp = 3;
//cv::resize(mSrcGray, mShow, cv::Size(mSrcGray.cols * nRProp, mSrcGray.rows * nRProp));
//cv::imshow("D:\\hough.tif", mShow);
cv::Canny(mSrcGray, mSrcGray, 100.0, 200.0);
//cv::resize(mSrcGray, mShow, cv::Size(mSrcGray.cols * nRProp, mSrcGray.rows * nRProp));
//cv::imshow("D:\\canny.tif", mShow);
nFindLines = (int)COpencvUser::HoughLinesProb(mSrcGray.clone(), lines, 15, 2 / lfGSD, 0);
//cv::Mat mSrcBGR;
//cv::cvtColor(mSrcGray, mSrcBGR, CV_GRAY2BGR);
//COpencvUser::HoughLinesShow(mSrcBGR, lines);
//cv::resize(mSrcBGR, mShow, cv::Size(mSrcGray.cols * nRProp, mSrcGray.rows * nRProp));
//cv::imshow("D:\\lines.tif", mShow);
//cv::waitKey();
//求得截断长度
if (nFindIndex != -1 && vContours[nFindIndex].size() > 4)
{
cv::RotatedRect roRc = cv::fitEllipse(vContours[nFindIndex]);
double dAngle = roRc.angle;
//cv::imwrite("D:\\area.tif", mSrcGray);
cv::Point2f VerPts[4];
roRc.points(VerPts);
double dGap1 = sqrt((VerPts[0].x - VerPts[1].x)*(VerPts[0].x - VerPts[1].x) + (VerPts[0].y - VerPts[1].y)*(VerPts[0].y - VerPts[1].y));
double dGap2 = sqrt((VerPts[1].x - VerPts[2].x)*(VerPts[1].x - VerPts[2].x) + (VerPts[1].y - VerPts[2].y)*(VerPts[1].y - VerPts[2].y));
#ifdef OUTPUT_LINE_IMG
cv::Mat mLineBGR;
cv::cvtColor(mSrcGray, mLineBGR, CV_GRAY2BGR);
cv::RNG rng;
for (size_t i = 0; i < 4; ++i)
{
cv::Point p1 = VerPts[i];
cv::Point p2 = VerPts[(i + 1) % 4];
cv::line(mLineBGR, p1, p2, cv::Scalar(rng.uniform(0.0, 255.0),rng.uniform(0.0, 255.0),rng.uniform(0.0, 255.0)));
}
cv::imwrite("D:\\areaR.tif", mLineBGR);
static int nTimes = 0;
nTimes++;
#endif // OUTPUT_LINE_IMG
cv::Rect bdRc = roRc.boundingRect();
if (dGap1 > 10.0)
{
//用得到的角度,切多边形,得到的线段宽度,求直方图统计值,中间的80%的数据的平均值
CSegment sg(VerPts[0].x, VerPts[0].y, VerPts[1].x, VerPts[1].y);
std::vector<POINT32F> vRasterPts = sg.Raster(2.0); //以像素为单位
std::vector<CSegment> vGapLines;
for (size_t i = 0; i < vRasterPts.size(); ++i)
{
double a = 0.0, b = 0.0, c = 0.0;
CSegment::CalcLineABC(dAngle, vRasterPts[i].x, vRasterPts[i].y, a, b, c);
POINT32F pt1, pt2;
CSegment::IsLineInterRect(a, b, c, MyRect(bdRc.x, bdRc.y, bdRc.width, bdRc.height), pt1, pt2);
CSegment sgCut(pt1, pt2);
std::vector<POINT32F> vRasterCutPts = sgCut.Raster();
bool bFindStart = false;
POINT32F ptStart, ptEnd;
size_t nRasterCutPtCount = vRasterCutPts.size();
for (size_t j = 0; j < nRasterCutPtCount; ++j)
{
if (cv::pointPolygonTest(vContours[nFindIndex], cv::Point2f(vRasterCutPts[j].x, vRasterCutPts[j].y), false) >= 0)
{
if (!bFindStart)
{
bFindStart = true;
ptStart = vRasterCutPts[j];
}
if (bFindStart && j == nRasterCutPtCount - 1)
{
ptEnd = vRasterCutPts[j];
vGapLines.push_back(CSegment(ptStart, ptEnd));
}
}
else
{
if (bFindStart)
{
ptEnd = vRasterCutPts[j];
vGapLines.push_back(CSegment(ptStart, ptEnd));
bFindStart = false;
}
}
}
}
std::multimap<double, int> mdiGap;
for (size_t j = 0; j < vGapLines.size(); ++j)
{
double leng = vGapLines[j].Length();
mdiGap.insert(std::make_pair(leng, j));
#ifdef OUTPUT_LINE_IMG
cv::line(mLineBGR, cv::Point(vGapLines[j].x1, vGapLines[j].y1), cv::Point(vGapLines[j].x2, vGapLines[j].y2),
cv::Scalar(rng.uniform(0.0, 255.0),rng.uniform(0.0, 255.0),rng.uniform(0.0, 255.0)));
#endif // OUTPUT_LINE_IMG
}
//转换map为vector
std::vector<double> vLength;
size_t nLineCount = mdiGap.size();
vLength.reserve(nLineCount);
for (auto it = mdiGap.begin(); it != mdiGap.end(); ++it)
{
vLength.push_back(it->first);
}
size_t idxStart = nLineCount * 0.1;
size_t idxEnd = nLineCount * 0.9;
double dHistLength = 0.0;
for (size_t j = idxStart; j < idxEnd; ++j)
{
dHistLength += vLength[j];
}
dHistLength /= idxEnd - idxStart + 1;
dHistWidth = dHistLength * lfGSD;
//此时,更新旋转矩形信息
pInput->m_ri.bUseful = true;
pInput->m_ri.dHistLength = dHistLength;
pInput->m_ri.dRotateRectLength = dGap1;
pInput->m_ri.dRotateRectWidth = dGap2;
pInput->m_ri.nHistLengthCount = idxEnd - idxStart + 1;
}
else
{
dHistWidth = MIN(dGap1, dGap2) * lfGSD;
//此时,更新旋转矩形信息
pInput->m_ri.bUseful = true;
pInput->m_ri.dHistLength = MIN(dGap1, dGap2);
pInput->m_ri.dRotateRectLength = dGap1;
pInput->m_ri.dRotateRectWidth = dGap2;
pInput->m_ri.nHistLengthCount = MAX(dGap1, dGap2);
}
#ifdef OUTPUT_LINE_IMG
cv::imwrite("D:\\areaL.tif", mLineBGR);
#endif // OUTPUT_LINE_IMG
}
}
switch (nDetectIndex)
{
case DETECT_HOUSE:
{
//房屋,必须存在至少一组平行或者垂直的线段
size_t nPPLines = ParallelOrPerpendLines(lines);
if (nPPLines > 0)
{
//如果检测多组直角,并且他们能够对应起来(平行或者垂直),则更容易是房屋,提高可能性
//房屋的实际面积
double dRealArea = dArea * lfGSD * lfGSD;
double dAreaProbablity = 1.0;
double dHouseWidthProb = 1.0;
double dLengthWidthProb = 1.0;
double dVarianceProb = 1.0;
//房屋面积在10-200的范围外,则降低其可能性
if (dRealArea < 10.0)
{
dAreaProbablity = dRealArea / 10.0;
}
else if (dRealArea > 200.0)
{
dRealArea = 1000.0 / dRealArea;
}
double dGrayValueProb = 1.0;
//如果亮度小于30,则越小越不可能是房子
std::vector<uchar> vRGB = CAreaLinesEx::VectorHSV2RGB(ale.GetAvgHSVRef());
uchar uValue = (vRGB[0] + vRGB[1] + vRGB[2]) / 3;
if (uValue < 30)
{
dGrayValueProb = uValue / 30.0;
}
if (nFindIndex != -1 && vContours[nFindIndex].size() > 4)
{
cv::RotatedRect roRc = cv::fitEllipse(vContours[nFindIndex]);
cv::Point2f VerPts[4];
roRc.points(VerPts);
double dGap1 = sqrt((VerPts[0].x - VerPts[1].x)*(VerPts[0].x - VerPts[1].x) + (VerPts[0].y - VerPts[1].y)*(VerPts[0].y - VerPts[1].y));
double dGap2 = sqrt((VerPts[1].x - VerPts[2].x)*(VerPts[1].x - VerPts[2].x) + (VerPts[1].y - VerPts[2].y)*(VerPts[1].y - VerPts[2].y));
double droRcArea = dGap1 * dGap2;
//旋转矩形占比
double dAreaRectProb = dArea / droRcArea;
if (dAreaRectProb < 0.2)
{
return dResult;
}
//房屋宽度不应该介于一定的范围
if (dHistWidth < 1.0)
{
dHouseWidthProb = dHistWidth / 1.0;
}
else if (dHistWidth > 10.0)
{
dHouseWidthProb = 10.0 / dHistWidth;
}
//如果区域的长度和宽度的比值过大,则降低可能性
double dLengWidthProp = dGap1 * lfGSD / dHistWidth;
if (dLengWidthProp > 5.0)
{
dLengthWidthProb = 5.0 / dLengWidthProp;
}
//CLOG::Out(_T("dLengthWidthProb = %lf"), dLengthWidthProb);
dResult = dAreaRectProb * dAreaProbablity * dHouseWidthProb /** dLengthWidthProb*/;
//直接增加概率
if (dResult < 0.5 && nPPLines > 1)
{
dResult += 0.5;
}
return dResult;
}
//正矩形占比
return (dArea / dRectArea) * dAreaProbablity * dHouseWidthProb * dGrayValueProb;
}
}
break;
case DETECT_GREEN:
{
//绿植
if (nPartialRGBIndex == 1 && dVariance > 60.0)
{
//可以增加平行直线的检测
return 1.0;
}
}
break;
case DETECT_WATER:
{
//水域
if (nPartialRGBIndex != -1)
{
return dResult;
}
//水域方差通常较小,而面积比较大,截断距离也较大
double dVarianceProb = 1.0;
if (dVariance > 20.0)
{
dVarianceProb = 20 / dVariance;
}
//面积,小于40则降低可能性
//水域的实际面积
double dRealArea = dArea * lfGSD * lfGSD;
double dAreaProbablity = 1.0;
//水域面积,优先考虑40.0以上的区域
if (dRealArea < 40.0)
{
dAreaProbablity = dRealArea / 40.0;
}
//水域的截断长度,通常较大
double dHistWidthProb = 1.0;
//截断宽度如果小于30m,则降低可能性
if (dHistWidth < 30.0)
{
dHistWidthProb = dHistWidth / 30.0;
}
return dVarianceProb * dAreaProbablity * dHistWidthProb;
}
break;
case DETECT_ROAD:
{
if (nPartialRGBIndex != -1 || nFindLines < 2)
{
return dResult;
}
//至少存在一条接近平行的线段组
std::vector<cv::Vec4i> vParaLines = ParallelLines(lines);
size_t nParaLineCount = vParaLines.size();
if (nParaLineCount == 0)
{
return dResult;
}
//判断检测到的直线中,至少存在两条直线接近平行
double dSumLength = 0.0;
for (size_t i = 0; i < nParaLineCount; ++i)
{
dSumLength += V4iLength(vParaLines[i]);
}
double dRealLength = dSumLength * lfGSD / nParaLineCount;
//道路检测到的平行直线组长度和
double dLengthProb = 1.0;
if (dRealLength < 10)
{
dLengthProb = dRealLength / 10;
}
//道路宽度比重
double dWidthProbability = 1.0;
//区域面积和外界旋转矩形的面积比
double dAreaPropProbablity = 1.0;
//旋转矩形的宽高比例
double drcLengthProb = 1.0;
double dLengWidthPropProbility = 1.0;
if (nFindIndex != -1 && vContours[nFindIndex].size() > 4)
{
cv::RotatedRect roRc = cv::fitEllipse(vContours[nFindIndex]);
cv::Point2f VerPts[4];
roRc.points(VerPts);
double dGap1 = sqrt((VerPts[0].x - VerPts[1].x)*(VerPts[0].x - VerPts[1].x) + (VerPts[0].y - VerPts[1].y)*(VerPts[0].y - VerPts[1].y));
double dGap2 = sqrt((VerPts[1].x - VerPts[2].x)*(VerPts[1].x - VerPts[2].x) + (VerPts[1].y - VerPts[2].y)*(VerPts[1].y - VerPts[2].y));
double droRcArea = dGap1 * dGap2;
dAreaPropProbablity = 1 - dArea / droRcArea;
//需要重新求得道路的统计宽度
double dLength = MAX(dGap1, dGap2) * lfGSD;
double dLengWidthProp = MAX(dGap1, dGap2) / dHistWidth;
if (dLength < 50.0)
{
drcLengthProb = dLength / 50.0;
}
//如果小于1m则减小可能性
if (dHistWidth < 1.0)
{
dWidthProbability = dHistWidth;
}
else if (dHistWidth > 20.0)
{
dWidthProbability = 20.0 / dHistWidth;
}
//长宽比例越长,越可能是道路
if (dLengWidthProp < 3.0)
{
dLengWidthPropProbility = dLengWidthProp / 3.0;
}
}
#ifdef PROBABLITY_LOG
//输出各概率到log
CLOG::Out(_T("dLengthProb = %f dWidthProbability = %f dAreaPropProbablity = %f drcLengthProb = %f dLengWidthPropProbility = %f IsRoadArea = %f"),
dLengthProb, dWidthProbability, dAreaPropProbablity, drcLengthProb, dLengWidthPropProbility, pInput->IsRoadArea(pSample, lfGSD));
#endif // PROBABLITY_LOG
return dLengthProb * dWidthProbability * dAreaPropProbablity * drcLengthProb * dLengWidthPropProbility * pInput->IsRoadArea(pSample, lfGSD);
}
break;
default:
break;
}
return dResult;
}