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));
}
原文地址:https://www.cnblogs.com/autumoonchina/p/7088282.html