GrabBag/App/DroneScrewbolt/DroneScrewServer/DroneScrewServerPresenter.h

404 lines
15 KiB
C
Raw Normal View History

2026-06-26 17:55:15 +08:00
#ifndef DRONESCREW_SERVER_PRESENTER_H
#define DRONESCREW_SERVER_PRESENTER_H
#include <QObject>
#include <QJsonObject>
#include <QString>
#include <QTimer>
#include <QMutex>
#include <QDateTime>
#include <atomic>
#include <condition_variable>
#include <deque>
2026-06-26 17:55:15 +08:00
#include <thread>
#include <memory>
#include <mutex>
#include <vector>
#include "IMvsDevice.h"
#include "IVrFFMediaPusher.h"
#include "Algo/IDroneScrewAlgo.h"
/**
* @brief Presenter
*
*
* MVS相机采集 RTSP ZMQ
*
*
* - 使 IMvsDevice
* - BinocularMarkPresenter
* -
* - RTMP/RTSP Rtsp.streamCamera
* - ZMQ detectMode
*
* detectMode
* - "binocular"ZMQ PUB BIWI
* - "mono"ZMQ PUB BIWI
* mono 使
*/
class DroneScrewServerPresenter : public QObject
{
Q_OBJECT
public:
explicit DroneScrewServerPresenter(QObject* parent = nullptr);
~DroneScrewServerPresenter() override;
/**
* @brief
*/
bool loadConfiguration(const QString& configFilePath);
/**
* @brief saveConfiguration
*
*
* runtime_config.xml
*/
void setConfigFilePath(const QString& path) { m_configFilePath = path; }
/**
* @brief m_configFilePath
*
* Camera/ Trigger
*/
bool saveConfiguration();
2026-07-11 15:28:36 +08:00
void setSimulationImageDir(const QString& dirPath);
bool isSimulationMode() const;
2026-06-26 17:55:15 +08:00
/**
* @brief / /
*/
int initAll();
/**
* @brief
*/
void deinitAll();
/**
* @brief
*/
bool isDetecting() const { return m_bIsDetecting.load(); }
bool isLiveStreaming() const { return m_bLiveStreaming.load(); }
/**
* @brief
*
* ZMQ REP single 使 success=false
* errorCode/message
*/
DroneScrewResult runSingleDetection();
/**
* @brief ZMQ REP / PUB ZMQ
*/
int getZmqControlPort() const { return m_zmqControlPort; }
int getZmqResultPort() const { return m_zmqResultPort; }
int getZmqRawImagePort() const { return m_zmqRawImagePort; }
QString getRtspUrl() const { return m_rtspAdvertiseUrl; }
QJsonObject getRuntimeInfo() const;
QJsonObject getCalibrationInfo() const;
2026-07-03 14:19:06 +08:00
bool getLastFinalDetectionResult(DroneScrewResult& result) const;
2026-06-26 17:55:15 +08:00
int startDetectionWork();
int stopDetectionWork();
int startLiveStream();
int stopLiveStream();
int swapCameraRoles();
/**
* @brief / ZMQ PUB
*
* ZMQ raw PUB Enable
* emit rawImageReady
*/
void setRawPubEnabled(bool enabled) { m_bRawPubEnabled = enabled; }
/**
* @brief
* @param mode "binocular" "mono"
*
* ZMQ PUB
* 使
*/
void setDetectMode(const std::string& mode);
std::string detectMode() const;
public slots:
/**
* @brief
*/
void handleSetExposure(double exposureTime);
/**
* @brief
*/
void handleSetGain(double gain);
/**
* @brief
*/
void handleSetLeftExposure(double exposureTime);
/**
* @brief
*/
void handleSetRightExposure(double exposureTime);
/**
* @brief
*/
void handleSetLeftGain(double gain);
/**
* @brief
*/
void handleSetRightGain(double gain);
/**
* @brief
*/
void handleUpdateAlgoParams(const DroneScrewAlgoParams& params);
signals:
/**
* @brief ZMQ
*/
void detectionResult(const DroneScrewResult& result);
/**
* @brief
*
* m_bRawPubEnabled true emit ZMQ 广
* MvsImageData pData presenter
* emit
*/
void rawImageReady(const MvsImageData& leftImg, const MvsImageData& rightImg);
/**
* @brief /
*/
void statusChanged(const QString& msg);
private slots:
/**
* @brief
*/
void onCameraReconnectTimer();
private:
int tryConnectCamera();
void closeCamera();
int configureCamera(IMvsDevice* camera,
const char* role,
bool ioTrigger = false,
double frameRate = 2.0,
int64_t binningHorizontal = 1,
int64_t binningVertical = 1,
int64_t decimationHorizontal = 1,
int64_t decimationVertical = 1);
2026-06-26 17:55:15 +08:00
IMvsDevice* cameraForRole(const char* role) const;
const char* liveStreamCameraRole() const;
IMvsDevice* liveStreamCamera() const;
IMvsDevice* nonLiveStreamCamera() const;
bool isLiveStreamCameraRole(const char* role) const;
bool areCamerasGrabbing();
int prepareDetectionAcquisition(double frameRate,
int64_t binningHorizontal,
int64_t binningVertical,
int64_t decimationHorizontal,
int64_t decimationVertical,
2026-06-26 17:55:15 +08:00
const char* tag);
int prepareLiveStreamAcquisition();
void resetFrameReadyFlags();
int initRtspPusher(unsigned int width, unsigned int height, unsigned int fps);
int startRtspPusher();
2026-06-26 17:55:15 +08:00
void releaseRtspPusher();
int pushRtspFrame(const MvsImageData& img);
void resetRtspPushState();
void recordRtspPushResult(int ret, unsigned long long frameId);
2026-06-26 17:55:15 +08:00
bool tryRgaScaleMonoToY(const MvsImageData& img,
unsigned char* dstY,
unsigned int outWidth,
unsigned int outHeight);
void leftCameraCallback(const MvsImageData& img);
void rightCameraCallback(const MvsImageData& img);
void detectThreadFunc();
2026-07-11 15:28:36 +08:00
int prepareSimulationImages(bool forceReload);
void clearSimulationImages();
bool loadNextSimulationImagePair(MvsImageData& leftImg,
MvsImageData& rightImg,
unsigned int targetWidth = 0,
unsigned int targetHeight = 0);
2026-06-26 17:55:15 +08:00
double exposureForRole(const char* role) const;
int applyExposureForRole(const char* role);
int applyCurrentExposureForRole(const char* role);
2026-06-26 17:55:15 +08:00
double gainForRole(const char* role) const;
int pulseGpioTrigger(bool logOk = true);
void startGpioTriggerLoop();
void stopGpioTriggerLoop();
void triggerThreadFunc();
bool waitAndCopyLatestBinocular(MvsImageData& leftImg,
MvsImageData& rightImg,
unsigned int timeoutMs);
void startImageSaveThread(const QString& modeName);
void stopImageSaveThread();
2026-07-01 18:16:18 +08:00
void imageSaveThreadFunc(int workerIndex);
2026-07-03 14:19:06 +08:00
bool enqueueImageSave(const MvsImageData& leftImg,
const MvsImageData& rightImg,
2026-07-02 10:57:32 +08:00
const DroneScrewResult& result,
unsigned long long index);
QString imageSaveModeName() const;
2026-07-03 14:19:06 +08:00
void resetPrecisionResultSamples();
void clearLastFinalDetectionResult();
void recordPrecisionResultSample(const DroneScrewResult& result,
unsigned long long imageIndex);
bool selectBestPrecisionResult(DroneScrewResult& result,
unsigned long long& imageIndex,
double& rankScore,
int& sampleCount) const;
void setLastFinalDetectionResult(const DroneScrewResult& result);
2026-06-26 17:55:15 +08:00
private:
struct ImageSaveBuffer
{
unsigned int width{0};
unsigned int height{0};
int pixelFormat{0};
std::vector<unsigned char> data;
bool valid{false};
};
struct ImageSaveJob
{
QString dirPath;
unsigned long long index{0};
ImageSaveBuffer left;
ImageSaveBuffer right;
2026-07-02 10:57:32 +08:00
DroneScrewResult result;
bool hasResult{false};
};
2026-07-03 14:19:06 +08:00
struct PrecisionResultSample
{
DroneScrewResult result;
unsigned long long imageIndex{0};
};
2026-07-11 15:28:36 +08:00
struct SimulationImagePair
{
QString dirPath;
QString leftPath;
QString rightPath;
unsigned long long index{0};
};
2026-06-26 17:55:15 +08:00
// 双目相机设备
IMvsDevice* m_pLeftCamera{nullptr};
IMvsDevice* m_pRightCamera{nullptr};
// 推流
IVrFFMediaPusher* m_pPusher{nullptr};
// 算法
std::unique_ptr<IDroneScrewAlgo> m_pAlgo;
DroneScrewAlgoParams m_algoParams;
// 状态
std::atomic<bool> m_bCameraConnected{false};
std::atomic<bool> m_bIsDetecting{false};
QTimer* m_pReconnectTimer{nullptr};
// 配置
std::string m_strLeftCameraSerial;
std::string m_strRightCameraSerial;
unsigned int m_nLeftCameraIndex{0};
unsigned int m_nRightCameraIndex{1};
double m_leftExposureTime{10000.0};
double m_rightExposureTime{10000.0};
double m_leftGain{1.0};
double m_rightGain{1.0};
QString m_configFilePath;
2026-07-11 15:28:36 +08:00
int m_zmqControlPort{15555};
int m_zmqResultPort{15556};
int m_zmqRawImagePort{15557};
2026-06-26 17:55:15 +08:00
int m_rtspPort{8554};
QString m_rtspPath{"/live/dronescrew"};
QString m_rtspAdvertiseUrl;
int m_pushBitrateKbps{4096};
int m_pushFps{30};
int m_liveStreamFps{30};
unsigned int m_liveStreamWidth{1024};
unsigned int m_liveStreamHeight{750};
std::string m_liveStreamCameraRole{"left"}; // fixed to left for realtime stream
bool m_useIoTrigger{true};
int m_triggerGpio{113};
int m_triggerSource{0}; // MVS Line0
int m_triggerActivation{0}; // MVS RisingEdge
std::thread m_triggerThread;
std::atomic<bool> m_bTriggerThreadExit{false};
unsigned int m_rtspWidth{0};
unsigned int m_rtspHeight{0};
std::atomic<bool> m_bRtspStarted{false};
std::atomic<bool> m_bLiveStreaming{false};
std::atomic<int> m_detectPipelineMode{0}; // 0=precision, 1=distance
std::atomic<int> m_activeTriggerFps{2};
std::atomic<int64_t> m_rtspFrameCounter{0}; // 相对帧计数(推流启动时重置)
std::mutex m_rtspPusherMutex;
std::mutex m_rtspPushMutex;
std::atomic<int64_t> m_rtspPushedFrameCounter{0};
std::atomic<int> m_rtspLastPushRet{0};
std::atomic<unsigned long long> m_rtspLastPushFrameId{0};
2026-06-26 17:55:15 +08:00
std::vector<unsigned char> m_rtspFrameBuffer;
std::vector<unsigned int> m_rtspScaleX;
std::vector<unsigned int> m_rtspScaleY;
unsigned int m_rtspScaleSrcWidth{0};
unsigned int m_rtspScaleSrcHeight{0};
unsigned int m_rtspScaleOutWidth{0};
unsigned int m_rtspScaleOutHeight{0};
bool m_rtspUvInitialized{false};
bool m_rtspRgaScaleDisabled{false};
bool m_rtspRgaScaleLogged{false};
// 原始图像 PUB 开关
std::atomic<bool> m_bRawPubEnabled{false};
// 检测模式下的图像传输模式
mutable std::mutex m_detectModeMutex;
std::string m_detectMode{"binocular"}; // "binocular" | "mono"
// 检测线程
std::thread m_detectThread;
std::atomic<bool> m_bThreadExit{false};
QMutex m_frameMutex;
MvsImageData m_leftImageData;
MvsImageData m_rightImageData;
bool m_bLeftImageReady{false};
bool m_bRightImageReady{false};
// 异步图像保存
2026-07-01 18:16:18 +08:00
std::vector<std::thread> m_imageSaveThreads;
std::atomic<bool> m_imageSaveThreadExit{false};
std::mutex m_imageSaveMutex;
std::condition_variable m_imageSaveCv;
std::deque<ImageSaveJob> m_imageSaveQueue;
QString m_imageSaveSessionDir;
unsigned long long m_imageSaveDropped{0};
2026-07-03 14:19:06 +08:00
mutable std::mutex m_detectionResultMutex;
std::vector<PrecisionResultSample> m_precisionResultSamples;
DroneScrewResult m_lastFinalResult;
bool m_hasLastFinalResult{false};
2026-07-11 15:28:36 +08:00
QString m_simulationImageDir;
std::vector<SimulationImagePair> m_simulationImagePairs;
size_t m_simulationImageCursor{0};
unsigned long long m_simulationFrameId{0};
mutable std::mutex m_simulationImageMutex;
2026-06-26 17:55:15 +08:00
};
#endif // DRONESCREW_SERVER_PRESENTER_H