如何在Python中获取包含距离(浮点型)与角度(弧度)信息的图像距离变换?
Hey there! Great question—getting both distance and angle info for each pixel's closest target is totally doable, and I'll walk you through a couple of solid approaches using Python, including OpenCV and some alternative tools if you're open to them.
方法1:OpenCV结合梯度计算角度
OpenCV's cv2.distanceTransform only returns distance values out of the box, but we can calculate the direction (angle) to the nearest target by computing the gradient of the distance map. Here's how:
- First, prepare a binary image where your target regions are foreground (e.g., 255) and the rest is background (0)
- Compute the distance transform map
- Calculate x/y gradients of the distance map, then derive the angle from the gradient direction
Code Example
import cv2 import numpy as np # 1. Create a sample binary image (white targets on black background) img = np.zeros((100, 100), dtype=np.uint8) cv2.circle(img, (30, 30), 10, 255, -1) cv2.rectangle(img, (70, 70), (90, 90), 255, -1) # 2. Compute Euclidean distance transform dist_transform = cv2.distanceTransform(img, cv2.DIST_L2, 5) # 3. Calculate x and y gradients of the distance map dx = cv2.Sobel(dist_transform, cv2.CV_64F, 1, 0, ksize=3) dy = cv2.Sobel(dist_transform, cv2.CV_64F, 0, 1, ksize=3) # 4. Compute angle (in radians) — gradient points away from targets, so invert to point towards them angles = np.arctan2(-dy, -dx) # Now: # dist_transform = float distance from each pixel to nearest target # angles = radians angle pointing from pixel to nearest target
Quick Explanation
np.arctan2(dy, dx) returns the angle from the positive x-axis to the vector (dx, dy). Since the gradient points in the direction of increasing distance (away from targets), we invert the gradient values to get the direction pointing towards the nearest target.
方法2:Scipy's distance_transform_edt (More Intuitive)
If you're okay adding Scipy to your stack, scipy.ndimage.distance_transform_edt can directly return both distances and the coordinates of the nearest target pixel. This makes angle calculation super straightforward:
Code Example
import numpy as np from scipy.ndimage import distance_transform_edt # 1. Create sample binary image (targets = 1, background = 0) img = np.zeros((100, 100), dtype=np.uint8) img[20:40, 20:40] = 1 img[60:80, 60:80] = 1 # 2. Get distances and coordinates of nearest target pixels distances, closest_points = distance_transform_edt(1 - img, return_indices=True) # Unpack coordinates: closest_points[0] = y-coords, closest_points[1] = x-coords y_target, x_target = closest_points # Generate current pixel coordinates y_current, x_current = np.indices(distances.shape) # 3. Calculate angle (radians) using vector from current pixel to target angles = np.arctan2(y_target - y_current, x_target - x_current) # Now: # distances = float distance from each pixel to nearest target # angles = radians angle pointing from pixel to nearest target
Quick Explanation
We pass 1 - img because distance_transform_edt calculates distances from non-zero pixels to the nearest zero pixel. Inverting the image lets us compute distances from background pixels to our target regions (original non-zero pixels).
Key Notes
- Angle Range: Both methods return angles in the range
[-π, π], with 0 pointing along the positive x-axis (right), and positive values rotating counterclockwise (standard mathematical radians). - Performance: OpenCV's method is faster for large images (optimized C++ under the hood), while Scipy's approach is more readable and requires less manual math.
- Binary Image Prep: Make sure your target regions are properly isolated (no noise) before running distance transforms—garbage in = garbage out!
内容的提问来源于stack exchange,提问作者Chris

