sudo apt update
sudo apt install libcamera-dev pkg-config cmake Build-essential
cmake_minimum_required(VERSION 3.16)
project(HQCameraApp CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Find libcamera using pkg-config
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBCAMERA REQUIRED libcamera)
add_executable(hq_camera_test main.cpp)
target_include_directories(hq_camera_test PRIVATE ${LIBCAMERA_INCLUDE_DIRS})
target_link_libraries(hq_camera_test PRIVATE ${LIBCAMERA_LIBRARIES})
#ifndef PI_HQ_CAMERA_H
#define PI_HQ_CAMERA_H
#include "device_base.h"
#include <QMutex>
#include <QByteArray>
#include <QSize>
#include <QString>
// Forward declarations of native libcamera structures to prevent polluting
// this header file with complex, external dependencies.
namespace libcamera {
class CameraManager;
class Camera;
class FrameBufferAllocator;
class CameraConfiguration;
class Request;
}
namespace LigDeviceNS {
/**
* Concrete driver class implementing the Raspberry Pi HQ Camera (Sony IMX477 sensor)
* within the DeviceBase framework. Maps standard controls to the native Linux libcamera stack.
*/
class PiHqCamera : public DeviceBase
{
public:
/**
* Constructor. Initializes the underlying Camera Manager.
*/
PiHqCamera(int camIndex = 0);
/**
* Destructor. Ensures clean device detachment and hardware release.
*/
~PiHqCamera();
// --- DeviceBase Interface Overrides ---
int mode() const override;
void setMode(int n) override;
int modeCount() const override;
QString modeInfo(int n) const override;
QSize imageSize() const override;
bool isAutoExposureSupported() const override;
bool autoExposureEnabled() const override;
void setAutoExposureEnabled(bool enabled) override;
double shutter() override;
void setShutter(double ms) override;
double minGain() const override;
double maxGain() const override;
double gain() override;
void setGain(double db) override;
double effectiveIntensity() override;
void setEffectiveIntensity(double f) override;
bool autoBalanceEnabled() override;
void setAutoBalanceEnabled(bool enabled) override;
// Custom color balance values can be stored, though standard libcamera
// groups manual adjustments under native AWB algorithms.
double balanceBlue() override;
void setBalanceBlue(double blue) override;
double balanceRed() override;
void setBalanceRed(double red) override;
/**
* Synchronously fetches the latest frame buffer captured by the background hardware loop.
* Maps the pixel data directly into a thread-safe QImage wrapper.
*/
QImage acquire() override;
QString deviceName() const override;
QString controllerName() const override;
QString info() const override;
bool queryConnection() override;
bool connect() override;
void disconnect() override;
private:
// Internal hardware tracking configuration parameters
int _camIndex {0};
int _mode {0};
bool _autoExposureEnabled {false};
bool _autoBalanceEnabled {false};
double _shutter {10.0}; // Exposure time tracker in milliseconds
double _gain {0.0}; // Analogue gain tracker in decibels
double _effectiveIntensity {0.5}; // Target exposure reference point
double _balanceBlue {0.15};
double _balanceRed {0.19};
QString _deviceName {"Raspberry Pi HQ Camera"};
QString _deviceSerial {"Unknown"};
QString _firmwareVersion {"1.0"};
// Native libcamera core pipeline control handles
std::unique_ptr<libcamera::CameraManager> _cameraManager;
std::shared_ptr<libcamera::Camera> _libcamDevice;
std::unique_ptr<libcamera::FrameBufferAllocator> _allocator;
std::vector<std::unique_ptr<libcamera::Request>> _requests;
// Buffer state variables to synchronize the asynchronous callback with acquire()
QMutex _bufferMutex;
QByteArray _latestFrameData;
bool _frameAvailable {false};
// Internal execution workers
void requestComplete(libcamera::Request *request);
bool applyDeviceControls();
// Static mapping routine matching codebase standard patterns
static int camToCbit(int camIdx, int cbn);
};
} // namespace LigDeviceNS
#endif // PI_HQ_CAMERA_H
#include <opencv2/opencv.hpp>
#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
// Thread-safe frame queue for processing
std::queue<cv::Mat> frameQueue;
std::mutex queueMutex;
bool running = true;
void captureThread(cv::VideoCapture& cap) {
while (running) {
cv::Mat frame;
cap >> frame; // Capture the latest frame
if (frame.empty()) continue;
std::lock_guard<std::mutex> lock(queueMutex);
if (frameQueue.size() < 10) { // Prevent memory bloating
frameQueue.push(frame.clone());
}
}
}