Initial commit
This commit is contained in:
commit
2d5f6b625e
12 changed files with 1162 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
build/
|
||||
33
femtoCAM.pro
Normal file
33
femtoCAM.pro
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
CONFIG += c++17
|
||||
|
||||
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += aravis-0.10 opencv4
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
idscam.cpp \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
processing.cpp
|
||||
|
||||
HEADERS += \
|
||||
framebatch.h \
|
||||
idscam.h \
|
||||
mainwindow.h \
|
||||
processing.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
227
femtoCAM.pro.user
Normal file
227
femtoCAM.pro.user
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 17.0.2, 2025-10-24T23:48:06. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{be9215e2-482c-41d7-992e-2ab1dc0ca384}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="qlonglong">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoDetect">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.LineEndingBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value>
|
||||
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">2</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
|
||||
<value type="bool" key="AutoTest.Framework.Boost">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.CTest">false</value>
|
||||
<value type="bool" key="AutoTest.Framework.Catch">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.GTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
||||
</valuemap>
|
||||
<value type="bool" key="AutoTest.ApplyFilter">false</value>
|
||||
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
||||
<valuelist type="QVariantList" key="AutoTest.PathFilters"/>
|
||||
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
||||
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
||||
<valuemap type="QVariantMap" key="ClangTools">
|
||||
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">8</value>
|
||||
<value type="bool" key="ClangTools.PreferConfigFile">true</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="DeviceType">Desktop</value>
|
||||
<value type="bool" key="HasPerBcDcs">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{88705c22-1dff-443a-bd85-c7eb89196b97}</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/gryhsh/Documents/Projekte/femtoCAM/build/Desktop-Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/gryhsh/Documents/Projekte/femtoCAM/build/Desktop-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Erstellen</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Erstellen</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Bereinigen</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges">
|
||||
<value type="QString">PKG_CONFIG_PATH=/usr/local/lib/pkgconfig</value>
|
||||
</valuelist>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deployment</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/gryhsh/Documents/Projekte/femtoCAM/femtoCAM.pro</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/gryhsh/Documents/Projekte/femtoCAM/build/Desktop-Debug</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deployment</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/gryhsh/Documents/Projekte/femtoCAM/femtoCAM.pro</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/gryhsh/Documents/Projekte/femtoCAM/build/Desktop-Debug</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="qlonglong">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
29
framebatch.h
Normal file
29
framebatch.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef FRAMEBATCH_H
|
||||
#define FRAMEBATCH_H
|
||||
|
||||
#define BATCHSIZE 100
|
||||
#define MAX_BATCHES 10
|
||||
#define N_THREADS 1
|
||||
|
||||
#include "arv.h"
|
||||
|
||||
struct ProcessingConfig {
|
||||
int thresholdValue = 128;
|
||||
bool adaptive = false;
|
||||
int adaptiveBlocksize = 11;
|
||||
int adaptiveShift = 2;
|
||||
int contourMinSize = 3;
|
||||
int contourMinArea = 5;
|
||||
int contourMaxArea = 1000;
|
||||
bool correctDoubleHits = true;
|
||||
int numDatapoints = 4;
|
||||
};
|
||||
|
||||
struct alignas(64) FrameBatch {
|
||||
static constexpr int BatchSize = BATCHSIZE;
|
||||
ArvBuffer* frames[BatchSize];
|
||||
quint64 frame_no[BatchSize]; // Possibly optional if constructing takes too long
|
||||
int count = 0;
|
||||
};
|
||||
|
||||
#endif // FRAMEBATCH_H
|
||||
263
idscam.cpp
Normal file
263
idscam.cpp
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
#include "idscam.h"
|
||||
|
||||
IdsCam::IdsCam()
|
||||
{
|
||||
connect(&timer, &QTimer::timeout, this, &IdsCam::buffer_polling);
|
||||
workers.setMaxThreadCount(N_THREADS);
|
||||
}
|
||||
|
||||
void IdsCam::update_av_cams()
|
||||
{
|
||||
arv_update_device_list();
|
||||
uint n = arv_get_n_devices();
|
||||
for(uint i = 0; i<n; i++)
|
||||
{
|
||||
av_cams_info.append(QString("%1: %2").arg(arv_get_device_model(i)).arg(arv_get_device_serial_nbr(i)));
|
||||
qDebug() << "Device: " << av_cams_info.at(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void IdsCam::select_cam(uint id)
|
||||
{
|
||||
if(camera != nullptr)
|
||||
g_clear_object(&camera);
|
||||
|
||||
camera = arv_camera_new(arv_get_device_id(id), &error);
|
||||
|
||||
uint n;
|
||||
// Update av. pixel formats
|
||||
av_pixel_formats.clear();
|
||||
const char** labels = arv_camera_dup_available_pixel_formats_as_strings(camera, &n, &error);
|
||||
for (uint i = 0; i<n; i++)
|
||||
av_pixel_formats.append(labels[i]);
|
||||
|
||||
// Update av. trigger sources
|
||||
av_trig_sources.clear();
|
||||
const char** trigs = arv_camera_dup_available_trigger_sources(camera, &n, &error);
|
||||
for (uint i = 0; i<n; i++)
|
||||
av_trig_sources.append(trigs[i]);
|
||||
|
||||
exposure_time = arv_camera_get_exposure_time(camera, &error);
|
||||
frame_rate = arv_camera_get_frame_rate(camera, &error);
|
||||
gain = arv_camera_get_gain(camera, &error);
|
||||
}
|
||||
|
||||
void IdsCam::set_pixel_format(int idx)
|
||||
{
|
||||
arv_camera_set_pixel_format_from_string(camera, reinterpret_cast<char *>(av_pixel_formats.at(idx).toLocal8Bit().data()), &error);
|
||||
qDebug() << "Selected new Pixel format " << av_pixel_formats.at(idx);
|
||||
if(error != nullptr)
|
||||
qDebug() << error->message;
|
||||
}
|
||||
|
||||
void IdsCam::set_exposure_time(double val)
|
||||
{
|
||||
arv_camera_set_exposure_time(camera, val, &error);
|
||||
qDebug() << "Setting new exposure time: " << val;
|
||||
if(error != nullptr)
|
||||
qDebug() << error->message;
|
||||
|
||||
exposure_time = arv_camera_get_exposure_time(camera, &error);
|
||||
}
|
||||
|
||||
void IdsCam::set_frame_rate(double val)
|
||||
{
|
||||
arv_camera_set_frame_rate(camera, val, &error);
|
||||
qDebug() << "New Framerate: " << val;
|
||||
if(error != nullptr)
|
||||
qDebug() << error->message;
|
||||
|
||||
frame_rate = arv_camera_get_frame_rate(camera, &error);
|
||||
}
|
||||
|
||||
void IdsCam::set_gain(double val)
|
||||
{
|
||||
arv_camera_set_gain(camera, val, &error);
|
||||
qDebug() << "New Gain: " << val;
|
||||
if(error != nullptr)
|
||||
qDebug() << error->message;
|
||||
|
||||
gain = arv_camera_get_gain(camera, &error);
|
||||
}
|
||||
|
||||
void IdsCam::set_trig(uint idx)
|
||||
{
|
||||
arv_camera_set_trigger_source(camera, reinterpret_cast<char *>(av_trig_sources.at(idx).toLocal8Bit().data()), &error);
|
||||
qDebug() << "Selected new Trig source " << av_trig_sources.at(idx);
|
||||
if(error != nullptr)
|
||||
qDebug() << error->message;
|
||||
}
|
||||
|
||||
bool IdsCam::setup_buffering()
|
||||
{
|
||||
if (ARV_IS_CAMERA (camera)) {
|
||||
arv_camera_set_acquisition_mode (camera, ARV_ACQUISITION_MODE_CONTINUOUS, &error);
|
||||
|
||||
callback_data.counter = 0;
|
||||
callback_data.counter_total = 0;
|
||||
callback_data.stream = NULL;
|
||||
if(callback_data.cur != nullptr)
|
||||
delete callback_data.cur;
|
||||
callback_data.cur = new FrameBatch{};
|
||||
callback_data.pendingData = &pendingData;
|
||||
callback_data.pendingMutex = &pendingMutex;
|
||||
|
||||
if (error == NULL)
|
||||
/* Create the stream object with callback */
|
||||
callback_data.stream = arv_camera_create_stream (camera, stream_callback, &callback_data, nullptr, &error);
|
||||
|
||||
if (ARV_IS_STREAM (callback_data.stream)) {
|
||||
int i;
|
||||
size_t payload;
|
||||
|
||||
/* Retrieve the payload size for buffer creation */
|
||||
payload = arv_camera_get_payload (camera, &error);
|
||||
if (error == NULL) {
|
||||
/* Insert some buffers in the stream buffer pool */
|
||||
for (i = 0; i < BATCHSIZE*MAX_BATCHES; i++)
|
||||
arv_stream_push_buffer (callback_data.stream, arv_buffer_new (payload, NULL));
|
||||
}
|
||||
|
||||
if (error == NULL)
|
||||
{
|
||||
/* Start the acquisition */
|
||||
arv_camera_start_acquisition (camera, &error);
|
||||
timer.start(500);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
bool IdsCam::stop_buffering()
|
||||
{
|
||||
arv_camera_stop_acquisition (camera, &error);
|
||||
if (error == NULL)
|
||||
{
|
||||
// will free all the buffers still in its queues when destroyed => push back all frames that were still pending
|
||||
qDebug() << "Stopping... Discharding last " << callback_data.counter << " frames";
|
||||
for(int i=0; i<callback_data.counter; i++)
|
||||
arv_stream_push_buffer(callback_data.stream, callback_data.cur->frames[i]);
|
||||
buffer_polling();
|
||||
|
||||
// Wait for data analysis finishing TODO: show software is busy
|
||||
workers.waitForDone();
|
||||
|
||||
g_clear_object(&callback_data.stream);
|
||||
timer.stop();
|
||||
//delete arv_buffer_get_user_data(callback_data.pendingData->at(0)->frames[0]);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void IdsCam::buffer_polling()
|
||||
{
|
||||
quint64 n;
|
||||
int pending_n;
|
||||
{
|
||||
QMutexLocker locker(callback_data.pendingMutex);
|
||||
n = callback_data.counter_total;
|
||||
pending_n = callback_data.pendingData->length();
|
||||
}
|
||||
emit new_status_text(QString("Total: %1 | Buf: %2/%3").arg(n).arg(pending_n).arg(MAX_BATCHES));
|
||||
|
||||
if(pending_n > 0)
|
||||
{
|
||||
ArvBuffer* ptr = nullptr;
|
||||
{
|
||||
QMutexLocker locker(callback_data.pendingMutex);
|
||||
ptr = callback_data.pendingData->at(0)->frames[0];
|
||||
}
|
||||
ProcessingResult res = processArvBuffer(ptr, pro_cfg);
|
||||
const void* data = arv_buffer_get_data(ptr, nullptr);
|
||||
guint32 width = arv_buffer_get_image_width(ptr);
|
||||
guint32 height = arv_buffer_get_image_height(ptr);
|
||||
//ArvPixelFormat pix_format = arv_buffer_get_image_pixel_format(ptr);
|
||||
QImage image((uchar*)data, width, height, QImage::Format_Grayscale8);
|
||||
|
||||
emit vis_new_frame(drawHitsOnGrayImage(image, res));
|
||||
}
|
||||
|
||||
if(workers.activeThreadCount() < workers.maxThreadCount())
|
||||
for(int i = 0; i<pending_n; i++)
|
||||
{
|
||||
FrameBatch* batch_ptr;
|
||||
{
|
||||
QMutexLocker locker(callback_data.pendingMutex);
|
||||
batch_ptr = callback_data.pendingData->takeFirst();
|
||||
}
|
||||
Worker *w = new Worker(batch_ptr, callback_data.stream);
|
||||
workers.start(w);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void stream_callback(void *user_data, ArvStreamCallbackType type, ArvBuffer *buffer)
|
||||
{
|
||||
ArvStreamCallbackData *callback_data = (ArvStreamCallbackData *) user_data;
|
||||
|
||||
/* This code is called from the stream receiving thread, which means all the time spent there is less time
|
||||
* available for the reception of incoming packets */
|
||||
|
||||
switch (type) {
|
||||
case ARV_STREAM_CALLBACK_TYPE_INIT:
|
||||
/* Stream thread started.
|
||||
*
|
||||
* Here you may want to change the thread priority arv_make_thread_realtime() or
|
||||
* arv_make_thread_high_priority() */
|
||||
break;
|
||||
case ARV_STREAM_CALLBACK_TYPE_START_BUFFER:
|
||||
/* The first packet of a new frame was received */
|
||||
break;
|
||||
case ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE:
|
||||
/* The buffer is received, successfully or not. It is already pushed in the output FIFO.
|
||||
*
|
||||
* You could here signal the new buffer to another thread than the main one, and pull/push the
|
||||
* buffer from this another thread.
|
||||
*
|
||||
* Or use the buffer here. We need to pull it, process it, then push it back for reuse by the
|
||||
* stream receiving thread */
|
||||
|
||||
g_assert (buffer == arv_stream_pop_buffer(callback_data->stream));
|
||||
g_assert (buffer != NULL);
|
||||
|
||||
if (arv_buffer_get_status(buffer) == ARV_BUFFER_STATUS_SUCCESS)
|
||||
{
|
||||
//qDebug() << "Acquired buffer " << arv_buffer_get_image_width(buffer) << " x " << arv_buffer_get_image_height(buffer);
|
||||
callback_data->cur->frames[callback_data->counter] = buffer;
|
||||
callback_data->cur->frame_no[callback_data->counter] = callback_data->counter_total;
|
||||
callback_data->counter++;
|
||||
if(callback_data->counter == BATCHSIZE)
|
||||
{
|
||||
{
|
||||
QMutexLocker locker(callback_data->pendingMutex);
|
||||
callback_data->pendingData->append(callback_data->cur);
|
||||
qDebug() << "New Batch started, current batch num: " << callback_data->pendingData->size();
|
||||
}
|
||||
callback_data->cur = new FrameBatch{};
|
||||
callback_data->counter = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//qDebug() << "ARV_BUFFER_STATUS was not OK; failed frame! Pushing frame back in buffer " << arv_buffer_get_status(buffer);
|
||||
arv_stream_push_buffer(callback_data->stream, buffer);
|
||||
}
|
||||
callback_data->counter_total++;
|
||||
|
||||
//arv_stream_push_buffer(callback_data->stream, buffer); TODO!!
|
||||
//callback_data->counter++;
|
||||
|
||||
break;
|
||||
case ARV_STREAM_CALLBACK_TYPE_EXIT:
|
||||
/* Stream thread ended */
|
||||
break;
|
||||
}
|
||||
}
|
||||
71
idscam.h
Normal file
71
idscam.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#ifndef IDSCAM_H
|
||||
#define IDSCAM_H
|
||||
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
#include <QList>
|
||||
#undef signals
|
||||
#include <arv.h>
|
||||
#undef signals
|
||||
#define signals Q_SIGNALS
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QTimer>
|
||||
#include <QImage>
|
||||
|
||||
#include "processing.h"
|
||||
#include "framebatch.h"
|
||||
|
||||
typedef struct {
|
||||
ArvStream *stream;
|
||||
QList<FrameBatch*> *pendingData;
|
||||
QMutex *pendingMutex;
|
||||
uint counter;
|
||||
quint64 counter_total;
|
||||
FrameBatch *cur = nullptr;
|
||||
} ArvStreamCallbackData;
|
||||
|
||||
static void stream_callback(void *user_data, ArvStreamCallbackType type, ArvBuffer *buffer);
|
||||
|
||||
class IdsCam : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IdsCam();
|
||||
void update_av_cams();
|
||||
void select_cam(uint id);
|
||||
void set_pixel_format(int idx);
|
||||
void set_exposure_time(double val);
|
||||
void set_frame_rate(double val);
|
||||
void set_gain(double val);
|
||||
void set_trig(uint idx);
|
||||
bool setup_buffering();
|
||||
bool stop_buffering();
|
||||
void buffer_polling();
|
||||
|
||||
QList<QString> av_cams_info{};
|
||||
QList<QString> av_pixel_formats{};
|
||||
QList<QString> av_trig_sources{};
|
||||
double exposure_time = 0;
|
||||
double frame_rate = 0;
|
||||
double gain = 0;
|
||||
|
||||
ArvStream *stream = NULL;
|
||||
private:
|
||||
ArvCamera *camera = nullptr;
|
||||
GError *error = NULL;
|
||||
ArvStreamCallbackData callback_data;
|
||||
QMutex pendingMutex;
|
||||
QList<FrameBatch*> pendingData;
|
||||
|
||||
QTimer timer;
|
||||
|
||||
QThreadPool workers{};
|
||||
ProcessingConfig pro_cfg{};
|
||||
signals:
|
||||
void new_status_text(QString text);
|
||||
void vis_new_frame(QImage img);
|
||||
};
|
||||
|
||||
#endif // IDSCAM_H
|
||||
11
main.cpp
Normal file
11
main.cpp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
102
mainwindow.cpp
Normal file
102
mainwindow.cpp
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
cam.update_av_cams();
|
||||
foreach (QString info, cam.av_cams_info)
|
||||
ui->cam_selector->addItem(info);
|
||||
handle_cam_selector(0);
|
||||
|
||||
ui->liveView->setPixmap(liveview_pixmap);
|
||||
|
||||
connect(ui->cam_selector, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::handle_cam_selector);
|
||||
connect(ui->pixel_format_selector, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::handle_pixel_format_selector);
|
||||
connect(ui->triggerSource, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::handle_new_trig);
|
||||
|
||||
connect(ui->exposureTime, &QDoubleSpinBox::editingFinished, this, &MainWindow::handle_new_exposure_time);
|
||||
connect(ui->frameRate, &QDoubleSpinBox::editingFinished, this, &MainWindow::handle_new_frame_rate);
|
||||
connect(ui->gain, &QDoubleSpinBox::editingFinished, this, &MainWindow::handle_new_gain);
|
||||
|
||||
connect(ui->startButton, &QPushButton::clicked, this, &MainWindow::handle_start_button);
|
||||
|
||||
connect(&cam, &IdsCam::new_status_text, ui->infotext, &QLabel::setText);
|
||||
connect(&cam, &IdsCam::vis_new_frame, this, &MainWindow::visualize_new_frame);
|
||||
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::handle_cam_selector(int i)
|
||||
{
|
||||
cam.select_cam(i);
|
||||
ui->pixel_format_selector->clear();
|
||||
foreach(QString mode, cam.av_pixel_formats)
|
||||
ui->pixel_format_selector->addItem(mode);
|
||||
|
||||
ui->triggerSource->clear();
|
||||
foreach (QString trig, cam.av_trig_sources)
|
||||
ui->triggerSource->addItem(trig);
|
||||
|
||||
ui->exposureTime->setValue(cam.exposure_time);
|
||||
ui->frameRate->setValue(cam.frame_rate);
|
||||
ui->gain->setValue(cam.gain);
|
||||
}
|
||||
|
||||
void MainWindow::handle_pixel_format_selector(int i)
|
||||
{
|
||||
if(i != -1)
|
||||
cam.set_pixel_format(i);
|
||||
}
|
||||
|
||||
void MainWindow::handle_new_exposure_time()
|
||||
{
|
||||
cam.set_exposure_time(ui->exposureTime->value());
|
||||
ui->exposureTime->setValue(cam.exposure_time);
|
||||
}
|
||||
|
||||
void MainWindow::handle_new_frame_rate()
|
||||
{
|
||||
cam.set_frame_rate(ui->frameRate->value());
|
||||
ui->frameRate->setValue(cam.frame_rate);
|
||||
}
|
||||
|
||||
void MainWindow::handle_new_gain()
|
||||
{
|
||||
cam.set_gain(ui->gain->value());
|
||||
ui->gain->setValue(cam.gain);
|
||||
}
|
||||
|
||||
void MainWindow::handle_new_trig(int i)
|
||||
{
|
||||
if(i != -1)
|
||||
cam.set_trig(i);
|
||||
}
|
||||
|
||||
void MainWindow::handle_start_button()
|
||||
{
|
||||
if (ui->startButton->text() == "Start")
|
||||
{
|
||||
qDebug("Setting up Buffering");
|
||||
if(cam.setup_buffering())
|
||||
ui->startButton->setText("Stop");
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("Stopping Buffering");
|
||||
if(cam.stop_buffering())
|
||||
ui->startButton->setText("Start");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::visualize_new_frame(QImage img)
|
||||
{
|
||||
//QPixmap *map = ui->liveView->setPixmap();
|
||||
ui->liveView->setPixmap(QPixmap::fromImage(img));
|
||||
}
|
||||
37
mainwindow.h
Normal file
37
mainwindow.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QPixmap>
|
||||
#include "idscam.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
IdsCam cam{};
|
||||
void handle_cam_selector(int i);
|
||||
void handle_pixel_format_selector(int i);
|
||||
void handle_new_exposure_time();
|
||||
void handle_new_frame_rate();
|
||||
void handle_new_gain();
|
||||
void handle_new_trig(int i);
|
||||
void handle_start_button();
|
||||
QPixmap liveview_pixmap{};
|
||||
|
||||
public slots:
|
||||
void visualize_new_frame(QImage img);
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
231
mainwindow.ui
Normal file
231
mainwindow.ui
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="liveView">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Hack</family>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Camera Settings</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cam_selector"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Pixel Format</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="pixel_format_selector"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Exposure [μs]</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="exposureTime">
|
||||
<property name="maximum">
|
||||
<double>10000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Framerate [Hz]</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="frameRate">
|
||||
<property name="maximum">
|
||||
<double>800.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Gain [dB]</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="gain">
|
||||
<property name="minimum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>20.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Trigger Source</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="triggerSource"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="infotext">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="startButton">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
114
processing.cpp
Normal file
114
processing.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#include "processing.h"
|
||||
|
||||
|
||||
|
||||
Worker::Worker(FrameBatch *batch, ArvStream *stream)
|
||||
:batch(batch), stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
void Worker::run()
|
||||
{
|
||||
for(int i=0; i<BATCHSIZE; i++)
|
||||
{
|
||||
ProcessingResult res = processArvBuffer(batch->frames[i], cfg);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
for(int i=0; i<BATCHSIZE; i++)
|
||||
if(ARV_IS_STREAM(stream))
|
||||
arv_stream_push_buffer(stream, batch->frames[i]);
|
||||
}
|
||||
|
||||
ProcessingResult processArvBuffer(ArvBuffer* buffer, const ProcessingConfig& config)
|
||||
{
|
||||
ProcessingResult result;
|
||||
|
||||
if (!buffer) {
|
||||
cerr << "Error: Null ArvBuffer pointer!" << endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- Get image data from ArvBuffer ---
|
||||
size_t data_size = 0;
|
||||
const uint8_t* data = (const uint8_t*)arv_buffer_get_data(buffer, &data_size);
|
||||
if (!data) {
|
||||
cerr << "Error: Could not get data from ArvBuffer!" << endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
int width = arv_buffer_get_image_width(buffer);
|
||||
int height = arv_buffer_get_image_height(buffer);
|
||||
if (width <= 0 || height <= 0) {
|
||||
cerr << "Error: Invalid image dimensions!" << endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- Wrap raw data in a cv::Mat (no copy) ---
|
||||
Mat frame(height, width, CV_8UC1, (void*)data);
|
||||
result.composit = Mat::zeros(height, width, CV_8UC1);
|
||||
|
||||
// --- Thresholding ---
|
||||
Mat frame_threshold;
|
||||
if (!config.adaptive) {
|
||||
cv::threshold(frame, frame_threshold, config.thresholdValue, 255, cv::THRESH_BINARY);
|
||||
} else {
|
||||
cv::adaptiveThreshold(frame, frame_threshold, 255, cv::ADAPTIVE_THRESH_MEAN_C,
|
||||
cv::THRESH_BINARY, config.adaptiveBlocksize, -config.adaptiveShift);
|
||||
}
|
||||
|
||||
// --- Find contours ---
|
||||
vector<vector<Point>> contours;
|
||||
cv::findContours(frame_threshold, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
|
||||
|
||||
uint32_t hits = 0;
|
||||
|
||||
for (const auto& contour : contours) {
|
||||
if ((int)contour.size() < config.contourMinSize) continue;
|
||||
|
||||
Moments m = cv::moments(contour);
|
||||
if (m.m00 == 0) continue;
|
||||
|
||||
int cx = (int)(m.m10 / m.m00);
|
||||
int cy = (int)(m.m01 / m.m00);
|
||||
int area = (int)cv::contourArea(contour);
|
||||
|
||||
if (area < config.contourMinArea || area > config.contourMaxArea) continue;
|
||||
if (cx < 0 || cy < 0 || cx >= width || cy >= height) continue;
|
||||
|
||||
result.composit.at<uint8_t>(cy, cx) += 1;
|
||||
|
||||
vector<uint16_t> entry(config.numDatapoints);
|
||||
entry[0] = cx;
|
||||
entry[1] = cy;
|
||||
entry[2] = area;
|
||||
entry[3] = 0; // placeholder (e.g., for roundness)
|
||||
result.extended_data.push_back(entry);
|
||||
|
||||
hits++;
|
||||
}
|
||||
|
||||
result.hitsPerFrame.push_back(hits);
|
||||
return result;
|
||||
}
|
||||
|
||||
QImage drawHitsOnGrayImage(const QImage& grayImage, const ProcessingResult& result)
|
||||
{
|
||||
QImage output = grayImage.copy(); // make a writable copy
|
||||
QPainter painter(&output);
|
||||
|
||||
QPen pen(Qt::white); // white markers stand out on grayscale
|
||||
pen.setWidth(2);
|
||||
painter.setPen(pen);
|
||||
|
||||
for (const auto& hit : result.extended_data) {
|
||||
if (hit.size() >= 2) {
|
||||
int x = hit[0];
|
||||
int y = hit[1];
|
||||
painter.drawEllipse(QPoint(x, y), 3, 3); // small white dot
|
||||
}
|
||||
}
|
||||
|
||||
painter.end();
|
||||
return output;
|
||||
}
|
||||
43
processing.h
Normal file
43
processing.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef PROCESSING_H
|
||||
#define PROCESSING_H
|
||||
|
||||
#include <QThreadPool>
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <opencv4/opencv2/imgcodecs.hpp>
|
||||
#include <opencv4/opencv2/opencv.hpp>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#undef signals
|
||||
#include <arv.h>
|
||||
#undef signals
|
||||
#define signals Q_SIGNALS
|
||||
|
||||
#include "idscam.h"
|
||||
#include "framebatch.h"
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
struct ProcessingResult {
|
||||
Mat composit;
|
||||
vector<vector<uint16_t>> extended_data;
|
||||
vector<uint32_t> hitsPerFrame;
|
||||
};
|
||||
|
||||
ProcessingResult processArvBuffer(ArvBuffer* buffer, const ProcessingConfig& config);
|
||||
|
||||
QImage drawHitsOnGrayImage(const QImage& grayImage, const ProcessingResult& result);
|
||||
|
||||
class Worker : public QRunnable
|
||||
{
|
||||
public:
|
||||
Worker(FrameBatch* batch, ArvStream *stream);
|
||||
void run() override;
|
||||
private:
|
||||
FrameBatch* batch;
|
||||
ArvStream *stream;
|
||||
ProcessingConfig cfg{};
|
||||
};
|
||||
|
||||
#endif // PROCESSING_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue