Baumer工业相机堡盟工业相机如何通过BGAPISDK使用AutoFocus自动对焦功能(C++)

简介: Baumer工业相机堡盟工业相机如何通过BGAPISDK使用AutoFocus自动对焦功能(C++)

Baumer工业相机

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


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

Baumer工业相机由于其性能和质量的优越和稳定,常用于高速同步采集领域,通常使用各种图像算法来提高其捕获的图像的质量。


Baumer工业相机BGAPISDK和AutoFocus功能的技术背景

Baumer工业相机的BGAPI SDK是Baumer公司开发的针对其相机产品系列的一套软件开发工具包。该SDK提供了一组API,使开发人员可以编写专业应用程序,从而控制、捕获、处理和显示Baumer相机的图像和数据。BGAPI SDK支持多种编程语言,包括C++、C#、Visual Basic、LabVIEW、Matlab等,并提供了大量示例代码和文档,以帮助用户轻松上手,快速完成应用程序的开发。


BGAPI SDK提供了丰富的功能,可以控制Baumer相机的所有参数,包括曝光时间、增益、白平衡、触发模式等,以及支持各种数据格式,例如Raw、BMP、JPG等,同时还提供了实时显示、数据采集、图像处理等功能,为开发人员提供了高度定制化的解决方案。此外,BGAPI SDK还支持多相机系统的开发,并可支持各种计算机操作系统,如Windows、Linux、Mac OS等。


工业相机的AutoFocus功能是指该相机具备自动对焦功能,可以通过相机自身或外部设备(如光电传感器、激光测距仪等)对物体进行快速、精准的自动对焦。


自动对焦功能可以大大提高相机的拍摄效率和准确性,特别是在工业生产、机器视觉、智能制造等领域中,可以快速、准确地识别物体、测量尺寸和形状等参数,从而实现自动化生产和质量控制。


在选择工业相机时,需要根据具体应用场景考虑是否需要AutoFocus功能,并根据需求选择相应的对焦方式和适合的镜头。


本文介绍的使用BGAPI SDK进行使用AutoFocus功能。


Baumer工业相机通过BGAPISDK使用AutoFocus功能

下面介绍在C++里Baumer工业相机如何通过BGAPISDK使用AutoFocus功能方式


1.引用合适的类文件

代码如下(示例):

#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <set>
#include <vector>
#include <algorithm>
#include <string>
#include "bgapi2_genicam/bgapi2_genicam.hpp"

 

2.通过BGAPISDK使用AutoFocus自动对焦功能

Baumer工业相机设置自动对焦AutoFucus功能核心代码如下所示:

