From patchwork Wed Mar 13 12:12:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 19704 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id C5BD6BD160 for ; Wed, 13 Mar 2024 12:12:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C62D262C8B; Wed, 13 Mar 2024 13:12:47 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="rgLSV1pm"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 579D162C8B for ; Wed, 13 Mar 2024 13:12:44 +0100 (CET) Received: from jasper.fritz.box (unknown [IPv6:2a00:6020:448c:6c00:9b07:31b5:38e1:e957]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D1F6DA8F; Wed, 13 Mar 2024 13:12:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1710331941; bh=ej1uK+sfbRUZYyaaAKX1MFmV6CMLr92Fr0BTKMd+7bY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rgLSV1pm8ubg8NZMvsLd0+wCHASUPxsiKqKpxEDtqcTouKJxNPTHNTq7kaR7kufzl Q8zL2Wv97S7VBolwzm4vXljSsSBCV6kKgki6Wq+bp9EIbfurDUg/vsNo8fOzVLo2Jd /ucwEPF5gJnskvuXRR15PeZ+EEppTGRO8pVhDjUc= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Subject: [PATCH v2 02/12] libcamera: lc-compliance: Add TimeSheet class Date: Wed, 13 Mar 2024 13:12:13 +0100 Message-Id: <20240313121223.138150-3-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240313121223.138150-1-stefan.klug@ideasonboard.com> References: <20240313121223.138150-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stefan Klug Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" This class allows us to prepare a time sheet with controls for the frames to capture (a bit like the capture script in cam). During capture the metadata is recorded. Additionally a mean brightness value of a 20x20 pixel spot in the middle of the frame is calculated. This allows easy analysis after running the capture without complicated state handling due to the asynchronous nature of the capturing process. Signed-off-by: Stefan Klug --- src/apps/lc-compliance/meson.build | 1 + src/apps/lc-compliance/time_sheet.cpp | 145 ++++++++++++++++++++++++++ src/apps/lc-compliance/time_sheet.h | 55 ++++++++++ 3 files changed, 201 insertions(+) create mode 100644 src/apps/lc-compliance/time_sheet.cpp create mode 100644 src/apps/lc-compliance/time_sheet.h diff --git a/src/apps/lc-compliance/meson.build b/src/apps/lc-compliance/meson.build index c792f072..eb7b2d71 100644 --- a/src/apps/lc-compliance/meson.build +++ b/src/apps/lc-compliance/meson.build @@ -16,6 +16,7 @@ lc_compliance_sources = files([ 'environment.cpp', 'main.cpp', 'simple_capture.cpp', + 'time_sheet.cpp', ]) lc_compliance = executable('lc-compliance', lc_compliance_sources, diff --git a/src/apps/lc-compliance/time_sheet.cpp b/src/apps/lc-compliance/time_sheet.cpp new file mode 100644 index 00000000..0ac544d6 --- /dev/null +++ b/src/apps/lc-compliance/time_sheet.cpp @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Ideas on Board Oy + * + * time_sheet.cpp + */ + +#include "time_sheet.h" + +#include +#include + +#include "libcamera/internal/formats.h" +#include "libcamera/internal/mapped_framebuffer.h" + +using namespace libcamera; + +double calcPixelMeanNV12(const uint8_t *data) +{ + return (double)*data; +} + +double calcPixelMeanRAW10(const uint8_t *data) +{ + return (double)*((const uint16_t *)data); +} + +double calculateMeanBrightnessFromCenterSpot(libcamera::Request *request) +{ + const Request::BufferMap &buffers = request->buffers(); + for (const auto &[stream, buffer] : buffers) { + MappedFrameBuffer in(buffer, MappedFrameBuffer::MapFlag::Read); + if (in.isValid()) { + auto data = in.planes()[0].data(); + auto streamConfig = stream->configuration(); + auto formatInfo = PixelFormatInfo::info(streamConfig.pixelFormat); + + std::function calcPixelMean; + int pixelStride; + + switch (streamConfig.pixelFormat) { + case formats::NV12: + calcPixelMean = calcPixelMeanNV12; + pixelStride = 1; + break; + case formats::SRGGB10: + calcPixelMean = calcPixelMeanRAW10; + pixelStride = 2; + break; + default: + std::stringstream s; + s << "Unsupported Pixelformat " << formatInfo.name; + throw std::invalid_argument(s.str()); + } + + double sum = 0; + int w = 20; + int xs = streamConfig.size.width / 2 - w / 2; + int ys = streamConfig.size.height / 2 - w / 2; + + for (auto y = ys; y < ys + w; y++) { + auto line = data + y * streamConfig.stride; + for (auto x = xs; x < xs + w; x++) { + sum += calcPixelMean(line + x * pixelStride); + } + } + sum = sum / (w * w); + return sum; + } + } + return 0; +} + +TimeSheetEntry::TimeSheetEntry(const ControlIdMap &idmap) + : controls_(idmap) +{ +} + +void TimeSheetEntry::handleCompleteRequest(libcamera::Request *request, const TimeSheetEntry *previous) +{ + metadata_ = request->metadata(); + + spotBrightness_ = calculateMeanBrightnessFromCenterSpot(request); + if (previous) { + brightnessChange_ = spotBrightness_ / previous->getSpotBrightness(); + } + sequence_ = request->sequence(); +} + +void TimeSheetEntry::printInfo() +{ + std::cout << "=== Frame " << sequence_ << std::endl; + if (!controls_.empty()) { + std::cout << "Controls:" << std::endl; + auto idMap = controls_.idMap(); + assert(idMap); + for (const auto &[id, value] : controls_) { + std::cout << " " << idMap->at(id)->name() << " : " << value.toString() << std::endl; + } + } + + if (!metadata_.empty()) { + std::cout << "Metadata:" << std::endl; + auto idMap = metadata_.idMap(); + assert(idMap); + for (const auto &[id, value] : metadata_) { + std::cout << " " << idMap->at(id)->name() << " : " << value.toString() << std::endl; + } + } + + std::cout << "Calculated Brightness: " << spotBrightness_ << std::endl; +} + +TimeSheetEntry &TimeSheet::get(size_t pos) +{ + auto &entry = entries_[pos]; + if (!entry) + entry = std::make_shared(idmap_); + return *entry; +} + +void TimeSheet::prepareForQueue(libcamera::Request *request, uint32_t sequence) +{ + request->controls() = get(sequence).controls(); +} + +void TimeSheet::handleCompleteRequest(libcamera::Request *request) +{ + uint32_t sequence = request->sequence(); + auto &entry = get(sequence); + TimeSheetEntry *previous = nullptr; + if (sequence >= 1) { + previous = entries_[sequence - 1].get(); + } + + entry.handleCompleteRequest(request, previous); +} + +void TimeSheet::printAllInfos() +{ + for (auto entry : entries_) { + if (entry) + entry->printInfo(); + } +} diff --git a/src/apps/lc-compliance/time_sheet.h b/src/apps/lc-compliance/time_sheet.h new file mode 100644 index 00000000..2bb89ab3 --- /dev/null +++ b/src/apps/lc-compliance/time_sheet.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Ideas on Board Oy + * + * time_sheet.h + */ + +#pragma once + +#include +#include + +#include + +class TimeSheetEntry +{ +public: + TimeSheetEntry() = delete; + TimeSheetEntry(const libcamera::ControlIdMap &idmap); + TimeSheetEntry(TimeSheetEntry &&other) noexcept = default; + TimeSheetEntry(const TimeSheetEntry &) = delete; + + libcamera::ControlList &controls() { return controls_; }; + libcamera::ControlList &metadata() { return metadata_; }; + void handleCompleteRequest(libcamera::Request *request, const TimeSheetEntry *previous); + void printInfo(); + double getSpotBrightness() const { return spotBrightness_; }; + double getBrightnessChange() const { return brightnessChange_; }; + +private: + double spotBrightness_ = 0.0; + double brightnessChange_ = 0.0; + libcamera::ControlList controls_; + libcamera::ControlList metadata_; + uint32_t sequence_ = 0; +}; + +class TimeSheet +{ +public: + TimeSheet(int count, const libcamera::ControlIdMap &idmap) + : idmap_(idmap), entries_(count){}; + + void prepareForQueue(libcamera::Request *request, uint32_t sequence); + void handleCompleteRequest(libcamera::Request *request); + void printAllInfos(); + + TimeSheetEntry &operator[](size_t pos) { return get(pos); }; + TimeSheetEntry &get(size_t pos); + size_t size() const { return entries_.size(); }; + +private: + const libcamera::ControlIdMap &idmap_; + std::vector> entries_; +};