You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用OpenCV自动检测SEM图像光刻胶柱并测量椭圆参数与周期?

用Python+OpenCV自动化检测光刻胶柱的尺寸与周期

完全可以用Python和OpenCV实现你的需求!针对你提到的椭圆检测替换圆检测、图像比例尺获取,还有x/y方向周期计算的问题,我来给你梳理一套落地的方案:

一、替换圆检测为椭圆拟合

你之前用的cv2.HoughCircles更适合规则圆形,而你的光刻胶柱因拍摄角度或本身形状呈现椭圆,咱们改用轮廓检测+椭圆拟合的方式更准确。步骤大概是:预处理图像→提取轮廓→筛选有效轮廓→拟合椭圆→提取长/短轴(对应x/y方向直径)。

这里给你修改后的核心代码片段:

import numpy as np
import cv2
from matplotlib import pyplot as plt

# 1. 图像读取与预处理
img = cv2.imread("01.jpg", 0)
output = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)  # 转彩色方便画标注

# 预处理:降噪+边缘检测+形态学操作
blurred = cv2.GaussianBlur(img, (5, 5), 0)
edged = cv2.Canny(blurred, 50, 200)
edged = cv2.dilate(edged, None, iterations=1)
edged = cv2.erode(edged, None, iterations=1)

# 2. 提取轮廓
contours, _ = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 3. 筛选有效轮廓(根据你的光刻胶柱大小调整面积阈值)
min_area = 100  # 最小轮廓面积,过滤噪点
max_area = 10000  # 最大轮廓面积,过滤大的干扰
ellipse_params = []  # 存储每个椭圆的参数:(中心x, 中心y, 短轴, 长轴, 旋转角)

for cnt in contours:
    area = cv2.contourArea(cnt)
    if min_area < area < max_area:
        # 拟合椭圆(需要轮廓点数≥5)
        if len(cnt) >= 5:
            ellipse = cv2.fitEllipse(cnt)
            (x, y), (minor_axis, major_axis), angle = ellipse
            ellipse_params.append((x, y, minor_axis, major_axis))
            # 在图上画出椭圆
            cv2.ellipse(output, ellipse, (0, 255, 0), 2)
            # 标记中心
            cv2.circle(output, (int(x), int(y)), 3, (0, 0, 255), -1)

# 4. 计算x/y方向的平均直径
if ellipse_params:
    # 短轴/长轴对应x/y方向可根据你的图像实际方向调整
    avg_x_diameter = np.mean([param[2] for param in ellipse_params])
    avg_y_diameter = np.mean([param[3] for param in ellipse_params])
    print(f"X方向平均直径(像素):{avg_x_diameter:.2f}")
    print(f"Y方向平均直径(像素):{avg_y_diameter:.2f}")

# 显示结果
plt.figure(figsize=(10, 8))
plt.imshow(cv2.cvtColor(output, cv2.COLOR_BGR2RGB))
plt.xticks([]), plt.yticks([])
plt.show()

二、解决图像比例尺问题

要把像素单位转换成实际物理尺寸(比如μm),你需要先确定图像的像素-实际尺寸比例,有两种常用方法:

  • 方法1:利用图像自带的标尺
    如果你的SEM图像边缘有已知长度的标尺(比如10μm),可以用画图工具或代码标记标尺的像素长度。比如标尺实际10μm对应200像素,那比例尺就是scale = 10 / 200 = 0.05 μm/像素。把这个值代入代码,就能把像素直径转换成实际尺寸:

    scale = 0.05  # 示例:1像素=0.05μm
    avg_x_diameter_actual = avg_x_diameter * scale
    avg_y_diameter_actual = avg_y_diameter * scale
    print(f"X方向平均直径(实际):{avg_x_diameter_actual:.2f} μm")
    print(f"Y方向平均直径(实际):{avg_y_diameter_actual:.2f} μm")
    
  • 方法2:利用已知设计尺寸
    如果你知道光刻胶柱的设计直径(比如设计的x方向直径是5μm),可以先检测出这个柱的像素直径,反推比例尺:scale = 设计尺寸 / 像素直径

三、计算x/y方向的平均周期

周期是相邻柱体中心的间距,咱们可以收集所有椭圆的中心坐标,分别计算x、y方向的相邻间距平均值:

# 提取所有中心的x、y坐标
x_centers = np.array([param[0] for param in ellipse_params])
y_centers = np.array([param[1] for param in ellipse_params])

# 计算X方向周期:排序后取相邻差的平均值
x_sorted = np.sort(x_centers)
x_spacings = np.diff(x_sorted)
avg_x_period = np.mean(x_spacings) if len(x_spacings) > 0 else 0

# 计算Y方向周期
y_sorted = np.sort(y_centers)
y_spacings = np.diff(y_sorted)
avg_y_period = np.mean(y_spacings) if len(y_spacings) > 0 else 0

# 转换成实际尺寸(如果有scale的话)
avg_x_period_actual = avg_x_period * scale
avg_y_period_actual = avg_y_period * scale

print(f"X方向平均周期(像素):{avg_x_period:.2f}")
print(f"Y方向平均周期(像素):{avg_y_period:.2f}")
print(f"X方向平均周期(实际):{avg_x_period_actual:.2f} μm")
print(f"Y方向平均周期(实际):{avg_y_period_actual:.2f} μm")

一些优化建议

  • 预处理步骤可以根据你的图像调整:比如调整高斯模糊的核大小、Canny的阈值,确保边缘检测更准确。
  • 轮廓筛选的面积阈值需要根据你的光刻胶柱实际大小(像素级)调整,避免过滤掉有效目标或者保留噪点。
  • 如果你的柱体排列很规则(比如网格状),可以用霍夫直线检测辅助验证周期,或者用聚类的方法分组计算间距。

内容的提问来源于stack exchange,提问作者user7086216

火山引擎 最新活动