我怎么能根据图像中的蛇纹来对坐标进行排序?

时间:2018-03-26 14:47:42

标签: python sorting opencv scikit-learn scikit-image

在下面的二进制图像中,

enter image description here

我已经能够得到坐标列表,其中值为1.

坐标从从左到右存储。

问题: 我怎样才能对坐标列表进行排序,使它们一个接一个地出现,并且它们遵循蛇形路径?

源代码:

from __future__ import division
import numpy as np

import cv2



from skimage.morphology import skeletonize, skeletonize_3d, medial_axis
diff = cv2.imread('img.png', 0)   
diff = diff.astype('uint8')

ret, thresh = cv2.threshold(diff, 1, 255, cv2.THRESH_BINARY)
thresh = cv2.dilate(thresh, None, iterations = 1)



sk = skeletonize_3d(thresh)


pixels = np.argwhere(sk==255)
pixels = np.asarray(pixels)

y = pixels[:,0]
x = pixels[:,1]

L = (x, y) # Question: How can I sort L?

np.savetxt("C:/test.csv", np.c_[L], delimiter = ',', fmt='%f')

任何想法我怎么可能这样做并根据蛇形排序L?

2 个答案:

答案 0 :(得分:5)

这是一种在数据中搜索路径的“强力”方式。它没有反向跟踪,所以如果有死角(也许是宽度大于1的线),它将无法找到“更好”的路径。

不幸的是C ++代码,但非常简单:

int main(int argc, char* argv[])
{
    cv::Mat inputBGR = cv::imread("C:/StackOverflow/Input/serpentine.png");
    if (inputBGR.empty()) return 0;

    cv::Mat input; // mask
    cv::cvtColor(inputBGR, input, CV_BGR2GRAY);

    cv::Mat mask = input.clone(); // keep the original mask. "input" will be modified during processing.

    cv::Point currentPoint = cv::Point(input.cols, input.rows);
    // find most top-left point:
    cv::Point origin(0, 0);
    for (int y = 0; y < input.rows; ++y)
        for (int x = 0; x < input.cols; ++x)
        {
            cv::Point cPoint = cv::Point(x, y);
            if (input.at<unsigned char>(cPoint))
            if (cv::norm(origin - cPoint) < cv::norm(origin - currentPoint)) // can be optimized by re-using temporary results
            {
                currentPoint = cPoint;
            }
        }

    // now find the path
    std::vector<cv::Point> path;

    // add first point:
    path.push_back(currentPoint);
    input.at<unsigned char>(currentPoint) = 0; // invalidate all used points

    while (true)
    {
        bool foundNeighbor = false;
        for (int y = -1; y <= 1; ++y)
        {
            for (int x = -1; x <= 1; ++x)
            {
                if (y != 0 || x != 0)
                {
                    cv::Point cPoint = currentPoint + cv::Point(x, y);
                    if (cPoint.x < 0 || cPoint.x >= input.cols || cPoint.y < 0 || cPoint.y >= input.rows) continue; // skip points outside of the image

                    /*
                    inputBGR.at<cv::Vec3b>(cPoint) = cv::Vec3b(0,255,0);
                    cv::imshow("debug", inputBGR);
                    cv::waitKey(0);
                    inputBGR.at<cv::Vec3b>(cPoint) = cv::Vec3b(255, 255, 255);
                    */

                    if (input.at<unsigned char>(cPoint))
                    {
                        currentPoint = cPoint;
                        path.push_back(cPoint);
                        input.at<unsigned char>(currentPoint) = 0; // invalidate all used points
                        foundNeighbor = true;
                    }
                }
                if (foundNeighbor) break; // restart on new current point
            }
            if (foundNeighbor) break; // restart on new current point
        }

        if (!foundNeighbor) break; // no more points in path...
    }

    // generate colored output
    cv::Mat output = cv::Mat::zeros(inputBGR.size(), CV_8UC1);

    // color the path...
    float nPoints = path.size();
    for (unsigned int i = 0; i < path.size(); ++i)
    {
        float posRel = i / nPoints;
        unsigned char val = 255 * posRel;
        output.at<unsigned char>(path[i]) = val;
    }

    // color code the path from blue to red
    cv::applyColorMap(output, output, cv::COLORMAP_JET);
    output.setTo(cv::Scalar::all(0), 255-mask);


    cv::imshow("output", output);
    cv::waitKey(0);
    return 0;
}

给出这个可视化结果:

enter image description here

这些点位于path变量中。

这是伪代码:

0. search/select a starting point A
1. create a directed list P to construct the path
2. create a memory M to remember which points were already observerd
3. maintain current point C, initialized with A
4. while end not found:
    4.1. for each pixel in direct neighborhood (3x3 region without the center point) with coordinates (x,y)
        4.1.1. if the pixel is white and (x,y) is not yet in M:
            4.1.1.1.  add (x,y) to M
            4.1.1.2.  set C to (x,y)
            4.1.1.3.  add (x,y) to P
            4.1.1.4.  go on with 4.
        4.1.2. if no pixel is white or all the white pixel's coordinates are already in M
            4.1.2.1.  end is found

答案 1 :(得分:0)

您可以在cv2(cv2.findContours)中使用findContours函数。如果您不习惯pyopencv,可能会有点棘手,但下面的代码提取使用了您问题中的图像(使用python2.7)。

import cv2

im = cv2.imread('/home/kola/temp/serpentine.png')# change path as necessary
im2 = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY);
contours = cv2.findContours(im2,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
contour = contours[0][0]
# use this section if you want to animate the ploting of the contour
# WARNING - can be slow!!!
import matplotlib.pyplot as plt
plt.ion()
plt.gca().set_xlim(0,im2.shape[1])
plt.gca().set_ylim(im2.shape[0],0)
plt.gca().set_aspect('equal')
plt.ion()
for c in contour:
    plt.plot(c[0][0],c[0][1],'*')
    plt.pause(0.001)