Acquisition of all points within the opencv contour

background:

        There is a demand point in the project, which involves two modules, A and B

A:

        Draw an ROI in the image area, which may be of any shape, and then A will pass some points of the contour to module B, and let B calculate the parameters

B:

        Get all point data in this ROI

Now think of two ways to implement this module

Common to both approaches:

        Since the points provided by A may be discontinuous, an interpolation may be required. Of course, this can be done or not, depending on the specific error requirements

Interpolation basic logic        

struct CvPointCompare
{
    template<typename T> bool operator()(const T &p1, const T &p2)
    {
        return (fabs(static_cast<float>(p1.x - p2.x)) < 0.0001f) ? (p1.y < p2.y) : (p1.x < p2.x);
    }
};

// 输入点集合,得到闭合线或者非闭合线
void GetLineByPoints(const std::vector<CvPoint> &Pt, bool bIsCircle, std::set<cv::Point2f, CvPointCompare> &sLine)
{
    sLine.clear(); // 清除集合中的元素
    int iSum = Pt.size();

    if (iSum > 0)
    {
        if (bIsCircle) // 环形的时候
        {
            for (int i = 0; i < iSum; i++)
            {
                ((iSum - 1) == i) ? GetLineByTwoPoints(Pt[iSum - 1], Pt[0], sLine) : GetLineByTwoPoints(Pt[i], Pt[i + 1], sLine);
            }
        }
        else  // 非环形的时候
        {
            for (int i = 0; i < iSum - 1; i++)
            {
                GetLineByTwoPoints(Pt[i], Pt[i + 1], sLine);
            }
        }
        
        sLine.insert(cvPointTo32f(Pt.back())); // 插入最后一个点(防止遗漏,非闭合跟只有一个点的时候会出现遗漏)
    }
    
}


void GetTraceSelectedPoints(std::vector<CvPoint> &vBoundaryArea, std::vector<CvPoint> &vArea)
{
    // 需要自定义排序
    std::set<cv::Point2f, CvPointCompare> sOutLine; // 轮廓点集合

    GetLineByPoints(vBoundaryArea, true, sOutLine); // 获取插值后的轮阔点集合

}

and then follow up

Method 1: Test if each point is inside the region

 Basic logic:

void GetTraceSelectedPoints(std::vector<CvPoint> &vBoundaryArea, std::vector<CvPoint> &vArea)
{
    // 需要自定义排序
    std::set<cv::Point2f, CvPointCompare> sOutLine; // 轮廓点集合

    GetLineByPoints(vBoundaryArea, true, sOutLine); // 获取插值后的轮阔点集合


    // 计算轮廓内所有点
    std::vector<cv::Point2f> vTmp(sOutLine.begin(), sOutLine.end()); // 转存到容器(set已经实现了排序过程)
    
    float fMinY = vTmp.front().y;
    float fMaxY = vTmp.front().y;
    for (cv::Point2f &pt : vTmp)
    {
        if (pt.y > fMaxY)
        {
            fMaxY = pt.y;
        }
        else if (pt.y < fMinY)
        {
            fMinY = pt.y;
        }
    }

    CvPoint LeftTop   = cvPointFrom32f(cvPoint2D32f(vTmp.front().x, fMinY));
    CvPoint RightDown = cvPointFrom32f(cvPoint2D32f(vTmp.back().x, fMaxY));
    vArea.clear();
    
    for (int y = LeftTop.y; y <= RightDown.y; y++)
    {
        for (int x = LeftTop.x; x <= RightDown.x; x++)
        {
            cv::Point2f PCur = cvPoint2D32f(x, y);
            if (!(pointPolygonTest(vTmp, PCur, false) < 0)) // 判断当前点是否在轮廓内
            {
                vArea.push_back(cvPointFrom32f(PCur));
            }
        }
    }

}

Method 2: directly get back to the internal point of the contour

int main()
{
	std::vector<uint8_t> v_data(500 * 500, 0);
	cv::Mat cv_back_end = cv::Mat(500, 500, CV_8UC1, v_data.data());

    // 这个位置就是模拟前面插值后的轮廓点
    std::vector<std::vector<cv::Point>> v_points = { {cv::Point(98, 2), cv::Point(40, 40), cv::Point(2, 98),   cv::Point(98, 98) } };
    
    //直接将轮廓内的所有点绘制在back_end上,这里的关键点就是thickness参数(最后一个参数)设置成了-1,设置成-1,opencv就会将轮廓内填充起来
    cv::drawContours(cv_back_end, v_points, -1, cv::Scalar(255), -1);

}

Guess you like

Origin blog.csdn.net/bocai1215/article/details/130101729