OneSeg
#pragma once #include "opencv.hpp" //一条线段,有起点和终点 class COneSeg { public: COneSeg(); COneSeg(cv::Vec4d v4d); COneSeg(cv::Point2d p1, cv::Point2d p2); COneSeg(const double& x1, const double& y1, const double& x2, const double& y2); ~COneSeg(); public: double x1, y1, x2, y2; //线段的断点坐标 public: //判断两直线是否平行,定义最大误差角度 bool AngleDiffAbs(COneSeg& os, const double& dDiff = 1.0); //判断线段上是否有指定亮度的点 bool HasWhitePixs(cv::Mat& mSrcGray, const int& nBrightness = 255); //两直线的交点 bool IntersectionLine(COneSeg& os, cv::Point2d& pInter); //两线段的交点 bool IntersectionSeg(COneSeg& os, cv::Point2d& pInter); //判断是否与某个矩形区域相交 bool IsPartInRect(const cv::Rect& rect); //点是否在直线上 bool IsPointInLine(const cv::Point2d& pt, const double& dDiff = 0.01); //点是否在线段上 bool IsPointInSeg(const cv::Point2d& pt, const double& dDiff = 1.0); //判断两直线是否垂直,定义最大误差角度 bool VerAngleDiffAbs(COneSeg& os, const double& dDiff = 1.0); //获取线段的中点 cv::Point2d GetCenter(); //获取点到直线的垂线段与直线的交点 cv::Point2d GetVerticalPoint(const cv::Point2d& pt); //获取线段在某张图片中的正方形区域 cv::Rect GetSquare(const int& nImgWidth, const int& nImgHeight, const int nSideLength); //获取线段所在的最小矩形区域,定义最小宽度 cv::Rect GetRect(const int& nMinGap = 8); //获取线段在图像内部的最小矩形区域,定义最小宽度 cv::Rect GetRect(const int& nImgWidth, const int& nImgHeight, const int& nMinGap = 8); //与x轴正向的夹角,-90到+90度 double Angle(); //两条线段中点的距离 double CenterGap(COneSeg& os); //长度 double Length(); double GapFromPoint(const cv::Point2d& pt); //斜率 double Slope(); int DrawToMat(cv::Mat& mCanvas, const cv::Scalar& color = cv::Scalar(0, 0, 255), const int& thickness = 2); int Offset(const int& x, const int& y); std::string ToString(); //求线段经过的所有的图像上的点 std::vector<cv::Point> GetLinePoints(); private: double TwoPointsGap(const cv::Point2d& p1, const cv::Point2d& p2); double TwoPointsGap(const double& x1, const double& y1, const double& x2, const double& y2); }; class CSegGroup { public: CSegGroup(); ~CSegGroup(); public: std::vector<COneSeg> vOs; //计算该组线段与x轴正向的角度平均值 double GetAvgAngle(); int DrawToMat(cv::Mat& mCanvas, const cv::Scalar& color = cv::Scalar(0, 0, 255), const int& thickness = 2); private: };
#include "OneSeg.h" COneSeg::COneSeg() { } COneSeg::COneSeg(cv::Vec4d v4d) { x1 = v4d[0]; y1 = v4d[1]; x2 = v4d[2]; y2 = v4d[3]; } COneSeg::COneSeg(cv::Point2d p1, cv::Point2d p2) { x1 = p1.x; y1 = p1.y; x2 = p2.x; y2 = p2.y; } COneSeg::COneSeg(const double& x1, const double& y1, const double& x2, const double& y2) { this->x1 = x1; this->y1 = y1; this->x2 = x2; this->y2 = y2; } COneSeg::~COneSeg() { } bool COneSeg::AngleDiffAbs(COneSeg& os, const double& dDiff /*= 1.0*/) { return fabs(Angle() - os.Angle()) <= dDiff; } bool COneSeg::HasWhitePixs( cv::Mat& mSrcGray, const int& nBrightness /*= 255*/ ) { cv::LineIterator iterator(mSrcGray, cv::Point(x1, y1), cv::Point(x2, y2)); std::vector<cv::Point> vLinePts; int count = iterator.count; for(int i = 0; i < count; i++, ++iterator ) { uchar* ptr = *iterator; if (ptr[0] == nBrightness) { return true; } } return false; } bool COneSeg::IntersectionLine(COneSeg& os, cv::Point2d& pInter) { //第一条直线的参数 double a0 = y1 - y2; double b0 = x2 - x1; double c0 = x1 * y2 - x2 * y1; double x3 = os.x1; double y3 = os.y1; double x4 = os.x2; double y4 = os.y2; //第二条直线的参数 double a1 = y3 - y4; double b1 = x4 - x3; double c1 = x3 * y4 - x4 * y3; //求交点 double D = a0 * b1 - a1 * b0; if (fabs(D) < 0.00001) { //无交点 return false; } pInter.x = (b0 * c1 - b1 * c0) / D; pInter.y = (c0 * a1 - c1 * a0) / D; return true; } bool COneSeg::IntersectionSeg( COneSeg& os, cv::Point2d& pInter ) { bool bRes = IntersectionLine(os, pInter); return bRes && IsPointInSeg(pInter) && os.IsPointInSeg(pInter); } bool COneSeg::IsPartInRect(const cv::Rect& rect) { return x1 >= rect.x && x1 <= rect.x + rect.width && y1 >= rect.y && y1 <= rect.y + rect.height || x2 >= rect.x && x2 <= rect.x + rect.width && y2 >= rect.y && y2 <= rect.y + rect.height; } bool COneSeg::IsPointInLine(const cv::Point2d& pt, const double& dDiff/* = 0.01*/) { return GapFromPoint(pt) <= dDiff; } bool COneSeg::IsPointInSeg(const cv::Point2d& pt, const double& dDiff/* = 1.0*/) { //考虑到图像的特殊性,不需要斜率相同,只需要用距离判断即可 return TwoPointsGap(pt, cv::Point2d(x1, y1)) + TwoPointsGap(pt, cv::Point2d(x2, y2)) - Length() <= dDiff; } bool COneSeg::VerAngleDiffAbs(COneSeg& os, const double& dDiff /*= 1.0*/) { return fabs(Angle() - os.Angle()) >= 90.0 - dDiff && fabs(Angle() - os.Angle()) <= 90 + dDiff; } cv::Point2d COneSeg::GetCenter() { return cv::Point2d((x1 + x2) / 2, (y1 + y2) / 2); } cv::Point2d COneSeg::GetVerticalPoint(const cv::Point2d& pt) { if (Slope() == DBL_MAX) { //如果是垂直的直线 double x = x1; double y = pt.y; return cv::Point2d(x, y); } if (fabs(Slope()) <= 0.00001) { //如果是水平的直线 double x = pt.x; double y = y1; return cv::Point2d(x, y); } //四舍五入 double x = (Slope()* x1 + pt.y + 1 / Slope() * pt.x - y1) /(Slope() + 1 / Slope()); double y = Slope() * x + y1 - Slope() * x1; return cv::Point2d(x, y); } cv::Rect COneSeg::GetSquare(const int& nImgWidth, const int& nImgHeight, const int nSideLength) { cv::Point2d center = GetCenter(); int x = center.x - nSideLength / 2; int y = center.y - nSideLength / 2; int width = nSideLength; int height = nSideLength; if (x < 0) { x = 0; width = center.x + nSideLength / 2; } if (y < 0) { y = 0; height = center.y + nSideLength / 2; } if (x + width > nImgWidth) { width = nImgWidth - x; } if (y + height > nImgHeight) { height = nImgHeight - y; } return cv::Rect(x, y, width, height); } double COneSeg::Angle() { return atan(Slope()) / CV_PI * 180; } double COneSeg::Slope() { if (fabs(x1 - x2) <= 0.0001) { return DBL_MAX; } return (y1 - y2) / (x1 - x2); } double COneSeg::Length() { return sqrt((y1 - y2) * (y1 - y2) + (x1 - x2) * (x1 - x2)); } int COneSeg::DrawToMat(cv::Mat& mCanvas, const cv::Scalar& color /*= cv::Scalar(0, 0, 255)*/, const int& thickness /*= 2*/) { cv::line(mCanvas, cv::Point(x1, y1), cv::Point(x2, y2), color, thickness); return 0; } cv::Rect COneSeg::GetRect(const int& nMinGap /*= 8*/) { //只是得到矩形区域,可能为负 int x = x1 < x2 ? x1 : x2; if (abs(y2 - y1) <= nMinGap) { int y = (y1 + y2) / 2 - nMinGap / 2; int width = abs(x1 - x2); if (width <= nMinGap) { x = (x1 + x2) / 2 - nMinGap / 2; width = nMinGap; } int height = nMinGap; return cv::Rect(x, y, width, height); } else { int y = y1 < y2 ? y1 : y2; int width = abs(x1 - x2); if (width <= nMinGap) { x = (x1 + x2) / 2 - nMinGap / 2; width = nMinGap; } int height = abs(y1 - y2); return cv::Rect(x, y, width, height); } } cv::Rect COneSeg::GetRect(const int& nImgWidth, const int& nImgHeight, const int& nMinGap /*= 8*/) { cv::Rect roi = GetRect(nMinGap); if (roi.x < 0) { roi.x = 0; } if (roi.x + roi.width > nImgWidth) { roi.width = nImgWidth - roi.x; } if (roi.y < 0) { roi.y = 0; } if (roi.y + roi.height > nImgHeight) { roi.height = nImgHeight - roi.y; } return roi; } double COneSeg::CenterGap(COneSeg& os) { cv::Point2d p1 = GetCenter(); cv::Point2d p2 = os.GetCenter(); return TwoPointsGap(p1, p2); } double COneSeg::GapFromPoint(const cv::Point2d& pt) { double k = Slope(); if (k == DBL_MAX) { //垂直的时候直接返回差值 return fabs(x1 - pt.x); } double b = y1 - k * x1; return fabs(k * pt.x - pt.y + b) / sqrt( 1 + k * k); } CSegGroup::CSegGroup() { } CSegGroup::~CSegGroup() { } double CSegGroup::GetAvgAngle() { double dSum = 0; for (int i = 0; i < vOs.size(); ++i) { dSum += vOs[i].Angle(); } return dSum / vOs.size(); } int CSegGroup::DrawToMat(cv::Mat& mCanvas, const cv::Scalar& color /*= cv::Scalar(0, 0, 255)*/, const int& thickness /*= 2*/) { for (int i = 0; i < vOs.size(); ++i) { vOs[i].DrawToMat(mCanvas, color, thickness); } return vOs.size(); } int COneSeg::Offset(const int& x, const int& y) { x1 += x; y1 += y; x2 += x; y2 += y; return 0; } std::string COneSeg::ToString() { std::string sCoors, sTmp; std::stringstream ss1, ss2, ss3, ss4; ss1 << x1; ss1 >> sTmp; sCoors += "x1 = "; sCoors += sTmp + " "; ss2 << y1; ss2 >> sTmp; sCoors += "y1 = "; sCoors += sTmp + " "; ss3 << x2; ss3 >> sTmp; sCoors += "x2 = "; sCoors += sTmp + " "; ss4 << y2; ss4 >> sTmp; sCoors += "y2 = "; sCoors += sTmp + " "; return sCoors; } std::vector<cv::Point> COneSeg::GetLinePoints() { std::vector<cv::Point> vOutput; int width = MAX(x1, x2) + 1; int height = MAX(y1, y2) + 1; cv::Mat image(cv::Size(width, height), CV_8UC1); cv::LineIterator iterator(image, cv::Point(x1, y1), cv::Point(x2, y2)); int count = iterator.count; for (int i = 0; i < count; i++) { /* print the pixel coordinates: demonstrates how to calculate the coordinates */ { int offset, x, y; /* assume that ROI is not set, otherwise need to take it into account. */ offset = iterator.ptr - (uchar*)(image.data); y = offset / image.step; x = (offset - y*image.step) / (sizeof(uchar)/* size of pixel */); vOutput.push_back(cv::Point(x, y)); } iterator++; } return vOutput; } double COneSeg::TwoPointsGap(const cv::Point2d& p1, const cv::Point2d& p2) { return TwoPointsGap(p1.x, p1.y, p2.x, p2.y); } double COneSeg::TwoPointsGap(const double& x1, const double& y1, const double& x2, const double& y2) { return sqrt((y1 - y2) * (y1 - y2) + (x1 - x2) * (x1 - x2)); }