SystemList 
Open a System 
Get the InterfaceList and fill it Open an Interface 
Get the DeviceList and fill it 
Open a Device 
typedef struct _Result {
    int64_t sharp_value;
    int64_t lens;
    int64_t method_value;
} Result;
std::map<int64_t, Result> result_map;
//---------------------------------------------------------------------------------------------------------------------
// This example uses a Software Trigger to get images from the camera. This method will trigger regularly using 
// a separate thread to trigger and calculate in parallel.
void SoftwareTriggerThread(BGAPI2::Device* device, int64_t time_delay) {
    std::this_thread::sleep_for(std::chrono::milliseconds(time_delay));
    device->GetRemoteNode("TriggerSoftware")->Execute();
}
void ExampleAutoFocus(BGAPI2::Device* device) {
    std::thread trigger_thread;
    const uint64_t lens_delay = 70;      // A delay required for settling the liquid lens 
    const int64_t  focus_threshold = 85;  // Threshold in percent for detection of a peak!
    BGAPI2::ImageProcessor* image_processor = new BGAPI2::ImageProcessor();
    device->GetRemoteNode("AcquisitionStop")->Execute();  // to make sure that camera stopped
    BGAPI2::Node* lens_focus = device->GetRemoteNode("OpticFeatureValue");
    BGAPI2::String pixel_format = device->GetRemoteNode("PixelFormat")->GetString();
    const int image_width = static_cast<int>(device->GetRemoteNode("Width")->GetInt());
    const int image_height = static_cast<int>(device->GetRemoteNode("Height")->GetInt());
    ROI roi = {200, 200, 400, 300};   // We only use a region of the image to set the focus
    int64_t focus_start_step = 1000;  // The step size to jump for next measurement
    int64_t focus_step = focus_start_step;
    int64_t lens_focus_max = std::min(static_cast<bo_int64>(40000), lens_focus->GetIntMax());
    int64_t lens_focus_min = std::max(static_cast<bo_int64>(10000), lens_focus->GetIntMin());
    int64_t focus_value = lens_focus->GetInt();  // the start value for the algorithm
    // Detect and open the data stream
    BGAPI2::DataStreamList *datastreamList = device->GetDataStreams();
    datastreamList->Refresh();
    BGAPI2::DataStream *datastream = datastreamList->begin()->second;
    datastream->Open();
    // Add 4 buffers to the data stream
    BGAPI2::BufferList *bufferList = datastream->GetBufferList();
    for (int i = 0; i < 4; i++) {
        BGAPI2::Buffer* buffer = new BGAPI2::Buffer();
        bufferList->Add(buffer);
        buffer->QueueBuffer();
    }
    BGAPI2::Buffer* buffer_filled = nullptr;
    //------------------------------------------------------------------------------------
    // A high gain value is bad for a good auto focus (regarding noise)!
    device->GetRemoteNode(SFNC_GAINSELECTOR)->SetString(SFNC_GAINSELECTORVALUE_ALL);
    device->GetRemoteNode(SFNC_GAIN)->SetValue("1.0");
    datastream->StartAcquisitionContinuous();
    // use camera auto function to obtain well balanced images
    AutoBrightnessWhiteBalance(device, datastream, roi);
    //------------------------------------------------------------------------------------
    device->GetRemoteNode("TriggerSource")->SetString("Software");
    device->GetRemoteNode("TriggerMode")->SetString("On");
    device->GetRemoteNode("AcquisitionStart")->Execute();
    device->GetRemoteNode("TriggerSoftware")->Execute();
    int64_t sharp_min = 1L << 30;
    int64_t sharp_max = 0;
    int64_t sharp_maxno = 0;
    const std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now();
    bool is_min_focus = false;
    bool is_max_focus = false;
    bool is_finished = false;
    for (int i = 0; !is_finished; i++) {
        int64_t read_focus_value = lens_focus->GetInt();
        buffer_filled = datastream->GetFilledBuffer(1000);
        if (buffer_filled == nullptr) {
            std::cout << "Error: Buffer Timeout after 1000 ms" << std::endl;
            device->GetRemoteNode("TriggerSoftware")->Execute();
        } else if (buffer_filled->GetIsIncomplete() == true) {
            std::cout << "Error: Image is incomplete" << std::endl;
            buffer_filled->QueueBuffer();
        } else {  
            // get a correct picture, check the calculated value and calculate the next step
            //=======================================================
            if (lens_focus) {
                int64_t next_focus = focus_value + focus_step;
                if (next_focus > lens_focus_max)
                    is_max_focus = true;
                if (next_focus < lens_focus_min)
                    is_min_focus = true;
                if (is_min_focus && is_max_focus) {
                    is_finished = true; break;  // reached both limits!
                }
                if (!is_min_focus && !is_max_focus) {
                    if (focus_step > 0) {
                        focus_step = -focus_step - focus_start_step;
                        if (next_focus + focus_step < lens_focus_min) {
                            is_min_focus = true;
                            focus_step = +focus_start_step;
                        }
                    } else {
                        focus_step = -focus_step + focus_start_step;
                        if (next_focus + focus_step > lens_focus_max) {
                            is_max_focus = true;
                            focus_step = -focus_start_step;
                        }
                    }
                } else {
                    if (!is_min_focus) {
                        focus_step = -focus_start_step;
                    } else if (!is_max_focus) {
                        focus_step = +focus_start_step;
                    }
                    next_focus = focus_value + focus_step;
                }
                focus_value = next_focus;
                if (focus_value > lens_focus_max) {
                    is_finished = true;
                }
                //=======================================================
                if (!is_finished) {  // -> next setting and image
                    lens_focus->SetInt(focus_value);
                    trigger_thread = std::thread(&SoftwareTriggerThread, device, lens_delay);
                }
                void* buffer_pointer = buffer_filled->GetMemPtr();
                uint64_t buffer_size = buffer_filled->GetSizeFilled();
                BGAPI2::Image* image = image_processor->CreateImage(image_width, image_height,
                    pixel_format, buffer_pointer, buffer_size);
                CheckAndFixRoi(&roi, image_width, image_height);
#if USE_OPENCV
                // Display the image
                if (pixel_format == "Mono8") {
                    ShowImage(buffer_pointer, image_width, image_height, CV_8UC1, &roi);
                } else {
                    // Convert to BGR8
                    const size_t size = static_cast<size_t>(image->GetTransformBufferLength("BGR8"));
                    char* mem_buffer = new char[size];
                    if (mem_buffer) {
                        image_processor->TransformImageToBuffer(image, "BGR8", mem_buffer, size);
                        ShowImage(mem_buffer, image_width, image_height, CV_8UC3, &roi);
                        delete[] mem_buffer;
                    }
                }
#endif
                // Convert to Mono8 for measurement sharpness
                const size_t size = static_cast<size_t>(image->GetTransformBufferLength("Mono8"));
                uint8_t* mem_buffer = new uint8_t[size];
                if (mem_buffer) {
                    image_processor->TransformImageToBuffer(image, "Mono8", mem_buffer, size);
                    int64_t sharpness = 0;
                    //-----------------------------------------------------------------
                    // The algorithm for measurement of sharp:
                    // Here you can use: prewitt, sobel, scharr - or you use an own algorithm like
                    // open_cv laplacian, DFT (FFT), canny or something else
                    // we use Sobel Sharpening! see HelperFuntions -> sobel matrix
                    sharpness = CrossCalculateMono(mem_buffer, image_width, image_height,
                        sobel_x, sobel_y, roi);
                    //-----------------------------------------------------------------
                    result_map[read_focus_value].lens = read_focus_value;
                    result_map[read_focus_value].method_value = sharpness;
                    if (sharpness < sharp_min) {
                        sharp_min = sharpness;
                    }
                    if (sharpness > sharp_max) {
                        sharp_max = sharpness;
                        sharp_maxno = read_focus_value;
                    }
                    if (sharpness < (focus_threshold * sharp_max) / 100) {
                        if (read_focus_value < sharp_maxno) {
                            is_min_focus = true;
                        } else {
                            is_max_focus = true;
                        }
                    }
                    delete[] mem_buffer;
                }
                buffer_filled->QueueBuffer();
            }
        }
        if (trigger_thread.joinable())
            trigger_thread.join();
    }
    int64_t meanvalue = 0;
    int64_t meancount = 0;
    int64_t auto_focus_value = -1;
    int64_t new_focus = -1;
    int64_t max_sharpness = sharp_max;
    lens_focus_min = lens_focus_max = -1;
    for (auto result : result_map) {
        if (lens_focus_min < 0)
            lens_focus_min = result.first;
        if (result.second.method_value * 100 > focus_threshold * max_sharpness) {
            lens_focus_max = result.first;
            meanvalue +=
                result.second.method_value * (result.first - lens_focus_min);
            meancount++;
        } else if (lens_focus_max < 0)
            lens_focus_min = result.first;
    }
    int64_t outside_min = -1;
    int64_t outside_max = -1;
    for (auto result : result_map) {
        if (result.second.method_value * 100 > focus_threshold * max_sharpness) {
            outside_max = result.first;
        } else if (outside_max < 0) {
            outside_min = result.first;
        } else {
            outside_max = result.first;
            break;
        }
    }
    if (outside_min > 0 && outside_max > 0 &&
        (result_map.find(outside_min + 1000) != result_map.end()) &&
        (result_map.find(outside_max - 1000) != result_map.end())) {
        int64_t threshold = (focus_threshold * max_sharpness) / 100;
        int64_t min = 1000 * (threshold - result_map[outside_min].method_value) /
            (result_map[outside_min + 1000].method_value - result_map[outside_min].method_value);
        outside_min += min;
        int64_t max = 1000 * (threshold - result_map[outside_min].method_value) /
            (result_map[outside_max - 1000].method_value - result_map[outside_min].method_value);
        outside_max -= max;
        new_focus = (outside_min + outside_max) / 2;
    }
    if (new_focus < 0) {
        new_focus = sharp_maxno;
    }
    if (lens_focus && (new_focus > lens_focus_min) && (new_focus < lens_focus_max)) {
        auto_focus_value = new_focus;
        lens_focus->SetInt(auto_focus_value); // set the new calculated value to the camera!
#if USE_OPENCV
        // read an image and show it (if you use OpenCV)
        SoftwareTriggerThread(device, lens_delay);
        buffer_filled = datastream->GetFilledBuffer(1000);
        if (buffer_filled) {
            BGAPI2::Image* image = image_processor->CreateImage(image_width, image_height,
                buffer_filled->GetPixelFormat(), buffer_filled->GetMemPtr(), 
                buffer_filled->GetSizeFilled());
            const size_t size = static_cast<size_t>(image->GetTransformBufferLength("BGR8"));
            char* mem_buffer = new char[size];
            if (mem_buffer) {
                image_processor->TransformImageToBuffer(image, "BGR8", mem_buffer, size);
                ShowImage(mem_buffer, image_width, image_height, CV_8UC3, nullptr);
            }
            buffer_filled->QueueBuffer();
        } else {
            std::cout << "don't get last buffer!" << std::endl;
        }
#endif
        std::chrono::duration<double, std::milli> overall_delay =
            std::chrono::system_clock::now() - start_time;
        std::cout << "AutoFocus finished after " << overall_delay.count() << "ms and " <<
            result_map.size() << " images, focus value = " << auto_focus_value << "!" << std::endl;
    } else {
        std::cout << "The camera couldn't focused correctly!" << std::endl;
    }
    // clean up camera and buffers
    device->GetRemoteNode("AcquisitionAbort")->Execute();
    device->GetRemoteNode("AcquisitionStop")->Execute();
    device->GetRemoteNode("TriggerMode")->SetString("Off");
    datastream->StopAcquisition();
    bufferList->DiscardAllBuffers();
    while (bufferList->size() > 0) {
        BGAPI2::Buffer* buffer = bufferList->begin()->second;
        bufferList->RevokeBuffer(buffer);
        delete buffer;
    }
    datastream->Close();
    if (image_processor != nullptr) {
        delete image_processor;
        image_processor = nullptr;
    }
}

