几何尺寸与公差论坛

 找回密码
 注册
查看: 163|回复: 5

小珠子,计数,椭圆长短轴直径

  [复制链接]
发表于 2024-10-31 09:21:17 | 显示全部楼层 |阅读模式
小珠子,计数,椭圆长短轴直径
 楼主| 发表于 2024-10-31 09:24:40 | 显示全部楼层
* 读取图像
read_image (Image, 'path/to/your/image.bmp')

* 二值化,调整阈值以分离小珠子
threshold (Image, Regions, 0, 59)

* 连接区域(将相邻的像素点连成一个区域)
connection (Regions, ConnectedRegions)

* 按尺寸过滤区域(根据宽度和面积筛选珠子)
select_shape (ConnectedRegions, SelectedRegions, 'width', 'and', 5, 100)  
select_shape (SelectedRegions, SelectedRegions, 'area', 'and', 50, 5000)

* 计算每个珠子的区域中心(质心)
area_center (SelectedRegions, Area, Row, Column)
num_elements (Area, NumberOfBeads)  * 统计珠子的数量

* 形态学腐蚀和膨胀,用于分离珠子
erosion_circle (SelectedRegions, RegionErosion, 5)
dilation_circle (RegionErosion, RegionDilation, 5)

* 为储存长轴和短轴直径创建空数组
RA := []
RB := []

* 遍历每个区域,拟合椭圆并提取长短轴信息
gen_empty_obj (EmptyObject)
for Index := 1 to NumberOfBeads by 1
    * 获取单个区域
    select_obj (RegionDilation, ObjectSelected, Index)
   
    * 生成区域轮廓
    gen_contour_region_xld (ObjectSelected, Contours, 'border')
   
    * 拟合椭圆并计算长轴、短轴
    fit_ellipse_contour_xld (Contours, 'fitzgibbon', -1, 0, 0, 200, 3, 2, Row1, Column1, Phi, Radius1, Radius2, StartPhi, EndPhi, PointOrder)
   
    * 存储长轴和短轴
    RA := RA.TupleConcat(Radius1 * 2)  * 长轴直径
    RB := RB.TupleConcat(Radius2 * 2)  * 短轴直径

    * 显示拟合的椭圆轮廓
    gen_ellipse_contour_xld (ContEllipse, Row1, Column1, Phi, Radius1, Radius2, 0, 6.28318, 'positive', 1.5)
    concat_obj (EmptyObject, ContEllipse, EmptyObject)
endfor

* 显示结果
dev_display (EmptyObject)
stop()
 楼主| 发表于 2024-10-31 09:25:17 | 显示全部楼层
代码解释

    threshold:对图像进行二值化处理,这一步用于分割珠子区域。阈值(0到59)可能需要根据具体图像进行调整。
    connection:将像素点连成区域。
    select_shape:根据宽度和面积过滤出符合条件的小珠子区域,参数可以根据珠子的尺寸进行调整。
    area_center:计算每个小珠子的面积和质心。
    erosion_circle和dilation_circle:形态学腐蚀和膨胀操作,确保珠子区域被分离。
    fit_ellipse_contour_xld:对每个小珠子区域进行椭圆拟合,获取长轴和短轴半径。长轴和短轴直径分别是Radius1*2和Radius2*2。
    结果显示:使用gen_ellipse_contour_xld绘制拟合的椭圆,RA和RB存储所有珠子的长轴和短轴直径。

注意事项

    阈值调整:根据图像的不同,阈值可能需要手动调整,以获得最佳的珠子分割效果。
    尺寸筛选:select_shape中的宽度和面积筛选条件需要根据小珠子的实际尺寸进行调整。
    形态学操作半径:腐蚀和膨胀的半径也可能需要调整,以确保珠子正确分离。

此代码能够检测图像中的小珠子数量,并测量其长轴和短轴直径,适用于HALCON中的图像分析任务。
 楼主| 发表于 2024-10-31 09:26:56 | 显示全部楼层
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

