Baumer工业相机堡盟工业相机如何联合NEOAPI SDK和OpenCV实现获取图像并对图像进行边缘检测(C++)

简介: Baumer工业相机堡盟工业相机如何联合NEOAPI SDK和OpenCV实现获取图像并对图像进行边缘检测(C++)

Baumer工业相机


Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。


Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具有快速数据传输、低功耗、易于集成以及高度可扩展性等特点。


Baumer工业相机NEOAPI SDK是用于Baumer工业相机的一款最新的软件开发工具包(SDK)。它为开发人员提供了一系列API和工具,用于与Baumer工业相机进行通信和控制,控制方式极为便捷类似Halcon的相机助手类控制方式。


OpenCV,全称Open Source Computer Vision Library,是一个开源的跨平台计算机视觉与机器视觉库。该库提供了丰富的图像处理和计算机视觉算法,涵盖了图像处理、特征检测、目标识别、运动跟踪等多个领域,适用于各种平台,包括Windows、Linux、Android和iOS等。OpenCV是由英特尔公司发起并开放源代码,是计算机视觉领域中广泛应用的一种工具。


注意:本文是基于Baumer的NEOAPI SDK的基础上联合OpenCV使用C#语言来实现相机对图像进行边缘检测。


Baumer工业相机使用OpenCV对图像进行边缘检测的技术背景


工业相机使用OpenCV进行图像边缘检测时,涉及到以下技术背景:


  1. 边缘检测算法:OpenCV中包含了许多经典的边缘检测算法,如Sobel、Canny、Laplacian等。这些算法可用于识别图像中的边缘区域,有助于提取出图像中重要的特征信息。


  1. 图像梯度:边缘检测的核心思想是利用图像中像素之间的梯度变化来识别边缘。Sobel和Laplacian算子可以分别用于计算图像中的水平和垂直梯度,而Canny算法则结合多种技术实现更加精确的边缘检测。


  1. 阈值处理:在边缘检测中,设置适当的阈值对梯度值进行处理是非常重要的。这有助于过滤掉噪声或非边缘区域的影响,从而提高边缘检测的准确度。


  1. 实时性和效率:工业相机通常需要实时进行图像处理,因此在选择边缘检测算法时需要考虑其计算复杂度和实时性能。OpenCV提供了针对性能优化的边缘检测算法,适合工业相机实时应用的需求。


  1. 应用场景:工业相机使用OpenCV进行边缘检测的应用场景包括产品质检、定位、测量等。通过边缘检测,可以有效提取并分析产品表面的特征,实现对产品的自动化检测和分析。


综上所述,工业相机使用OpenCV进行图像边缘检测时,需要深入理解边缘检测算法原理、图像梯度计算、阈值处理等技术背景知识,以实现对图像中边缘区域的准确提取和分析。


在NEOAPI SDK里使用OpenCV建立边缘检测功能


在相机连接后可以在NEOAPI SDK里使用OpenCV对建立边缘检测功能函数,C++调用代码如下所示:

#include <iostream>
#include <thread>
#include <vector>
#include <map>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core/ocl.hpp"
#include "neoapi/neoapi.hpp"
class EdgeDetector {
 public:
    explicit EdgeDetector(NeoAPI::NeoString serialnumber) {
        camera_.Connect(serialnumber);
        camera_.f().ExposureTime.Set(2500);
        // cv mats will created by width and height -> there is no space for chunk -> disable chunk
        camera_.DisableChunk();
        try {
            camera_.f().PixelFormat.Set(NeoAPI::PixelFormat::BayerRG8);
        } catch (NeoAPI::FeatureAccessException&) {
            camera_.f().PixelFormat.Set(NeoAPI::PixelFormat::Mono8);
        }
        pixel_format_ = camera_.f().PixelFormat.Get();
        identifier_ = serialnumber;
    }
    ~EdgeDetector() {
        Stop();
        FreeCamBuffers();
    }
    // setups the edge detector to do processing with the requested type
    void Setup(MemoryMode memtype) {
        cv::ocl::setUseOpenCL(MemoryMode::cpu != memtype);
        if (cv::ocl::Device::getDefault().hostUnifiedMemory()) {  // do not use svm functions if this failes
            try {
                cv::ocl::Context::getDefault().setUseSVM(MemoryMode::shared == memtype);
            }
            catch(...) {
                memtype = MemoryMode::cpu;
                std::cout << "SVM Error: falling back to cpu memory!" << std::endl;
            }
        }
        SetupBuffers(3, memtype);
        camera_.SetUserBufferMode();
    }
    // single edge detection on a given image
    void Detect(const NeoAPI::Image& image, bool show_image) {
        cv::UMat *img_mat = &(image.GetUserBuffer<CamBuffer*>()->gpu_mat_);
        if (NeoAPI::PixelFormat::BayerRG8 == pixel_format_) {
            cv::cvtColor(*img_mat, grey_mat_, cv::COLOR_BayerRG2GRAY);
        } else {
            grey_mat_ = *img_mat;
        }
        cv::GaussianBlur(grey_mat_, gauss_mat_, cv::Size(5, 5), 0);
        cv::Sobel(gauss_mat_, sobel_mat_, sobel_mat_.depth(), 1, 1, 5);
        if (show_image) {
            cv::imshow(identifier_, sobel_mat_);
            cv::pollKey();
        }
        ++frames_;
    }
    // returns the number of processed images since last call
    size_t ProcessedFrames() {
        size_t ret = frames_;
        frames_ = 0;
        return ret;
    }
    // return the cameras serial number
    const cv::String& GetIdentifier() {
        return identifier_;
    }
    // starts a seperate thread that will do edge detection continouosly
    void Start(bool show_images) {
        run_ = true;
        detect_thread_ = std::thread(&EdgeDetector::Detect_, this, show_images);
    }
    // stops a previous started continouosly edge detection
    void Stop() {
        run_ = false;
        if (detect_thread_.joinable()) {
            detect_thread_.join();
        }
    }
 private:
    void FreeCamBuffers() {
        while (!buffers_.empty()) {
            delete buffers_.back();
            buffers_.pop_back();
        }
    }
    void SetupBuffers(size_t count, MemoryMode memtype) {
        int width = static_cast<int>(camera_.f().Width.Get());
        int height = static_cast<int>(camera_.f().Height.Get());
        FreeCamBuffers();
        for (size_t i = 0; i < count; ++i) {
            buffers_.push_back(new CamBuffer(width, height, memtype));
            camera_.AddUserBuffer(buffers_.back());
        }
        // allocate processing matrices because operations cannot run in place
        // some opencv versions use the wrong constructor -> create the mats objects with explicit memory type
        grey_mat_ = cv::UMat();
        gauss_mat_ = cv::UMat();
        sobel_mat_ = cv::UMat();
        grey_mat_.create(cv::Size(width, height), CV_8UC1, static_cast<cv::UMatUsageFlags>(memtype));
        gauss_mat_.create(cv::Size(width, height), CV_8UC1, static_cast<cv::UMatUsageFlags>(memtype));
        sobel_mat_.create(cv::Size(width, height), CV_8UC1, static_cast<cv::UMatUsageFlags>(memtype));
    }
    void Detect_(bool show_images) {
        try {
            while (run_) {
                NeoAPI::Image image = camera_.GetImage();
                if (image.IsEmpty()) {
                    std::cout << identifier_ << " Error during acquisition!" << std::endl;
                    break;
                } else {
                    Detect(image, show_images);
                }
            }
            if (show_images) {
                cv::destroyWindow(identifier_);
            }
        } catch (NeoAPI::NeoException& exc) {
            std::cout << identifier_ << " error: " << exc.GetDescription() << std::endl;
        } catch (cv::Exception& exc) {
            std::cout << identifier_ <<  "cv error:" << exc.msg << std::endl;
        }
    }
    NeoAPI::Cam camera_;
    std::vector<CamBuffer*> buffers_;
    cv::String identifier_;
    cv::UMat grey_mat_;
    cv::UMat gauss_mat_;
    cv::UMat sobel_mat_;
    std::thread detect_thread_;
    size_t frames_ {0};
    NeoAPI::PixelFormat pixel_format_;
    bool run_ {false};
};


在NEOAPI SDK里使用边缘检测功能对图像进行边缘检测


在相机连接后可以在NEOAPI SDK里使用OpenCV对图像进行边缘检测,C++调用代码如下所示:

#include <iostream>
#include <thread>
#include <vector>
#include <map>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core/ocl.hpp"
#include "neoapi/neoapi.hpp"
void PrintMetrics(const std::vector<EdgeDetector*>& devices, size_t duration) {
    for (size_t secs = 0; secs < duration; ++secs) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));  // print every second metrics
        for (auto device : devices) {
            std::cout << device->GetIdentifier() << " fps: " << device->ProcessedFrames() << std::endl;
        }
    }
}
void FindDevices(std::vector<EdgeDetector*> *devices) {
    for (auto device : NeoAPI::CamInfoList::Get()) {
        try {
            devices->push_back(new EdgeDetector(device.GetSerialNumber()));
        }
        catch (NeoAPI::NeoException& exc) {
            std::cout << exc.GetDescription() << std::endl;
        }
    }
    std::cout << devices->size() << " device(s) connected!" << std::endl;
}
void GetGpuCapabilities(std::map<MemoryMode, std::string> *memtypes) {
    (*memtypes)[MemoryMode::cpu] = "cpu";
    if (cv::ocl::haveOpenCL()) {
        (*memtypes)[MemoryMode::gpu] = "gpu";
        if (cv::ocl::Device::getDefault().hostUnifiedMemory()) {
            (*memtypes)[MemoryMode::shared] = "gpu with shared memory";
        }
    }
}
void RunDetection(const std::vector<EdgeDetector*> &devices,
                  const std::map<MemoryMode, std::string> &memtypes,
                  bool show_images) {
    if (devices.size()) {
        for (auto memtype : memtypes) {
            std::cout << "Next run will be processed on " << memtype.second << std::endl;
            for (auto device : devices) {
                device->Setup(memtype.first);
            }
            for (auto device : devices) {
                device->Start(show_images);
            }
            // run the detection for given time in seconds and print status informations
            PrintMetrics(devices, 5);
            for (auto device : devices) {
                device->Stop();
            }
        }
    }
}
void FreeDevices(std::vector<EdgeDetector*> *devices) {
    while (devices->size()) {
        delete devices->back();
        devices->pop_back();
    }
}
int main(int argc, char *argv[]) {
    /* Showing the images have a high impact on processing speed.
       For better comparision show_images should be disabled. */
    bool show_images = ((argc > 1) && argv);
    std::map<MemoryMode, std::string> memtypes;
    std::vector<EdgeDetector*> devices;
    // look if the gpu supports opencl and shared memory
    GetGpuCapabilities(&memtypes);
    // find all connected cameras
    FindDevices(&devices);
    // edge detection processing on all connected cameras
    RunDetection(devices, memtypes, show_images);
    // cleanup
    FreeDevices(&devices);
    return 0;
}