3.通过BGAPISDK运行测试AutoFocus自动对焦功能

SystemList 
Open a System 
Get the InterfaceList and fill it Open an Interface 
Get the DeviceList and fill it 
Open a Device 
int main(int numArgs, char *args[]) 
{
    int returncode = 0;
    int64_t camfound = 0;
    std::cout << "BGAPI2 Example 503 - AutoFocus"  << std::endl;
#ifndef USE_OPENCV   // OpenCV
    // this part is use if no matching OpenCV found in CMake!
    std::cout << "Without OpenCV buffer images are not shown on screen and not saved to files!" << std::endl;
    std::cout << "Availability of OpenCV is checked while CMake creates this project." << std::endl;
    std::cout << "Please install OpenCV (version 2.3 or later) or set 'OpenCV_DIR' to the" << std::endl;
    std::cout << "correct path in the CMakeList.txt script or as a variable in your environment" << std::endl;
    std::cout << "and run CMake again. " << std::endl;
    std::cout << "######################################" << std::endl << std::endl;
#endif  // USE_OPENCV
    try {
        // First search for a camera which supports the liquid lens
        // We use the feature "OpticFeatureValue" to check if the camera supports the liquid lens
        // Get the list of systems and loop through
        BGAPI2::SystemList *system_list = BGAPI2::SystemList::GetInstance();
        system_list->Refresh();
        for (auto system_pair : *system_list) {
            auto system = system_pair->second;  // gige, usb3, ..
            system->Open();
            // Get the list of interfaces on the system and loop through
            auto interface_list = system->GetInterfaces();
            interface_list->Refresh(100);
            for (auto interface_pair : *interface_list) {
                auto interface = interface_pair->second;
                interface->Open();
                auto device_list = interface->GetDevices();
                device_list->Refresh(100);
                // Get the list of devices and loop though them to find a camera supporting a liquid lens
                for (auto device_pair: *device_list) {
                    BGAPI2::Device* device = device_pair->second;
                    device->Open();
                    std::stringstream camera_name;
                    camera_name << device->GetModel() << "(SN = " << device->GetSerialNumber() << ")";
                    if (device->GetRemoteNodeList()->GetNodePresent("OpticFeatureValue")) {
                        if (!device->GetRemoteNode("OpticFeatureValue")->IsWriteable()) {
                            continue;
                        }
                    } else {
                        continue;
                    }
                    std::cout << "Camera found!" << std::endl;
#ifdef _DEBUG
                    // Switch off the heartbeat in debug mode, otherwise the camera might disconnect during debug!
                    if (device->GetRemoteNodeList()->GetNodePresent("DeviceLinkHeartbeatMode"))
                        device->GetRemoteNode("DeviceLinkHeartbeatMode")->SetString("Off");
#endif
                    // no try to focus the camera
                    ExampleAutoFocus(device);
#ifdef _DEBUG
                    // Switch the heartbeat back on
                    if (device->GetRemoteNodeList()->GetNodePresent("DeviceLinkHeartbeatMode"))
                        device->GetRemoteNode("DeviceLinkHeartbeatMode")->SetString("On");
#endif
                    // close the camera
                    device->Close();
                    camfound = 1;
                    break;  // if one camera found!
                }
                interface->Close();
                if (camfound)
                    break;  // if one camera found!
            }
            system->Close();
            if (camfound)
                break;  // if one camera found!
        }
        if (camfound == 0) {
            std::cout << "No camera found on any system and any interface!" << std::endl;
        }
    }
    catch (BGAPI2::Exceptions::IException& ex) {
        returncode = (returncode == 0) ? 1 : returncode;
        std::cout << "Error in function: " << ex.GetFunctionName() << std::endl << "Error description: "
            << ex.GetErrorDescription() << std::endl << std::endl;
    }
    BGAPI2::SystemList::ReleaseInstance();
#ifdef USE_OPENCV   // OpenCV
    // Wait a delay
    cv::waitKey(10000);  // show a little while of 5 seconds the focused image
    cv::destroyAllWindows();
#else
    for (int i = 0; i < 5; i++) {  // a little while of 5 seconds...
      std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
#endif
    return returncode;
}

Baumer工业相机使用AutoFocus自动对焦功能的优势

工业相机使用AutoFocus自动对焦功能有以下优势:


提高工作效率:自动对焦功能可以快速、准确地识别并对焦目标物体,避免了手动调节对焦焦距带来的时间浪费。因此,使用自动对焦功能可以提高生产效率,节省时间和人力成本。


提高测量精度:自动对焦功能可以根据不同的拍摄距离和物体大小,自动调整对焦焦距,保证图像清晰度和测量精度。


适应不同场景:自动对焦功能适应范围广泛,可以应用于工业生产、机器视觉、智能制造等多个领域中,对于不同大小、不同形状的目标物体均能有效识别并对焦,具有很高的通用性。


减少使用难度:相对于手动调节对焦焦距,自动对焦功能更易于操作和使用,减少了对操作人员技术水平的要求,也降低了需要培训的成本。


总之,自动对焦功能是现代工业相机的重要功能之一,对于提高工作效率、测量精度和操作便利性都有很大的帮助。


Baumer工业相机使用AutoFocus自动对焦功能的行业应用

工业相机使用AutoFocus自动对焦功能在许多行业具有广泛的应用价值,以下是一些常见的行业应用:


机器视觉检测:自动对焦功能可以帮助机器视觉系统自动识别各种零件,进行尺寸测量、外观检测和定位等。这在制造业、电子行业、汽车行业等领域具有重要价值。


材料科学与无损检测:借助自动对焦功能,工业相机可用于对材料表面进行精确的缺陷检测(如裂纹、气孔等),提高检测的准确性和速度,用于金属制品、塑料制品等行业。


医疗健康:利用自动对焦功能,工业相机可以提供精确的成像数据,辅助进行病理分析、影像诊断等医学应用。例如,在显微镜成像、内窥镜成像等医学设备中进行快速对焦。


生物科技:自动对焦功能可用于生物制品样品检测、显微成像、基因芯片成像等领域,实现高速、高精度的图像处理与分析。


半导体工业:自动对焦可用于芯片制程的检测与质量控制,检查晶圆、封装等组件的缺陷。减少缺陷率,监控生产质量。


能源行业:工业相机的自动对焦功能可以应用于太阳能电池板、核电站等能源设施的检测与维护,保障设备的正常运行与安全。


安防监控:自动对焦功能可用于监控摄像头的调整与控制,确保拍摄到清晰的监控图像,提高安防系统的效果。


总之,在各行业应用中,工业相机使用AutoFocus自动对焦功能可以提高图像处理速度和准确性,实现对目标物体的快速捕捉和检测,提高生产效率和质量。

目录
相关文章
|
5天前
|
设计模式 uml C++
C++中的装饰器模式:灵活地扩展功能
C++中的装饰器模式:灵活地扩展功能
36 0
|
5天前
|
算法 C语言 C++
C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)(一)
C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)
181 1
|
5天前
|
缓存 算法 安全
C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)(三)
C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)
61 1
|
5天前
|
安全 调度 C++
C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)(二)
C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)
116 0
|
3天前
|
存储 安全 C语言
C++|多态性与虚函数(1)功能绑定|向上转换类型|虚函数
C++|多态性与虚函数(1)功能绑定|向上转换类型|虚函数
|
5天前
|
算法 编译器 C++
【C++入门到精通】新的类功能 | 可变参数模板 C++11 [ C++入门 ]
【C++入门到精通】新的类功能 | 可变参数模板 C++11 [ C++入门 ]
23 1
|
5天前
|
搜索推荐 算法 大数据
【C++ 标准库排序算法】C++标准库中的排序算法深入解析:功能、原理与应用
【C++ 标准库排序算法】C++标准库中的排序算法深入解析:功能、原理与应用
54 0
|
5天前
|
算法 数据安全/隐私保护 C++
【C/C++ 编程题 03】用两个栈实现一个队列的功能
【C/C++ 编程题 03】用两个栈实现一个队列的功能
16 0
|
5天前
|
算法 编译器 C语言
【C/C++ 编程题 02】用两个栈实现一个队列的功能
【C/C++ 编程题 02】用两个栈实现一个队列的功能
21 0
|
5天前
|
存储 设计模式 uml
C++备忘录模式实践:轻松实现撤销与恢复功能
C++备忘录模式实践:轻松实现撤销与恢复功能
40 0