基于Skimage Hough Line检测液滴接触面水平线的技术求助
问题描述
这是首个Python项目,需求是检测黑白液滴图像中液滴与接触面的水平交界线。已用cv2.Canny成功检测液滴轮廓,但将边缘图输入Skimage的Hough变换(hough_line)后,无法确定是否检测到线条,也无法将线条绘制到原图上(单独绘制线条功能正常)。环境为Anaconda下的Spyder,Python版本3.10。
当前代码
import numpy as np import cv2 from skimage.transform import hough_line, probabilistic_hough_line def fit_baseline(image): # Convert the image to grayscale gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) cv2.imshow('Graubild', gray_image) # Apply edge detection edges = cv2.Canny(gray_image, 80, 120, apertureSize=3) cv2.imshow('Ecken',edges) # Perform the Hough Transform h, theta, d = hough_line(edges) print('h:', h) print('theta: ', theta) print('d: ', d) # Find the most prominent line (baseline) angle, dist = np.unravel_index(np.argmax(h), h.shape) angle = np.rad2deg(theta[angle]) dist = d[dist] # Convert from polar to slope-intercept form if angle != 0: slope = -1 / np.tan(np.deg2rad(angle)) intercept = dist / np.sin(np.deg2rad(angle)) else: slope = float('inf') intercept = dist return slope, intercept # Load the image image = cv2.imread('Bilder/drop_zoomed.png') # Fit the baseline slope, intercept = fit_baseline(image) # Draw the baseline on the image height, width, _ = image.shape baseline_start_x = 0 baseline_start_y = int(intercept) baseline_end_x = width - 1 baseline_end_y = int(slope * baseline_end_x + intercept) baseline_color = (0, 255, 0) # Green color (BGR format) baseline_thickness = 2 image_with_baseline = cv2.line(image, (baseline_start_x, baseline_start_y), (baseline_end_x, baseline_end_y), baseline_color, baseline_thickness) # Display the image with the baseline cv2.imshow('Image with Baseline', image_with_baseline) cv2.waitKey(0) cv2.destroyAllWindows()
待检测图像

预期效果

调整建议与可行方案
一、修正Hough变换的坐标转换逻辑
skimage的hough_line中,theta是线条与x轴正方向的夹角,d是原点到线条的垂直距离,你当前的坐标转换公式有误,导致直线位置偏移。直接用极坐标参数生成端点即可,无需转换为斜截式:
# 替换原Hough变换后的坐标转换代码 theta_rad = theta[angle] x0 = np.cos(theta_rad) * d[dist] y0 = np.sin(theta_rad) * d[dist] # 生成直线两端点(取垂直于theta的方向,避免斜率无穷大问题) dx = np.cos(theta_rad + np.pi/2) * 1000 dy = np.sin(theta_rad + np.pi/2) * 1000 start_point = (int(x0 - dx), int(y0 - dy)) end_point = (int(x0 + dx), int(y0 + dy)) # 直接绘制直线 cv2.line(image, start_point, end_point, (0,255,0), 2)
二、改用概率霍夫变换简化检测
probabilistic_hough_line直接返回直线端点,且更擅长检测长直线,适合你的场景:
# 替换原Hough变换部分 edges = cv2.Canny(gray_image, 30, 100, apertureSize=3) lines = probabilistic_hough_line(edges, threshold=10, line_length=50, line_gap=5) # 筛选接近水平的直线(角度误差±5度) horizontal_lines = [] for line in lines: (x1, y1), (x2, y2) = line angle = np.arctan2(y2 - y1, x2 - x1) if abs(np.rad2deg(angle)) < 5 or abs(np.rad2deg(angle) - 180) < 5: horizontal_lines.append(line) # 取最下方的水平直线(液滴与接触面的交界线) if horizontal_lines: # 按平均y坐标排序,取最大的(最靠下) horizontal_lines.sort(key=lambda l: (l[0][1] + l[1][1])/2, reverse=True) best_line = horizontal_lines[0] cv2.line(image, best_line[0], best_line[1], (0,255,0), 2)
三、优化边缘检测参数
当前Canny阈值可能过滤了交界线边缘,可降低下限阈值并增加高斯模糊降噪:
blur = cv2.GaussianBlur(gray_image, (3,3), 0) edges = cv2.Canny(blur, 30, 100, apertureSize=3)
四、替代方案:行像素统计法
针对水平交界线,直接统计每行白色像素占比,找到突变行:
def find_baseline_by_row(gray_image): width = gray_image.shape[1] # 统计每行白色像素数量(背景为白色,液滴为黑色) row_counts = np.sum(gray_image == 255, axis=1) # 从下往上找白色像素骤增的行 for y in range(gray_image.shape[0]-1, 0, -1): if row_counts[y] - row_counts[y-1] > width * 0.5: return y return gray_image.shape[0] // 2 # 使用示例 gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) baseline_y = find_baseline_by_row(gray_image) cv2.line(image, (0, baseline_y), (gray_image.shape[1]-1, baseline_y), (0,255,0), 2)
内容的提问来源于stack exchange,提问作者Leah Fernández
相关产品推荐
相关产品推荐

