距离变换工作原理咨询及代码错误修正请求
Hey there! Let's walk through how the Borgefors distance transform (for approximating Euclidean distance) works, then fix that frustrating all-zero output issue you're facing.
Borgefors距离变换(欧几里得近似)工作原理
The Borgefors method is a super efficient way to compute approximate Euclidean distances using integer arithmetic—no slow floating-point operations needed. It relies on two passes of template-based neighborhood checks:
- Forward Pass: Traverse the image from top-left to bottom-right. For each pixel, update its distance value using a forward-weighted template, taking the minimum distance from its top-left neighboring pixels plus the template's corresponding weight.
- Backward Pass: Traverse the image from bottom-right to top-left. Use a backward-weighted template to refine the distance values, this time checking the bottom-right neighbors to catch any smaller distances missed in the forward pass.
- The final values are integer approximations of Euclidean distances; you can divide by a scaling factor (like 5, the base weight in the template) to get values closer to true Euclidean distances.
Your Code Issues & Fixes
Looking at your code snippet, there are a few key problems causing the all-zero output:
- Invalid Template Definitions: Your
forwardtemplate has most rows set to 0, which means no weight values are being applied to update distances. The Borgefors templates need proper integer weights that map to distance approximations. - Uninitialized Distance Matrix: You didn't set up a result matrix with initial values (like a large maximum value for background pixels, 0 for foreground pixels)—without this, there's no basis for computing distances.
- Missing Traversal Logic: You defined templates but didn't implement the forward/backward traversal to apply them.
Here's the corrected, complete code with explanations:
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char* argv[]) { // Read input binary image (assuming foreground is 0, background is 255) Mat img = imread("ref.png", 0); if (img.empty()) { cerr << "Oops, couldn't read the image! Check the file path." << endl; return -1; } imshow("Input", img); // Initialize distance matrix: set foreground pixels to 0, background to max int value Mat dist(img.size(), CV_32S); dist = Scalar(INT_MAX); for (int i = 0; i < img.rows; i++) { for (int j = 0; j < img.cols; j++) { if (img.at<uchar>(i, j) == 0) { // Adjust this if your foreground is 255 instead dist.at<int>(i, j) = 0; } } } // Correct Borgefors forward template (5x5 integer weights for Euclidean approximation) // Weights map to: 5=1 unit,7=√2≈1.414,11=2 units Mat forward = (Mat_<int>(5, 5) << 0, 11, 0, 11, 0, 11, 7, 5, 7, 11, 0, 5, 0, 5, 0, 11, 7, 5, 7, 11, 0, 11, 0, 11, 0); // Backward template is symmetric to forward, so we can just clone it Mat backward = forward.clone(); int half_template = forward.rows / 2; // Forward pass: top-left to bottom-right for (int i = half_template; i < img.rows - half_template; i++) { for (int j = half_template; j < img.cols - half_template; j++) { if (dist.at<int>(i, j) == 0) continue; // Skip foreground pixels int min_dist = dist.at<int>(i, j); // Check all template positions for (int di = -half_template; di <= half_template; di++) { for (int dj = -half_template; dj <= half_template; dj++) { int weight = forward.at<int>(di + half_template, dj + half_template); if (weight == 0) continue; // Skip positions with no weight int neighbor_dist = dist.at<int>(i + di, j + dj); if (neighbor_dist != INT_MAX) { min_dist = min(min_dist, neighbor_dist + weight); } } } dist.at<int>(i, j) = min_dist; } } // Backward pass: bottom-right to top-left for (int i = img.rows - half_template - 1; i >= half_template; i--) { for (int j = img.cols - half_template - 1; j >= half_template; j--) { if (dist.at<int>(i, j) == 0) continue; int min_dist = dist.at<int>(i, j); for (int di = -half_template; di <= half_template; di++) { for (int dj = -half_template; dj <= half_template; dj++) { int weight = backward.at<int>(di + half_template, dj + half_template); if (weight == 0) continue; int neighbor_dist = dist.at<int>(i + di, j + dj); if (neighbor_dist != INT_MAX) { min_dist = min(min_dist, neighbor_dist + weight); } } } dist.at<int>(i, j) = min_dist; } } // Normalize result to 0-255 for display, divide by 5 to get approximate true distances Mat dist_display; dist.convertTo(dist_display, CV_8U, 255.0 / (dist.max() / 5)); imshow("Distance Transform Result", dist_display); waitKey(0); return 0; }
Key Fixes:
- Valid Templates: The 5x5 templates use the correct Borgefors integer weights that map to approximate Euclidean distances.
- Proper Initialization: The distance matrix starts with
INT_MAXfor background pixels and 0 for foreground, so the algorithm has a baseline to compute minimum distances from. - Full Traversal Logic: Implemented both forward and backward passes to apply the templates correctly, ensuring all possible neighbor distances are considered.
- Error Handling: Added a check for failed image loading to avoid crashes.
- Display Ready: Normalized the result to a visible 0-255 range, with scaling to convert integer weights to approximate true distances.
内容的提问来源于stack exchange,提问作者van
相关产品推荐
相关产品推荐

