Как обнаружить 2 пересекающихся (перекрещенных) кривых, используя opencv или python? - PullRequest
0 голосов
/ 23 октября 2019

Учитывая изображение с 2 пересекающимися кривыми, как показано на изображении ниже, как я могу обнаружить и различить 2 кривые, используя opencv или python? (поэтому мне нужно 2 отдельных кривых)

enter image description here

1 Ответ

1 голос
/ 23 октября 2019

вы можете отсканировать каждый столбец и идентифицировать кластеры там из связанных частей.

псевдоалгоритм:

list of curves
for each column
    if a pixel region is black, surrounded by white
        add it to the list of curves for which it continues the curve best

самая сложная часть - как определить, как продолжается уже заданная криваяЛучший. Если вы просто выберете расстояние до ближайшей точки кривой, у вас возникнут проблемы на перекрестке. Создание линии от предыдущей к последней точке кривой до новой точки и измерение расстояния до последней точки кривой работали достаточно хорошо. Однако из-за измерения очень малых расстояний (возможно, из-за проблем с округлением и т. Д.) Я выполнял не все столбцы, а только каждый 5-й столбец.

enter image description here

C ++ код здесь:

double distance_to_Line(cv::Point line_start, cv::Point line_end, cv::Point point)
{
    double normalLength = _hypot(line_end.x - line_start.x, line_end.y - line_start.y);
    double distance = (double)((point.x - line_start.x) * (line_end.y - line_start.y) - (point.y - line_start.y) * (line_end.x - line_start.x)) / normalLength;
    return abs(distance);
}

int main()
{
    cv::Mat in = cv::imread("C:/StackOverflow/Input/splitCurves.png", cv::IMREAD_GRAYSCALE);

    std::vector<std::vector <cv::Point2f> > clusters;
    float maxDist = 10.0f; //heuristic

    // looping like this is quite expensive, but we need to scan column-wise
    // will be cheaper to first transpose the image and then scan row-wise!!
    for (int x = 0; x < in.cols; x+=5)
    {
        bool active = false;
        cv::Point2f cCluster;
        int cClusterSupportSize = 0;
        for (int y = 0; y < in.rows; ++y)
        {
            cv::Point2f cPoint = cv::Point2f(x, y);
            bool cActive = in.at<unsigned char>(y,x) == 0; // is the pixel black?
            if (cActive)
            {
                cCluster += cPoint;
                cClusterSupportSize += 1;
                active = cActive;
            }

            if (active && !cActive)
            {
                // creating cluster:
                cv::Point2f finishedCluster = 1.0f / cClusterSupportSize * cCluster;

                cCluster = cv::Point2f();
                cClusterSupportSize = 0;
                active = false;

                // adding cluster to list
                int bestCluster = -1;
                float bestDist = FLT_MAX;
                for (int i = 0; i < clusters.size(); ++i)
                {
                    float distToClusters = FLT_MAX;

                    // compute dist from apprximating a line through the last two points of the curve
                    // special case: no 2 points yet:
                    if (clusters[i].size() == 1)
                    {
                        float cDist = cv::norm(finishedCluster - clusters[i].back());
                        if (cDist < distToClusters) distToClusters = cDist;
                    }
                    else
                    {
                        // test continuity by testing whether adding the new point would make the last point still be placed well on the curve
                        cv::Point2f lineA = clusters[i][clusters[i].size() - 1];
                        cv::Point2f lineB = clusters[i][clusters[i].size() - 2];
                        //cv::Point2f lineB = finishedCluster;
                        // get dist from the current point to that line:

                        float cDist =  distance_to_Line(lineA, lineB, finishedCluster);
                        if (cDist < distToClusters) distToClusters = cDist;
                    }



                    /*
                    for (int j = 0; j < clusters[i].size(); ++j)
                    {
                        // get dist to the curve
                        cv::Point2f lineA = 
                        //float cDist = cv::norm(finishedCluster - clusters[i][j]);
                        if (cDist < distToClusters) distToClusters = cDist;
                    }
                    */

                    if (distToClusters < maxDist)
                    {
                        if (distToClusters < bestDist)
                        {
                            bestDist = distToClusters;
                            bestCluster = i;
                        }
                    }
                }

                if (bestCluster < 0)
                {
                    std::vector<cv::Point2f> newCluster;
                    newCluster.push_back(finishedCluster);
                    clusters.push_back(newCluster);
                }
                else
                {
                    clusters[bestCluster].push_back(finishedCluster);
                }

            }

        }
    }

    cv::Mat out;
    cv::cvtColor(in, out, cv::COLOR_GRAY2BGR);
    for (int i = 0; i < clusters.size(); ++i)
    {
        cv::Scalar color = cv::Scalar(i*rand() % 255, (i+2)*rand() % 255, (i+1) * 100);
        if (i == 0) color = cv::Scalar(0, 255, 0);
        if (i == 1) color = cv::Scalar(0, 0, 255);
        for (int j = 1; j < clusters[i].size(); ++j)
        {
            cv::line(out, clusters[i][j - 1], clusters[i][j], color, 2);
        }
    }
    cv::imwrite("C:/StackOverflow/Input/splitCurves_out.png", out);
    cv::imshow("out", out);
    cv::waitKey(0);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...