int main() {
    // 读取图像
    cv::Mat image = cv::imread("path/to/your/image.bmp", cv::IMREAD_GRAYSCALE);
    if (image.empty()) {
        std::cerr << "Error loading image!" << std::endl;
        return -1;
    }

    // 二值化,阈值分割
    cv::Mat binary;
    cv::threshold(image, binary, 60, 255, cv::THRESH_BINARY_INV);

    // 腐蚀和膨胀操作,分离小珠子
    cv::Mat morph;
    cv::erode(binary, morph, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5)));
    cv::dilate(morph, morph, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5)));

    // 查找轮廓
    std::vector<std::vector<cv:oint>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(morph, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

    // 用于存储长轴和短轴
    std::vector<double> longAxes;
    std::vector<double> shortAxes;

    // 遍历每个轮廓
    cv::Mat result;
    cv::cvtColor(binary, result, cv::COLOR_GRAY2BGR);
    for (size_t i = 0; i < contours.size(); ++i) {
        // 过滤小区域
        double area = cv::contourArea(contours[i]);
        if (area < 50 || area > 5000) continue; // 过滤面积过小或过大的区域

        // 拟合椭圆
        if (contours[i].size() < 5) continue; // 拟合椭圆需要至少5个点
        cv::RotatedRect ellipse = cv::fitEllipse(contours[i]);

        // 获取长轴和短轴
        double longAxis = std::max(ellipse.size.width, ellipse.size.height);
        double shortAxis = std::min(ellipse.size.width, ellipse.size.height);

        // 保存长轴和短轴
        longAxes.push_back(longAxis);
        shortAxes.push_back(shortAxis);

        // 绘制椭圆和中心点
        cv::ellipse(result, ellipse, cv::Scalar(0, 255, 0), 2);
        cv::circle(result, ellipse.center, 3, cv::Scalar(0, 0, 255), -1);

        // 在图像上显示长轴和短轴
        std::string text = "L:" + std::to_string(longAxis) + " S:" + std::to_string(shortAxis);
        cv::putText(result, text, ellipse.center, cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(255, 0, 0), 1);
    }

    // 显示结果
    cv::imshow("Detected Beads", result);
    cv::waitKey(0);
    return 0;
}
 楼主| 发表于 2024-10-31 09:27:05 | 显示全部楼层
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

int main() {
    // 读取图像
    cv::Mat image = cv::imread("path/to/your/image.bmp", cv::IMREAD_GRAYSCALE);
    if (image.empty()) {
        std::cerr << "Error loading image!" << std::endl;
        return -1;
    }

    // 二值化,阈值分割
    cv::Mat binary;
    cv::threshold(image, binary, 60, 255, cv::THRESH_BINARY_INV);

    // 腐蚀和膨胀操作,分离小珠子
    cv::Mat morph;
    cv::erode(binary, morph, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5)));
    cv::dilate(morph, morph, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5)));

    // 查找轮廓
    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(morph, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

    // 用于存储长轴和短轴
    std::vector<double> longAxes;
    std::vector<double> shortAxes;

    // 遍历每个轮廓
    cv::Mat result;
    cv::cvtColor(binary, result, cv::COLOR_GRAY2BGR);
    for (size_t i = 0; i < contours.size(); ++i) {
        // 过滤小区域
        double area = cv::contourArea(contours[i]);
        if (area < 50 || area > 5000) continue; // 过滤面积过小或过大的区域

        // 拟合椭圆
        if (contours[i].size() < 5) continue; // 拟合椭圆需要至少5个点
        cv::RotatedRect ellipse = cv::fitEllipse(contours[i]);

        // 获取长轴和短轴
        double longAxis = std::max(ellipse.size.width, ellipse.size.height);
        double shortAxis = std::min(ellipse.size.width, ellipse.size.height);

        // 保存长轴和短轴
        longAxes.push_back(longAxis);
        shortAxes.push_back(shortAxis);

        // 绘制椭圆和中心点
        cv::ellipse(result, ellipse, cv::Scalar(0, 255, 0), 2);
        cv::circle(result, ellipse.center, 3, cv::Scalar(0, 0, 255), -1);

        // 在图像上显示长轴和短轴
        std::string text = "L:" + std::to_string(longAxis) + " S:" + std::to_string(shortAxis);
        cv::putText(result, text, ellipse.center, cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(255, 0, 0), 1);
    }

    // 显示结果
    cv::imshow("Detected Beads", result);
    cv::waitKey(0);
    return 0;
}
 楼主| 发表于 2024-10-31 09:27:47 | 显示全部楼层
注意事项

    阈值:cv::threshold中的阈值(60)和形态学操作的结构元素大小(Size(5, 5))可能需要根据具体图像调整。
    轮廓过滤:面积过滤条件(小于50或大于5000的轮廓会被过滤)用于去除噪声和非目标区域。
    椭圆拟合条件:拟合椭圆要求轮廓至少包含5个点,否则会导致异常。

这段代码可以有效地检测小珠子,统计珠子的数量,并获取每个珠子的长轴和短轴直径。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-12-21 23:20 , Processed in 0.040469 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.

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