这是一种在数据中搜索路径的“蛮力”方式。它没有回溯,所以如果有死胡同(可能是宽度大于 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;
}
给出这个可视化的结果:
这些点位于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