基于OpenCV检测透射电镜下弯曲网格的节点坐标
TEM网格图片节点坐标检测问题
我有多张透射电镜(TEM)下的网格图片,想要获取网格节点(交叉点)的坐标。参考数独网格或普通直线检测教程实现时,因为线条弯曲、和背景颜色相近,检测结果不理想。
我的实现代码
import cv2 import numpy as np image = cv2.imread("test.png") original = image.copy() cv2.imshow("Image", image) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) cv2.imshow("gray", gray) blur = cv2.GaussianBlur(gray, (5, 5), 0) cv2.imshow("blur", blur) ret, thresh = cv2.threshold(blur, 32, 255, cv2.THRESH_BINARY) cv2.imshow("thresh", thresh) low_threshold = 50 high_threshold = 150 edges = cv2.Canny(thresh, low_threshold, high_threshold) cv2.imshow("edges", edges) rho = 1 # 霍夫网格的像素距离分辨率 theta = np.pi / 180 # 霍夫网格的弧度角度分辨率 threshold = 30 # 霍夫网格单元格的最小投票数 min_line_length = 50 # 构成线条的最小像素数 max_line_gap = 250 # 可连接线段之间的最大像素间隙 line_image = np.copy(image) * 0 # 创建空白画布用于绘制线条 # 在边缘检测图像上运行霍夫变换 # 输出"lines"是包含检测线段端点的数组 lines = cv2.HoughLinesP(edges, rho, theta, threshold, np.array([]), min_line_length, max_line_gap) print(lines) for line in lines: for x1,y1,x2,y2 in line: cv2.line(line_image,(x1,y1),(x2,y2),(255,0,0),1) cv2.imshow('result',line_image) cv2.waitKey(0) cv2.destroyAllWindows()
现有处理结果
网格原图

灰度化、高斯模糊及阈值处理后的结果

Canny边缘检测结果

霍夫线变换后的最终结果

优化解决方案
针对线条弯曲、背景对比度低的问题,可通过调整预处理和检测策略改善结果:
1. 改进预处理流程
替换固定阈值为自适应阈值,适配背景不均匀的图像;增加形态学操作强化网格线条:
# 替换原固定阈值处理步骤 thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) # 形态学闭运算填补线条间隙 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
2. 调整边缘检测参数
降低Canny高阈值并缩小高低阈值比例(建议1:2),保留更多弱边缘:
low_threshold = 30 high_threshold = 60 edges = cv2.Canny(thresh, low_threshold, high_threshold)
3. 优化霍夫线检测参数
减小max_line_gap避免误连无关线段,降低threshold检测更多短线条:
threshold = 20 min_line_length = 30 max_line_gap = 50 lines = cv2.HoughLinesP(edges, rho, theta, threshold, np.array([]), min_line_length, max_line_gap)
4. 提取网格节点坐标
分离水平/垂直线条,计算所有线对的交点并去重:
# 分离水平和垂直线条 horizontal_lines = [] vertical_lines = [] for line in lines: x1, y1, x2, y2 = line[0] angle = np.arctan2(y2-y1, x2-x1) * 180 / np.pi # 允许10度以内的角度偏差 if abs(angle) < 10 or abs(angle) > 170: horizontal_lines.append(line[0]) elif abs(angle - 90) < 10 or abs(angle +90) <10: vertical_lines.append(line[0]) # 计算两条线段的交点 def line_intersection(line1, line2): x1,y1,x2,y2 = line1 x3,y3,x4,y4 = line2 denom = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4) if denom == 0: return None # 平行无交点 t_num = (x1-x3)*(y3-y4) - (y1-y3)*(x3-x4) u_num = (x1-x3)*(y1-y2) - (y1-y3)*(x1-x2) t = t_num / denom u = u_num / denom if 0<=t<=1 and 0<=u<=1: x = x1 + t*(x2-x1) y = y1 + t*(y2-y1) return (int(x), int(y)) return None # 计算所有水平与垂直线的交点并去重 intersections = [] for h_line in horizontal_lines: for v_line in vertical_lines: pt = line_intersection(h_line, v_line) if pt is not None: intersections.append(pt) intersections = list(set(intersections)) print("网格节点坐标:", intersections)
内容的提问来源于stack exchange,提问作者Xuanhao Wang
相关产品推荐
相关产品推荐

