From aaaaf3faf667d2e3a66349bf1d6aa64321a6739b Mon Sep 17 00:00:00 2001
From: am0ebe <am0ebe@gmx.de>
Date: Mon, 12 Feb 2024 19:58:31 +0100
Subject: [PATCH] add frameProcessor class, to process the frame data
 asynchronously.

---
 obj/recorder-cmd.pro       |  3 ++
 src/cmd/core.cpp           |  6 ++--
 src/cmd/frameObserver.cpp  | 37 ---------------------
 src/cmd/frameObserver.h    | 14 --------
 src/cmd/frameobserver.cpp  | 53 ++++++++++++++++++++++++++++++
 src/cmd/frameobserver.h    | 23 +++++++++++++
 src/cmd/frameprocessor.cpp | 66 ++++++++++++++++++++++++++++++++++++++
 src/cmd/frameprocessor.h   | 21 ++++++++++++
 8 files changed, 169 insertions(+), 54 deletions(-)
 delete mode 100644 src/cmd/frameObserver.cpp
 delete mode 100644 src/cmd/frameObserver.h
 create mode 100644 src/cmd/frameobserver.cpp
 create mode 100644 src/cmd/frameobserver.h
 create mode 100644 src/cmd/frameprocessor.cpp
 create mode 100644 src/cmd/frameprocessor.h

diff --git a/obj/recorder-cmd.pro b/obj/recorder-cmd.pro
index 9170ac9..ac54cd1 100644
--- a/obj/recorder-cmd.pro
+++ b/obj/recorder-cmd.pro
@@ -8,12 +8,14 @@ SOURCES += \
 	../src/cmd/console.cpp \
 	../src/cmd/core.cpp \
 	../src/cmd/frameObserver.cpp \
+	../src/cmd/frameProcessor.cpp \
 	../src/utils.cpp
 
 HEADERS += \
 	../src/cmd/console.h \
 	../src/cmd/core.h \
 	../src/cmd/frameObserver.h \
+	../src/cmd/frameProcessor.h \
 	../src/utils.h
 
 DEFINES *= QT_USE_QSTRINGBUILDER		#converts + to % when building strings
@@ -29,6 +31,7 @@ LIBS += -L$${VIMBA_LIB_DIR} -lVmbC -lVmbCPP -Wl,-rpath,\'\$$ORIGIN\'
 
 #-Wl,-rpath,.
 QMAKE_POST_LINK += cp $${VIMBA_LIB_DIR}/lib*.so ../bin  # copy vmb-libs to bin
+QMAKE_CXXFLAGS += -Wno-deprecated-enum-enum-conversion # ignore opencv warnings.
 
 #PRE_LINK: cp vimba libs once
 # cp ../b/vimbax/api/lib/GenICam/*.so $${VIMBA_LIB_DIR}
diff --git a/src/cmd/core.cpp b/src/cmd/core.cpp
index f8d8103..c751373 100644
--- a/src/cmd/core.cpp
+++ b/src/cmd/core.cpp
@@ -1,7 +1,7 @@
 #include "core.h"
 #include "VmbC/VmbCommonTypes.h"
 #include "VmbCPP/SharedPointerDefines.h"
-#include "frameObserver.h"
+#include "frameobserver.h"
 
 #include "../utils.h"
 #include <iostream>
@@ -203,8 +203,8 @@ void Core::record()
 	if ( f(curCam->GetFeatureByName ("PayloadSize", pFeature ),"get PayloadSize") )
 		return; // emit error("Couldn't get payload size 1");
 
-	if( pFeature == nullptr )
-		return; // emit error("Couldn't get payload size 2");
+	// if( pFeature == nullptr )
+		// return; // emit error("Couldn't get payload size 2");
 
 	if( f(pFeature->GetValue (nPLS)))
 		return;
