{"id":244,"date":"2026-06-12T12:53:18","date_gmt":"2026-06-12T11:53:18","guid":{"rendered":"https:\/\/myjetsonnano.perseus314.com\/?p=244"},"modified":"2026-06-12T12:55:03","modified_gmt":"2026-06-12T11:55:03","slug":"hq-camera-imx477-in-c","status":"publish","type":"post","link":"https:\/\/myjetsonnano.perseus314.com\/index.php\/2026\/06\/12\/hq-camera-imx477-in-c\/","title":{"rendered":"HQ Camera (IMX477) in C++"},"content":{"rendered":"\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"787\" height=\"586\" src=\"https:\/\/myjetsonnano.perseus314.com\/wp-content\/uploads\/2026\/06\/image-1.png\" alt=\"\" class=\"wp-image-246\" srcset=\"https:\/\/myjetsonnano.perseus314.com\/wp-content\/uploads\/2026\/06\/image-1.png 787w, https:\/\/myjetsonnano.perseus314.com\/wp-content\/uploads\/2026\/06\/image-1-300x223.png 300w, https:\/\/myjetsonnano.perseus314.com\/wp-content\/uploads\/2026\/06\/image-1-768x572.png 768w\" sizes=\"auto, (max-width: 787px) 100vw, 787px\" \/><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update\nsudo apt install libcamera-dev pkg-config cmake Build-essential<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"794\" height=\"435\" src=\"https:\/\/myjetsonnano.perseus314.com\/wp-content\/uploads\/2026\/06\/image-2.png\" alt=\"\" class=\"wp-image-247\" srcset=\"https:\/\/myjetsonnano.perseus314.com\/wp-content\/uploads\/2026\/06\/image-2.png 794w, https:\/\/myjetsonnano.perseus314.com\/wp-content\/uploads\/2026\/06\/image-2-300x164.png 300w, https:\/\/myjetsonnano.perseus314.com\/wp-content\/uploads\/2026\/06\/image-2-768x421.png 768w\" sizes=\"auto, (max-width: 794px) 100vw, 794px\" \/><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>cmake_minimum_required(VERSION 3.16)\nproject(HQCameraApp CXX)\n\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\n\n# Find libcamera using pkg-config\nfind_package(PkgConfig REQUIRED)\npkg_check_modules(LIBCAMERA REQUIRED libcamera)\n\nadd_executable(hq_camera_test main.cpp)\n\ntarget_include_directories(hq_camera_test PRIVATE ${LIBCAMERA_INCLUDE_DIRS})\ntarget_link_libraries(hq_camera_test PRIVATE ${LIBCAMERA_LIBRARIES})<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>#ifndef PI_HQ_CAMERA_H\n#define PI_HQ_CAMERA_H\n\n#include \"device_base.h\"\n#include &lt;QMutex>\n#include &lt;QByteArray>\n#include &lt;QSize>\n#include &lt;QString>\n\n\/\/ Forward declarations of native libcamera structures to prevent polluting \n\/\/ this header file with complex, external dependencies.\nnamespace libcamera {\n    class CameraManager;\n    class Camera;\n    class FrameBufferAllocator;\n    class CameraConfiguration;\n    class Request;\n}\n\nnamespace LigDeviceNS {\n\n\/**\n * Concrete driver class implementing the Raspberry Pi HQ Camera (Sony IMX477 sensor)\n * within the DeviceBase framework. Maps standard controls to the native Linux libcamera stack.\n *\/\nclass PiHqCamera : public DeviceBase\n{\npublic:\n    \/**\n     * Constructor. Initializes the underlying Camera Manager.\n     *\/\n    PiHqCamera(int camIndex = 0);\n    \n    \/**\n     * Destructor. Ensures clean device detachment and hardware release.\n     *\/\n    ~PiHqCamera();\n\n    \/\/ --- DeviceBase Interface Overrides ---\n    int mode() const override;\n    void setMode(int n) override;\n    int modeCount() const override;\n    QString modeInfo(int n) const override;\n    QSize imageSize() const override;\n\n    bool isAutoExposureSupported() const override;\n    bool autoExposureEnabled() const override;\n    void setAutoExposureEnabled(bool enabled) override;\n\n    double shutter() override;\n    void setShutter(double ms) override;\n\n    double minGain() const override;\n    double maxGain() const override;\n    double gain() override;\n    void setGain(double db) override;\n\n    double effectiveIntensity() override;\n    void setEffectiveIntensity(double f) override;\n\n    bool autoBalanceEnabled() override;\n    void setAutoBalanceEnabled(bool enabled) override;\n\n    \/\/ Custom color balance values can be stored, though standard libcamera \n    \/\/ groups manual adjustments under native AWB algorithms.\n    double balanceBlue() override;\n    void setBalanceBlue(double blue) override;\n    double balanceRed() override;\n    void setBalanceRed(double red) override;\n\n    \/**\n     * Synchronously fetches the latest frame buffer captured by the background hardware loop.\n     * Maps the pixel data directly into a thread-safe QImage wrapper.\n     *\/\n    QImage acquire() override;\n\n    QString deviceName() const override;\n    QString controllerName() const override;\n    QString info() const override;\n\n    bool queryConnection() override;\n    bool connect() override;\n    void disconnect() override;\n\nprivate:\n    \/\/ Internal hardware tracking configuration parameters\n    int _camIndex {0};\n    int _mode {0};\n    bool _autoExposureEnabled {false};\n    bool _autoBalanceEnabled {false};\n    double _shutter {10.0};          \/\/ Exposure time tracker in milliseconds\n    double _gain {0.0};              \/\/ Analogue gain tracker in decibels\n    double _effectiveIntensity {0.5}; \/\/ Target exposure reference point\n    double _balanceBlue {0.15};\n    double _balanceRed {0.19};\n    \n    QString _deviceName {\"Raspberry Pi HQ Camera\"};\n    QString _deviceSerial {\"Unknown\"};\n    QString _firmwareVersion {\"1.0\"};\n\n    \/\/ Native libcamera core pipeline control handles\n    std::unique_ptr&lt;libcamera::CameraManager> _cameraManager;\n    std::shared_ptr&lt;libcamera::Camera> _libcamDevice;\n    std::unique_ptr&lt;libcamera::FrameBufferAllocator> _allocator;\n    std::vector&lt;std::unique_ptr&lt;libcamera::Request>> _requests;\n\n    \/\/ Buffer state variables to synchronize the asynchronous callback with acquire()\n    QMutex _bufferMutex;\n    QByteArray _latestFrameData; \n    bool _frameAvailable {false};\n\n    \/\/ Internal execution workers\n    void requestComplete(libcamera::Request *request);\n    bool applyDeviceControls();\n    \n    \/\/ Static mapping routine matching codebase standard patterns\n    static int camToCbit(int camIdx, int cbn);\n};\n\n} \/\/ namespace LigDeviceNS\n\n#endif \/\/ PI_HQ_CAMERA_H<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;opencv2\/opencv.hpp>\n#include &lt;iostream>\n#include &lt;thread>\n#include &lt;mutex>\n#include &lt;queue>\n\n\/\/ Thread-safe frame queue for processing\nstd::queue&lt;cv::Mat> frameQueue;\nstd::mutex queueMutex;\nbool running = true;\n\nvoid captureThread(cv::VideoCapture&amp; cap) {\n    while (running) {\n        cv::Mat frame;\n        cap >> frame; \/\/ Capture the latest frame\n        if (frame.empty()) continue;\n\n        std::lock_guard&lt;std::mutex> lock(queueMutex);\n        if (frameQueue.size() &lt; 10) { \/\/ Prevent memory bloating\n            frameQueue.push(frame.clone());\n        }\n    }\n}\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":245,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-244","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/myjetsonnano.perseus314.com\/index.php\/wp-json\/wp\/v2\/posts\/244","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/myjetsonnano.perseus314.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/myjetsonnano.perseus314.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/myjetsonnano.perseus314.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/myjetsonnano.perseus314.com\/index.php\/wp-json\/wp\/v2\/comments?post=244"}],"version-history":[{"count":2,"href":"https:\/\/myjetsonnano.perseus314.com\/index.php\/wp-json\/wp\/v2\/posts\/244\/revisions"}],"predecessor-version":[{"id":249,"href":"https:\/\/myjetsonnano.perseus314.com\/index.php\/wp-json\/wp\/v2\/posts\/244\/revisions\/249"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/myjetsonnano.perseus314.com\/index.php\/wp-json\/wp\/v2\/media\/245"}],"wp:attachment":[{"href":"https:\/\/myjetsonnano.perseus314.com\/index.php\/wp-json\/wp\/v2\/media?parent=244"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/myjetsonnano.perseus314.com\/index.php\/wp-json\/wp\/v2\/categories?post=244"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/myjetsonnano.perseus314.com\/index.php\/wp-json\/wp\/v2\/tags?post=244"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}