几何尺寸与公差论坛

 找回密码
 注册
查看: 56|回复: 9

如何检测晶圆bump?

  [复制链接]
发表于 6 小时前 | 显示全部楼层 |阅读模式
检测晶圆bump-从图像上提取边界圆,为什么只需做个开运算和圆边界提取?
 楼主| 发表于 6 小时前 | 显示全部楼层
1. 开运算的作用

开运算是先腐蚀(Erode)再膨胀(Dilate),它主要有两个效果:

    去除小噪声:将小于结构元素的“毛刺”或散点噪声剔除掉。

    分离轻微黏连:如果相邻 bump 之间因为噪声或轻微挤压而在二值图上黏连,开运算能弱化它们的连接处。

这样做完之后,你得到的二值图上,bump 的区域会更加“干净”、轮廓更平滑,也更容易与背景“分割”开来。
 楼主| 发表于 6 小时前 | 显示全部楼层
* 1. 读入彩色或灰度图
read_image(Image, 'bump_image.png')
* 如果是彩色图,转灰度
if (ImageType(Image)=='byte')
    Gray := Image
else
    rgb1_to_gray(Image, Gray)
endif

* 2. 阈值分割出 bump 区域(根据实际亮度范围调整)
threshold(Gray, Region, 128, 255)

* 3. 开运算:半径为 5 像素的圆形结构元素
opening_circle(Region, RegionOpened, 5)

* 4. 连通区域并按圆度过滤
connection(RegionOpened, ConnRegions)
* 计算每个区域的“圆度”(形状特征:circularity)
select_shape(ConnRegions, SelRegions, 'circularity', 'and', 0.7, 1.0)

* 5. 提取亚像素边缘
union1(SelRegions, UnionRegion)
gen_contour_region_xld(UnionRegion, Contours, 'border')
edges_sub_pix(Contours, Edges, 'canny', 3, 20, 40)

* 6. 对每一条边缘拟合圆
*    Algebraic 算法,2 次拟合迭代,最小样本 5,最大样本 20
fit_circle_contour_xld(Edges, Circles, 'algebraic', 2, 5, 20, 3, 2, 0.05,
                       RowCenters, ColCenters, Radii, StartPhi, EndPhi)

* 7. 可视化:在原图上画出拟合圆
dev_display(Image)
count_obj(Circles, N)
for Index := 1 to N by 1
    select_obj(Circles, SingleCircle, Index)
    dev_set_color('green')
    dev_display(SingleCircle)
endfor
阈值:根据 bump 在图中灰度/亮度调整 threshold 的上下限。

开运算半径:opening_circle(...,5) 中 5 可根据 bump 的最小尺寸微调。

圆度筛选:select_shape(...,'circularity',0.7,1.0) 去掉形状不够圆的干扰。

拟合参数:fit_circle_contour_xld 最后的各项可按噪声和精度要求优化。
 楼主| 发表于 6 小时前 | 显示全部楼层
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;