diff --git a/src/cmd/frameObserver.cpp b/src/cmd/frameObserver.cpp
deleted file mode 100644
index f0796be..0000000
--- a/src/cmd/frameObserver.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "frameObserver.h"
-
-#include <VmbCPP/SharedPointerDefines.h>
-#include <VmbCPP/Camera.h>
-#include <QDebug>
-
-using namespace VmbCPP;
-
-
-FrameObserver::FrameObserver( CameraPtr pCamera ) : IFrameObserver( pCamera )
-{
-	// static int count=0;
-	// qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << " #:" << count++
-}
-
-// Frame callback notifies about incoming frames
-void FrameObserver::FrameReceived ( const FramePtr pframe )
-{
-	VmbUint64_t timestamp;
-	qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << "";
-	pframe->GetTimestamp(timestamp);
-	qDebug() << "FrameObserver::FrameReceived():" << timestamp;
-
-	// process data afap
-	// some functions are prohibited within this callback
-
-	// XXX
-	// ensure framedata is valid:
-	// Frame::GetReceiveStatus == VmbFrameStatusComplete
-	// pframe->GetReceiveStatus(VmbFrameStatusType &status)
-
-	// Send notification to working thread
-	// Do not apply image processing within this callback ( performance )
-	// When the frame has been processed , requeue it
-
-	m_pCamera->QueueFrame( pframe );
-}
diff --git a/src/cmd/frameObserver.h b/src/cmd/frameObserver.h
deleted file mode 100644
index 8eb7b22..0000000
--- a/src/cmd/frameObserver.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-
-#include <VmbCPP/IFrameObserver.h>
-
-namespace VmbCPP{
-
-class FrameObserver : public IFrameObserver
-{
-	public:
-		void FrameReceived( const FramePtr pFrame );
-		FrameObserver( CameraPtr pCamera );
-};
-
-}
diff --git a/src/cmd/frameobserver.cpp b/src/cmd/frameobserver.cpp
new file mode 100644
index 0000000..28feedb
--- /dev/null
+++ b/src/cmd/frameobserver.cpp
@@ -0,0 +1,53 @@
+#include "frameobserver.h"
+#include "frameprocessor.h"
+#include "qnamespace.h"
+
+#include <VmbCPP/SharedPointerDefines.h>
+#include <VmbCPP/Camera.h>
+
+#include <QDebug>
+#include <QThread>
+#include <QObject>
+
+
+using namespace VmbCPP;
+
+
+FrameObserver::FrameObserver( CameraPtr pCamera ) : IFrameObserver( pCamera )
+{
+	// static int count=0;
+	// qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << " #:" << count++
+}
+
+// Frame callback notifies about incoming frames
+// process data afap
+// some functions are prohibited within this callback!
+// Do not apply image processing within this callback ( performance )
+// -> create frame processor to handle frame processing asynchronously
+// When the frame has been processed , requeue it
+void FrameObserver::FrameReceived ( const FramePtr pframe )
+{
+	qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << "";
+
+	FrameProcessor *processor = new FrameProcessor(pframe, this);
+
+
+	QThread *thread = new QThread;
+	processor->moveToThread(thread);
+
+	connect(thread, &QThread::started, processor, &FrameProcessor::processFrame);
+	connect(processor, &FrameProcessor::frameProcessed, processor, &FrameProcessor::deleteLater);
+	connect(processor, &FrameProcessor::frameProcessed, thread, &QThread::quit);
+	connect(processor, &FrameProcessor::frameProcessed, this, &FrameObserver::queueFrame); // Connect to a slot in FrameObserver
+	connect(thread, &QThread::finished, thread, &QThread::deleteLater);
+
+	thread->start();
+
+	m_pCamera->QueueFrame( pframe );
+}
+
+
+void FrameObserver::queueFrame(FramePtr pFrame)
+{
+	m_pCamera->QueueFrame(pFrame); // Queue the frame back to the camera
+}
diff --git a/src/cmd/frameobserver.h b/src/cmd/frameobserver.h
new file mode 100644
index 0000000..23f39ce
--- /dev/null
+++ b/src/cmd/frameobserver.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <QObject>
+#include <VmbCPP/IFrameObserver.h>
+
+// using VmbCPP::CameraPtr;
+// using VmbCPP::FramePtr;
+// using VmbCPP::IFrameObserver;
+using namespace VmbCPP;
+
+class FrameObserver : public QObject, public IFrameObserver
+{
+	Q_OBJECT
+
+	public:
+		void FrameReceived( const FramePtr pFrame );
+		FrameObserver( CameraPtr pCamera );
+
+	private slots:
+		void queueFrame(FramePtr pFrame);
+
+};
+
diff --git a/src/cmd/frameprocessor.cpp b/src/cmd/frameprocessor.cpp
new file mode 100644
index 0000000..cd6cbca
--- /dev/null
+++ b/src/cmd/frameprocessor.cpp
@@ -0,0 +1,66 @@
+#include "frameprocessor.h"
+#include "opencv2/imgcodecs.hpp"
+
+#include <opencv2/opencv.hpp>
+
+#include <VmbC/VmbCommonTypes.h>
+#include <VmbCPP/Frame.h>
+
+#include <QDebug>
+#include <QThread>
+#include <QObject>
+#include <QImage>
+
+FrameProcessor::FrameProcessor(FramePtr pframe, QObject *parent) : QObject(parent), m_pframe(pframe)
+{}
+
+//2d check image format!
+//2d add camera name to filename
+/// Process the received frame asynchronously
+void FrameProcessor::processFrame()
+{
+	// process frames receiveStatus
+	VmbFrameStatusType status;
+	m_pframe->GetReceiveStatus(status);
+	if (status != VmbFrameStatusComplete)
+	{
+		qDebug() << "Frame not complete, skip processing.";
+		return;
+	}
+
+	VmbUint32_t width = 0;
+	VmbUint32_t height = 0;
+	unsigned char* pdata;
+	VmbPixelFormatType pixelFormat;
+	VmbUint64_t timestamp;
+
+	m_pframe->GetWidth(width);
+	m_pframe->GetHeight(height);
+	m_pframe->GetBuffer(pdata);
+	m_pframe->GetPixelFormat(pixelFormat);
+	m_pframe->GetTimestamp(timestamp);
+
+	cv::Mat frameMat(height, width, CV_8UC3, pdata);
+
+	if (pixelFormat == VmbPixelFormatRgb8)
+	{
+		// If the frame pixel format is RGB8, directly copy the data
+		// memcpy(frameMat.data, pData, width * height * 3);
+		qDebug() << "Pixel format is RGB8";
+	}
+	else
+	{
+		// If the pixel format is not already in BGR format, you may need to convert it
+		// cv::Mat tempMat(height, width, CV_8UC1, pdata); //UC1??
+		// cv::cvtColor(tempMat, frameMat, cv::COLOR_BayerGB2BGR); // Adjust the conversion based on the actual Bayer pattern
+		qDebug() << "Pixel format is not RGB8, converting to BGR";
+	}
+
+	std::vector<int> params = {cv::IMWRITE_JPEG_QUALITY, 99, cv::IMWRITE_JPEG_OPTIMIZE, 1, cv::IMWRITE_JPEG_RST_INTERVAL,4};
+
+	QString filename = QString::number(timestamp) + "frame.jpg";
+	cv::imwrite(filename.toStdString(), frameMat, params);
+	qDebug() << "Frame saved as JPEG: " << filename;
+
+	emit frameProcessed(m_pframe);
+}
diff --git a/src/cmd/frameprocessor.h b/src/cmd/frameprocessor.h
new file mode 100644
index 0000000..9a80335
--- /dev/null
+++ b/src/cmd/frameprocessor.h
@@ -0,0 +1,21 @@
+#include <QObject>
+#include <VmbCPP/SharedPointerDefines.h>
+
+using VmbCPP::FramePtr;
+
+class FrameProcessor : public QObject
+{
+	Q_OBJECT
+
+public:
+	explicit FrameProcessor(FramePtr, QObject *parent = nullptr);
+
+public slots:
+	void processFrame();
+
+signals:
+	void frameProcessed(FramePtr);
+
+private:
+	FramePtr m_pframe;
+};
-- 
GitLab