工业相机通过OpenCV对图像进行边缘检测的优势


工业相机通过OpenCV进行图像边缘检测具有多重优势,包括但不限于以下几点:


  1. 丰富的算法支持:OpenCV提供了多种经典的边缘检测算法,如Sobel、Canny、Laplacian等,适用于不同场景下的边缘识别需求。这意味着工业相机可以根据特定应用选择最适合的算法,以获得最佳的边缘检测效果。


  1. 高效的实时性能:OpenCV优化了多个边缘检测算法,使其在工业相机实时处理场景下表现出色。这意味着工业相机可以快速、准确地对图像进行边缘检测,适用于实时监控、自动化检测等应用。


  1. 灵活的参数设置:OpenCV的边缘检测算法通常具有可调节的参数,如阈值、卷积核大小等,使得工程师可以根据具体场景和需求进行参数优化,以获得最佳的边缘检测结果。


  1. 跨平台性和易用性:OpenCV是一个跨平台的开源库,可以在多种操作系统上运行,并提供易于使用的API和文档。这为工业相机的开发和部署提供了便利,同时也为算法调试和优化提供了支持。


  1. 结合其他图像处理功能:OpenCV不仅提供边缘检测算法,还包含了丰富的图像处理功能,如滤波、形态学操作等。工业相机可以结合这些功能与边缘检测相互配合,实现更复杂的图像处理任务。


综上所述,工业相机通过OpenCV进行图像边缘检测具有丰富的算法支持、高效的实时性能、灵活的参数设置、跨平台性和易用性以及结合其他图像处理功能等多重优势,为工业检测和自动化生产等领域提供了强大的图像处理解决方案。


工业相机使用OpenCV对图像进行边缘检测的行业应用


工业相机使用OpenCV对图像进行边缘检测在各个行业都有广泛的应用,包括但不限于以下几个方面:


  1. 制造业:工业相机结合OpenCV的边缘检测功能可用于产品质量检测、表面缺陷检测、尺寸测量等领域。通过边缘检测,可以快速准确地识别产品表面的特征和缺陷,实现自动化的质量控制。


  1. 智能制造:在智能制造领域,工业相机通过OpenCV进行边缘检测可应用于视觉导航、自动化装配等场景,帮助机器人和自动化生产线实现精确定位和操作。


  1. 医疗影像分析:工业相机与OpenCV结合可用于医学影像的边缘特征提取和分析,辅助医生进行疾病诊断和治疗。


  1. 智能交通:在智能交通领域,工业相机通过OpenCV实现的边缘检测可用于车辆识别、行人检测、交通监控等任务,提高交通系统的智能化和安全性。


  1. 农业领域:工业相机结合OpenCV的边缘检测应用于农业领域的果蔬质量检测、病虫害检测、作物生长监测等领域。


  1. 安防监控:工业相机通过OpenCV进行边缘检测可应用于安防监控领域,如人脸识别、行为分析等,帮助提高监控系统的准确性和效率。


综上所述,工业相机使用OpenCV对图像进行边缘检测在制造业、智能制造、医疗、智能交通、农业和安防监控等多个行业领域都具有重要的应用价值,为这些领域提供了高效的图像处理和分析解决方案。

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
目录
相关文章
|
7月前
|
监控 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C#)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C#)
94 0
|
4月前
|
数据采集 开发工具 Python
海康威视工业相机SDK+Python+PyQt开发数据采集系统(支持软件触发、编码器触发)
该系统基于海康威视工业相机SDK,使用Python与PyQt开发,支持Gige与USB相机设备的搜索及双相机同时显示。系统提供软件触发与编码器触发模式,并可在数据采集过程中实时保存图像。此外,用户可以调节曝光时间和增益,并进行信息输入,这些信息将被保存至配置文件以便下次自动加载。参数调节与实时预览等功能进一步增强了系统的实用性。
298 1
|
7月前
|
监控 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C++)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C++)
79 0
|
25天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
38 2
|
1月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
83 5
|
1月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
80 4
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
88 4
|
2月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
31 4
|
2月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
32 4
|
2月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
26 1

热门文章

最新文章

下一篇
DataWorks