int main()
{
    // 1. 读取图像并灰度化
    Mat src = imread("bump_image.png");
    if (src.empty()) return -1;
    Mat gray;
    cvtColor(src, gray, COLOR_BGR2GRAY);

    // 2. 二值化(固定阈值/自适应均可)
    Mat bin;
    threshold(gray, bin, 128, 255, THRESH_BINARY);

    // 3. 开运算去噪:半径 5 的椭圆结构元素
    Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(11, 11));
    Mat opened;
    morphologyEx(bin, opened, MORPH_OPEN, kernel);

    // 4. 找轮廓
    vector<vector<Point>> contours;
    findContours(opened, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    // 5. 对每个轮廓拟合最小包含圆
    Mat disp = src.clone();
    for (auto& cnt : contours) {
        // 可选:按面积或圆度过滤
        double area = contourArea(cnt);
        if (area < 50) continue;           // 面积太小跳过
        Point2f center;
        float radius;
        minEnclosingCircle(cnt, center, radius);

        // 可选:按圆与原轮廓的重合度筛选
        double perim = arcLength(cnt, true);
        double circ = 4 * CV_PI * area / (perim * perim);
        if (circ < 0.7) continue;         // 圆度太差跳过

        // 画出圆
        circle(disp, center, int(radius), Scalar(0, 255, 0), 2);
    }

    // 6. 显示结果
    imshow("Bump Circles", disp);
    waitKey();
    return 0;
}
    threshold:根据背景/前景对比度选择固定或自适应阈值。

    开运算核大小:Size(11,11) 对应半径约 5 像素,按 bump 大小调整。

    过滤条件:通过 contourArea 和 “圆度” (4π·area/perim&#178;) 去除杂轮廓。

    拟合方式:minEnclosingCircle 简单快速,若需要更高精度也可先做 Canny 边缘再 HoughCircles 或 fitEllipse。

这样,Halcon 与 OpenCV 两种环境下均只用到一次开运算 + 圆形拟合,就能快速准确地从晶圆图中提取出 bump 的圆边界。
 楼主| 发表于 6 小时前 | 显示全部楼层
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;

int main()
{
    Mat src = imread("bump_image.png");
    if (src.empty()) return -1;

    // 1. 预处理:灰度 + 高斯去噪
    Mat gray;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    GaussianBlur(gray, gray, Size(5,5), 1.5);

    // 2. Canny 边缘提取
    Mat edges;
    Canny(gray, edges, 50, 150, 3);

    // 3A. HoughCircles 检测圆
    vector<Vec3f> circles;
    HoughCircles(edges, circles,
                 HOUGH_GRADIENT,
                 1,      // dp = 1
                 20,     // minDist
                 100,    // param1: Canny high threshold
                 30,     // param2: 阈值(累加器)
                 5,      // minRadius
                 30      // maxRadius
    );

    Mat disp = src.clone();
    for (auto & c : circles) {
        Point center(cvRound(c[0]), cvRound(c[1]));
        int radius = cvRound(c[2]);
        circle(disp, center, radius, Scalar(0,255,0), 2);
    }

    // 3B. (可选)轮廓+fitEllipse 拟合更精细的“椭圆”近似圆
    //    先找轮廓,再对足够点数的轮廓用 fitEllipse
    vector<vector<Point>> contours;
    findContours(edges, contours, RETR_LIST, CHAIN_APPROX_NONE);
    for (auto & cnt : contours) {
        if (cnt.size() < 50) continue;  // 点太少难以拟合
        double area = contourArea(cnt);
        if (area < 50) continue;
        RotatedRect ellipse = fitEllipse(cnt);
        // 只取长短轴差不多(近似圆)
        if (abs(ellipse.size.width - ellipse.size.height) / ellipse.size.width < 0.2) {
            ellipse.angle = 0; // 不显示旋转
            ellipse.size.width = ellipse.size.height = (ellipse.size.width + ellipse.size.height) / 2;
            ellipse.center = ellipse.center;
            // 画出拟合圆
            circle(disp, ellipse.center, int(ellipse.size.width/2),
                   Scalar(255,0,0), 2);
        }
    }

    imshow("High-Precision Bump Circles", disp);
    waitKey();
    return 0;
}
 楼主| 发表于 6 小时前 | 显示全部楼层
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;

int main()
{
    Mat src = imread("bump_image.png");
    if (src.empty()) return -1;

    // 1. 预处理:灰度 + 高斯去噪
    Mat gray;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    GaussianBlur(gray, gray, Size(5,5), 1.5);

    // 2. Canny 边缘提取
    Mat edges;
    Canny(gray, edges, 50, 150, 3);

    // 3A. HoughCircles 检测圆
    vector<Vec3f> circles;
    HoughCircles(edges, circles,
                 HOUGH_GRADIENT,
                 1,      // dp = 1
                 20,     // minDist
                 100,    // param1: Canny high threshold
                 30,     // param2: 阈值(累加器)
                 5,      // minRadius
                 30      // maxRadius
    );

    Mat disp = src.clone();
    for (auto & c : circles) {
        Point center(cvRound(c[0]), cvRound(c[1]));
        int radius = cvRound(c[2]);
        circle(disp, center, radius, Scalar(0,255,0), 2);
    }

    // 3B. (可选)轮廓+fitEllipse 拟合更精细的“椭圆”近似圆
    //    先找轮廓,再对足够点数的轮廓用 fitEllipse
    vector<vector<Point>> contours;
    findContours(edges, contours, RETR_LIST, CHAIN_APPROX_NONE);
    for (auto & cnt : contours) {
        if (cnt.size() < 50) continue;  // 点太少难以拟合
        double area = contourArea(cnt);
        if (area < 50) continue;
        RotatedRect ellipse = fitEllipse(cnt);
        // 只取长短轴差不多(近似圆)
        if (abs(ellipse.size.width - ellipse.size.height) / ellipse.size.width < 0.2) {
            ellipse.angle = 0; // 不显示旋转
            ellipse.size.width = ellipse.size.height = (ellipse.size.width + ellipse.size.height) / 2;
            ellipse.center = ellipse.center;
            // 画出拟合圆
            circle(disp, ellipse.center, int(ellipse.size.width/2),
                   Scalar(255,0,0), 2);
        }
    }

    imshow("High-Precision Bump Circles", disp);
    waitKey();
    return 0;
}
 楼主| 发表于 6 小时前 | 显示全部楼层
说明

    GaussianBlur + Canny:先平滑降噪,再提取细化边缘。

    HoughCircles:快速批量检测规则圆;param2(累加器阈值)越低检测越多(但误检也多),需根据实际调参。

    fitEllipse:对轮廓点做最小二乘椭圆拟合,可获得亚像素精度的长/短轴与中心;这里筛选近似圆后,将宽高取平均画圆。

这样就能在 OpenCV 中实现更高精度的 bump 圆边界提取。
 楼主| 发表于 6 小时前 | 显示全部楼层
下面给出一个完整的 C# 示例,演示如何通过 HalconDotNet 接口调用 Halcon,先做高斯去噪+亚像素 Canny 边缘提取,再用 HoughCircle 检测粗圆并用 FitCircleContourXld 做高精度拟合。
 楼主| 发表于 6 小时前 | 显示全部楼层
using System;
using HalconDotNet;

namespace HalconHighPrecisionCircleFit
{
    class Program
    {
        static void Main(string[] args)
        {
            // 图像路径
            string imagePath = "bump_image.png";

            // 1. 读入图像
            HImage image = new HImage(imagePath);

            // 2. 转灰度
            HImage gray;
            HOperatorSet.Rgb1ToGray(image, out gray);

            // 3. 高斯去噪 (sigma=1.5)
            HImage smooth;
            HOperatorSet.GaussImage(gray, out smooth, 1.5);

            // 4. 亚像素精度 Canny 边缘提取 (aperture=1, low=50, high=150)
            HRegion edges;
            HOperatorSet.EdgesSubPix(smooth, out edges, "canny", 1, 50, 150);

            // 5. Hough 圆变换检测 (sigma=3, threshold=50, minDist=20, maxDist=200, rMin=5, rMax=30)
            HRegion roughCircles;
            HOperatorSet.HoughCircle(edges, out roughCircles,
                                     "greys",  // 基于灰度投票
                                     3,        // 高斯平滑半径
                                     50,       // 投票阈值
                                     20,       // 圆心最小间距
                                     200,      // 最大投票距离
                                     5,        // 最小半径
                                     30        // 最大半径
            );

            // 6. 用 FitCircleContourXld 做高精度拟合
            HObject preciseCircles;
            HTuple rowC, colC, radC, startPhi, endPhi;
            HOperatorSet.FitCircleContourXld(roughCircles, out preciseCircles,
                "algebraic",  // 拟合算法
                2,             // 拟合迭代次数
                5,             // 最小点数
                20,            // 最大点间隔
                3,             // 最小弧长
                2,             // 最大重叠
                0.05,          // 最大拟合误差
                out rowC, out colC, out radC, out startPhi, out endPhi
            );

            // 7. 可视化结果
            // 创建一个窗口,大小同图像
            HWindow window = new HWindow(0, 0, image.Width, image.Height);
            window.DispObj(image);

            // 在原图上画出每个拟合的圆
            int count = rowC.Length;
            window.SetColor("green");
            for (int i = 0; i < count; i++)
            {
                window.DispCircle(rowC[i], colC[i], radC[i]);
            }

            Console.WriteLine($"检测到 {count} 个 bump 圆。");
            Console.WriteLine("按任意键退出。");
            Console.ReadKey();
        }
    }
}
 楼主| 发表于 6 小时前 | 显示全部楼层
关键步骤说明

    GaussImage 平滑去噪,提高边缘检测稳定性。

    EdgesSubPix 用亚像素精度的 Canny 获得细化边缘。

    HoughCircle 快速粗略定位所有圆心和半径。

    FitCircleContourXld 对 Hough 输出的轮廓做最小二乘精确拟合,获得亚像素级圆心位置和半径。

这样,你就能在 C# 环境中调用 Halcon,实现高精度的 bump 圆边界提取与拟合。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|Archiver|小黑屋|几何尺寸与公差论坛

GMT+8, 2025-4-28 21:29 , Processed in 0.041198 second(s), 18 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表