From patchwork Mon May 11 18:16:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Javier Tia X-Patchwork-Id: 26714 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 7483CBDCBD for ; Mon, 11 May 2026 18:16:12 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1D7A26301A; Mon, 11 May 2026 20:16:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=jetm.me header.i=@jetm.me header.b="fVU4tIpK"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="Ti5dcHpp"; dkim-atps=neutral Received: from fout-b1-smtp.messagingengine.com (fout-b1-smtp.messagingengine.com [202.12.124.144]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8483562E9D for ; Mon, 11 May 2026 20:16:06 +0200 (CEST) Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfout.stl.internal (Postfix) with ESMTP id 792A91D00155; Mon, 11 May 2026 14:16:05 -0400 (EDT) Received: from phl-imap-07 ([10.202.2.97]) by phl-compute-02.internal (MEProxy); Mon, 11 May 2026 14:16:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jetm.me; h=cc:cc :content-transfer-encoding:content-type:content-type:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm2; t=1778523365; x=1778609765; bh=bXv8QgCOCwDnXna1X01SjMJ8LH44mXxXFsakOOrQ30g=; b= fVU4tIpKKubSxYJXtIs7StvjguoWToRX40vLWlgDVr40M+BPFNVGI+q4f2KMRopw 8xuDj8Ic2gwHBM5y2hamQV/8jgGojFn/+1msMxIpYbCrUL2u8kKe4rliaWN6Dzdh s4x2SOVg9OFzrcYicX3UDxNlxPaeHiwscmKDBu5nAJ8jXy4hNVeWNNPri00Y1VYC 2k4V1tETyvcptmYA5vIDC0LbL+6vJjT4pHMJ+HJGF3dWxVHowKEwnXf9jO1JRZqj rwvZZ0CaH4skOYtUFugf5qZ22YezA1LB5EiSxroA8lm/CoBp19wcjtY3++9fGHst 0qMAfEE1Y4EsJ+s6obTZSQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1778523365; x= 1778609765; bh=bXv8QgCOCwDnXna1X01SjMJ8LH44mXxXFsakOOrQ30g=; b=T i5dcHppbW9YuQDLjSluP4iT1/OKRUIT3d4nh8kWjLPtm73TelYimTGxwyKwNPUxC KjKOUq9FLTbK+OiirLNoZrtlxm983bFhak9+z9fY7Ciqj/jDbLELNSVmLb47/vl+ oz0MSLprDn55tBhATfn1pxOp9cYFaE54dSLaW9zpjVwrrbwdWgEc9k1p1gyPXBGG 740cYPc8TYYraPB3WDhhoaY9642tjiFHLuH7tqVmeUVqLofhUF17WLVzv2poFGbN uaKcXsBUyNlaGjAc7dngm9DZyoUsdVM0vq/4TsZnF0KkEqV9diecDd5iPsG8ecWQ wWtlq6VD9p08r66WfB0Tw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdduudeliedvucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepoffhfffugggtgffkvfevofgjfhesthekredtredtjeenucfhrhhomheplfgrvhhi vghrucfvihgruceofhhlohhsshesjhgvthhmrdhmvgeqnecuggftrfgrthhtvghrnhepve ektdfhffevuddtgfetieevtddvheduhfeggfekveejlefhleefieevueefiefhnecuvehl uhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepfhhlohhsshesjh gvthhmrdhmvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmhhtphhouhhtpdhrtghp thhtoheprhhosggvrhhtrdhmrgguvghrsegtohhllhgrsghorhgrrdgtohhmpdhrtghpth htohepsggrrhhnrggsrghsrdhpohgtiigvsehiuggvrghsohhnsghorghrugdrtghomhdp rhgtphhtthhopehkihgvrhgrnhdrsghinhhghhgrmhesihguvggrshhonhgsohgrrhgurd gtohhmpdhrtghpthhtoheplhgruhhrvghnthdrphhinhgthhgrrhhtsehiuggvrghsohhn sghorghrugdrtghomhdprhgtphhtthhopehlihgstggrmhgvrhgrqdguvghvvghlsehlih hsthhsrdhlihgstggrmhgvrhgrrdhorhhgpdhrtghpthhtohepjhhohhgrnhhnvghsrdhg ohgvuggvsehoshhsrdhquhgrlhgtohhmmhdrtghomhdprhgtphhtthhopehmiigrmhgrii grlhesrhgvughhrghtrdgtohhm X-ME-Proxy: Feedback-ID: i9dde48b3:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 2103A1EA006B; Mon, 11 May 2026 14:16:05 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface From: Javier Tia Date: Mon, 11 May 2026 12:16:01 -0600 Subject: [PATCH v3 1/3] libcamera: software_isp: Drop redundant sumShift_ guard in finishFrame MIME-Version: 1.0 Message-Id: <20260511-ov2740-tuning-v3-1-8ff3e57c7368@jetm.me> To: libcamera-devel@lists.libcamera.org Cc: Kieran Bingham , Laurent Pinchart , =?utf-8?b?QmFybmFiw6FzIFDFkWN6?= =?utf-8?q?e?= , Milan Zamazal , Robert Mader , Hans de Goede X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=1350; i=floss@jetm.me; h=from:subject:message-id; bh=Nxi4aMjw+W7YmkXEKUECwpuUfdMTxYTUXauUrkEo+Zk=; b=owEB7QES/pANAwAKAbXuwwuoZ3cfAcsmYgBqAhzgH1/tCUwaCjDdT1t3c9tayJ+QNq+2Q5qgq UEn7PblWOyJAbMEAAEKAB0WIQSbE7ILzw7eI0VKk8m17sMLqGd3HwUCagIc4AAKCRC17sMLqGd3 Hx1NDACRxzeKteXgVsNScj4P7fmQCHMti+W8xgi5SyTXXqbOrJpu8tHG2EPEVwrasfEBJu4yzrT c92d/SW4oY8Ed9gPs40cmiwLpU35xsxkMQs5cm5+puN1tGnbEMBdE757cXj/Dn0Wjcpoa+veADt UOrJ55dz/AvkImTvs1dDdQvYtKBzwCQqfG0WNc/7ZF5n5XxFFD5j04XdVBP2zDudfagEMZDOnq3 3WQWXPljNhLaneEIhEDpIgDBfDgwpteaV3b9ZiL6PNFJ+tj+NrJXyp3GdzP19DLYaGAcsOtg06F N65KFZHryX5enqlPzbLGTE65SuqNBuzo+xabnNC0SjdAWTixEGxGxZeVKfDz8LI9kHnqWPT6am9 J/MI00SnNV1o2f9cCSGBPkAsDEO8e+yGVPlBr0pongug3zNmjWEXwbGVSWO3Mke5dBs0szPZHDl xHNru9j4EgeA4y+Jb+8c9j03w4P2Pe1dohavyYCEqTYMYNqralFzoCA1MTVIM1112sG+U= X-Developer-Key: i=floss@jetm.me; a=openpgp; fpr=9B13B20BCF0EDE23454A93C9B5EEC30BA867771F In-Reply-To: <20260511-ov2740-tuning-v3-0-8ff3e57c7368@jetm.me> References: <20260511-ov2740-tuning-v3-0-8ff3e57c7368@jetm.me> 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Right-shifting by zero is a no-op, so the if (sumShift_) check before the three >>= sumShift_ assignments is unnecessary. Remove it. Suggested-by: Laurent Pinchart Suggested-by: Barnabas Pocze Signed-off-by: Javier Tia Reviewed-by: Laurent Pinchart Reviewed-by: Barnabás Pőcze --- src/libcamera/software_isp/swstats_cpu.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp index b40d3334..2e020e62 100644 --- a/src/libcamera/software_isp/swstats_cpu.cpp +++ b/src/libcamera/software_isp/swstats_cpu.cpp @@ -362,11 +362,10 @@ void SwStatsCpu::finishFrame(uint32_t frame, uint32_t bufferId) for (unsigned int j = 0; j < SwIspStats::kYHistogramSize; j++) sharedStats_->yHistogram[j] += s.yHistogram[j]; } - if (sumShift_) { - sharedStats_->sum_.r() >>= sumShift_; - sharedStats_->sum_.g() >>= sumShift_; - sharedStats_->sum_.b() >>= sumShift_; - } + + sharedStats_->sum_.r() >>= sumShift_; + sharedStats_->sum_.g() >>= sumShift_; + sharedStats_->sum_.b() >>= sumShift_; } sharedStats_->valid = valid; From patchwork Mon May 11 18:16:02 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Javier Tia X-Patchwork-Id: 26715 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 5FA27C32F7 for ; Mon, 11 May 2026 18:16:14 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D90EB6302E; Mon, 11 May 2026 20:16:12 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=jetm.me header.i=@jetm.me header.b="bceJVvT3"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="PqVQs8Sk"; dkim-atps=neutral Received: from fhigh-b1-smtp.messagingengine.com (fhigh-b1-smtp.messagingengine.com [202.12.124.152]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5F77D62DC4 for ; Mon, 11 May 2026 20:16:08 +0200 (CEST) Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfhigh.stl.internal (Postfix) with ESMTP id EB9387A00C4; Mon, 11 May 2026 14:16:06 -0400 (EDT) Received: from phl-imap-07 ([10.202.2.97]) by phl-compute-02.internal (MEProxy); Mon, 11 May 2026 14:16:07 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jetm.me; h=cc:cc :content-transfer-encoding:content-type:content-type:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm2; t=1778523366; x=1778609766; bh=2gWSqYkwBitTNhg3SSRLFDPdQLDS0MxbIfQ7KDluudQ=; b= bceJVvT3rQq3EVuQfYgFOnxZrDMrjp/Chv3htv3aYeeHHJH5zVBgaMyBFxzsrFwo IhcrYhHZlFpbUBVnRQsK1brO+aEOPE0KtyzT4VuamEGYBnGfM4oDg5joffYyPHn4 g1Bo723n6MfeVO6dIBmFBEbxDtPMSvbWMP8Bd/BtpAFCqoh6MaU+6sSV6Ma5bF1T Rz/tP7+9VuqYpb/0qz/KWHNNYewp2pNGif4S8reZz8si3fHavIPo77SDBvWX2hQo vhAyyQYJS2iNd0sXt8WQmnc4hYH9QztpS9Llf1Qb6xHoH3fD/pB/Tec10swX/2jV jd0p5Pm1h4ZuTZ9WmagWKA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1778523366; x= 1778609766; bh=2gWSqYkwBitTNhg3SSRLFDPdQLDS0MxbIfQ7KDluudQ=; b=P qVQs8SkMQQfKTL22v6P2KaLXwQD91jw9LTqCRJsuvN0e3jpJN4QUoByEnwC2iCub oA0AhxEkBISnyH9e/xXA8Tcjm/FaBWZJNME+NmLuXeyCocW/aCmNLUFicM8fNfUT KnZNTFBBbee4ui/sLQ5oQs7JBa58DTbdScAzhaH7X1EwC3VSfFuU8kvosg/Wr9CL i5tHhW4EmKAST2mWeRqbnY1a54UO8FEMIfq8/zqjPiTmc1rM9br9Dao/Dy4/MBA+ yoxwd2pPWxsUxc6Ktby39Qq7cf6cdpFaqxx70IB6biahIi03me52uDBVrozgOe8L fW35P15U//8lntxSp9QJQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdduudeliedvucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepoffhfffugggtgffkvfevofgjfhesthejredtredtjeenucfhrhhomheplfgrvhhi vghrucfvihgruceofhhlohhsshesjhgvthhmrdhmvgeqnecuggftrfgrthhtvghrnhepvd dtjeeiheeijedtveeujeevvdekjeeuveekleeijeekfeejhfefveeiffffvdeinecuvehl uhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepfhhlohhsshesjh gvthhmrdhmvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmhhtphhouhhtpdhrtghp thhtoheprhhosggvrhhtrdhmrgguvghrsegtohhllhgrsghorhgrrdgtohhmpdhrtghpth htohepsggrrhhnrggsrghsrdhpohgtiigvsehiuggvrghsohhnsghorghrugdrtghomhdp rhgtphhtthhopehkihgvrhgrnhdrsghinhhghhgrmhesihguvggrshhonhgsohgrrhgurd gtohhmpdhrtghpthhtoheplhgruhhrvghnthdrphhinhgthhgrrhhtsehiuggvrghsohhn sghorghrugdrtghomhdprhgtphhtthhopehlihgstggrmhgvrhgrqdguvghvvghlsehlih hsthhsrdhlihgstggrmhgvrhgrrdhorhhgpdhrtghpthhtohepjhhohhgrnhhnvghsrdhg ohgvuggvsehoshhsrdhquhgrlhgtohhmmhdrtghomhdprhgtphhtthhopehmiigrmhgrii grlhesrhgvughhrghtrdgtohhm X-ME-Proxy: Feedback-ID: i9dde48b3:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id ABE2C1EA006B; Mon, 11 May 2026 14:16:06 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface From: Javier Tia Date: Mon, 11 May 2026 12:16:02 -0600 Subject: [PATCH v3 2/3] ipa: simple: data: Add OV2740 tuning file MIME-Version: 1.0 Message-Id: <20260511-ov2740-tuning-v3-2-8ff3e57c7368@jetm.me> To: libcamera-devel@lists.libcamera.org Cc: Kieran Bingham , Laurent Pinchart , =?utf-8?b?QmFybmFiw6FzIFDFkWN6?= =?utf-8?q?e?= , Milan Zamazal , Robert Mader , Hans de Goede X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3811; i=floss@jetm.me; h=from:subject:message-id; bh=PF2gc+FYa/uT/H4EVGsAYS/w7sQZDONq0fZ6ceMKq0g=; b=owEB7QES/pANAwAKAbXuwwuoZ3cfAcsmYgBqAhzgRMkuHei5e/6URAeecjaFweFi3rArbT16V mIlovtDNayJAbMEAAEKAB0WIQSbE7ILzw7eI0VKk8m17sMLqGd3HwUCagIc4AAKCRC17sMLqGd3 Hyq5C/44qiLBs64vTrqL/Vws4sRJbtrq/dCRG1lapFLMtG/OoVvNYHa6uTgA/6UNBSHjZ9E4ypb Nv4A8m3vLht8K6fj5lHgSeoXHp/E3m8lmcBEhRVYUTa49hqYPAOQ1tLJ3Msssw44SgX4hXcxigE +2np2aC061lZJFCFesNpaNkPm0XeRAWykuUy3fK+zjWXPCAayJvK8bwrgHiCrqnOM9xm2GRRGYp 8odImRAqs/V2QsZuucKN34a+nb/kwevD78ETlO2O4bkElrT71MG7okABCNn3yVOJFa8SI7xo/nm I7uOpWoxhQUGLA9jiCNTX6qw3JCLv1PtuFi5nad/69xXz6IxnOUeUynpMZET/k+n8PrFMuvvths VgycGTGST0Nam/Td5ZwhNoNgIQ+RvBqObTYJcJVT7nyw/OO/RGHTx8HwJGf21ZifBKykP76vdXZ FHooHYEUcJOKdUTYokfEQ2nQxrQWjUL/KuhURzYMmf8CTYdYxOgcaFzHADMrQQIE28bII= X-Developer-Key: i=floss@jetm.me; a=openpgp; fpr=9B13B20BCF0EDE23454A93C9B5EEC30BA867771F In-Reply-To: <20260511-ov2740-tuning-v3-0-8ff3e57c7368@jetm.me> References: <20260511-ov2740-tuning-v3-0-8ff3e57c7368@jetm.me> 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a tuning file for the OV2740 sensor calibrated from the Intel IPU6 AIQB binary (OV2740_CJFLE23_ADL.aiqb) shipped with the Lenovo ThinkPad X1 Carbon Gen 10 (Alder Lake, JP2 module, Chicony CJFLE23 camera). Black level is 0x40 at 10-bit (64 ADU), stored as the 16-bit value 4096 per the BlackLevel algorithm convention (value >> 8 = 16 at 8-bit scale). AWB gain limits are derived from the minimum R/G and B/G chromaticities across the 8 calibrated illuminants (2319 K to 6302 K), with a 10% headroom margin: maxGainR=2.49, maxGainB=3.07. Eight CCMs are extracted from the AIQB advanced color matrix records (record id=25, float format), covering illuminants from 2319 K (incandescent) to 6302 K (daylight). Signed-off-by: Javier Tia --- src/ipa/simple/data/meson.build | 1 + src/ipa/simple/data/ov2740.yaml | 72 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/src/ipa/simple/data/meson.build b/src/ipa/simple/data/meson.build index 92795ee4..e3e4de74 100644 --- a/src/ipa/simple/data/meson.build +++ b/src/ipa/simple/data/meson.build @@ -1,6 +1,7 @@ # SPDX-License-Identifier: CC0-1.0 conf_files = files([ + 'ov2740.yaml', 'uncalibrated.yaml', ]) diff --git a/src/ipa/simple/data/ov2740.yaml b/src/ipa/simple/data/ov2740.yaml new file mode 100644 index 00000000..0704143a --- /dev/null +++ b/src/ipa/simple/data/ov2740.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: CC0-1.0 +# Calibrated from OV2740_CJFLE23_ADL.aiqb (Lenovo JP2 module, IPU6 ADL) +%YAML 1.1 +--- +version: 1 +algorithms: + - BlackLevel: + blackLevel: 4096 + - Awb: + algorithm: grey + maxGainR: 2.49 + maxGainB: 3.07 + speed: 0.25 + # Forward-compatible with the AwbGrey colourGains interpolation in + # libcamera patch series 5874. Has no effect until that series merges. + colourGains: + - ct: 2319 + gains: [1.0103, 2.7953] + - ct: 2854 + gains: [1.2614, 2.3815] + - ct: 2884 + gains: [1.3996, 2.4229] + - ct: 3239 + gains: [1.5648, 2.2331] + - ct: 3865 + gains: [1.7861, 1.8856] + - ct: 4136 + gains: [1.9005, 1.8955] + - ct: 4939 + gains: [1.9603, 1.6439] + - ct: 6302 + gains: [2.2597, 1.4038] + - Ccm: + ccms: + - ct: 2319 + ccm: [ 1.5938, -0.1714, -0.4224, + -0.6134, 1.9612, -0.3478, + -0.4710, -1.8500, 3.3210 ] + - ct: 2854 + ccm: [ 1.6119, -0.3132, -0.2987, + -0.4418, 1.8227, -0.3809, + -0.1017, -1.3958, 2.4975 ] + - ct: 2884 + ccm: [ 1.7739, -0.6655, -0.1085, + -0.4113, 1.6619, -0.2506, + -0.0150, -1.1661, 2.1811 ] + - ct: 3239 + ccm: [ 1.8298, -0.6636, -0.1662, + -0.4086, 1.7373, -0.3287, + -0.0500, -1.0836, 2.1335 ] + - ct: 3865 + ccm: [ 1.8836, -0.7430, -0.1406, + -0.3653, 1.7000, -0.3348, + -0.0542, -0.8442, 1.8984 ] + - ct: 4136 + ccm: [ 1.9043, -0.8348, -0.0695, + -0.3241, 1.6389, -0.3148, + 0.0262, -0.9593, 1.9332 ] + - ct: 4939 + ccm: [ 1.6371, -0.4490, -0.1881, + -0.2675, 1.6494, -0.3819, + -0.0245, -0.7782, 1.8026 ] + - ct: 6302 + ccm: [ 1.6401, -0.4418, -0.1984, + -0.2360, 1.7191, -0.4832, + -0.0248, -0.7221, 1.7469 ] + - Adjust: + gamma: 2.2 + contrast: 1.0 + saturation: 1.0 + - Agc: +... From patchwork Mon May 11 18:16:03 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Javier Tia X-Patchwork-Id: 26716 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 25581BDCBD for ; Mon, 11 May 2026 18:16:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B024563020; Mon, 11 May 2026 20:16:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=jetm.me header.i=@jetm.me header.b="viGNj2F9"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="nI9jbXty"; dkim-atps=neutral Received: from fout-b1-smtp.messagingengine.com (fout-b1-smtp.messagingengine.com [202.12.124.144]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A69566302C for ; Mon, 11 May 2026 20:16:09 +0200 (CEST) Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfout.stl.internal (Postfix) with ESMTP id A0E181D00134; Mon, 11 May 2026 14:16:08 -0400 (EDT) Received: from phl-imap-07 ([10.202.2.97]) by phl-compute-02.internal (MEProxy); Mon, 11 May 2026 14:16:08 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jetm.me; h=cc:cc :content-transfer-encoding:content-type:content-type:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm2; t=1778523368; x=1778609768; bh=fZq8EJTkljr6qchHJWWzJ+vDKc1flX5PrThPvbc//r0=; b= viGNj2F9lHb5uzPz3yUB5+yugfuCcD4k+mSazLfOuBWvqS5p/4x3OUkMYCh3iHQG yT3VwVfDyl1FjhZuTnw37DslqSIMrsGu/cPlhUNOy7ZD3GPgBu6ak7NLHoUl4L0B Yat3AzoIZFaXbU8kEtrBHgE9rJZR3i1kR+/gR87Ec7kE1tc7O4rbCkupvfj6VcOD 9fQtTWIExj/HSSEhuf6HOxOD/oJuX6F5+1nVgDa1UAqZ3fQtbGgF+QWE8Jw1qv+5 AklOFRB9+jFTW07Js/zPlrzYnz45iUf6GC7RmfCDERhCkgzkF5PPHQFfMFCApsro jZCSPflS5wRoKmULYgbc4g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1778523368; x= 1778609768; bh=fZq8EJTkljr6qchHJWWzJ+vDKc1flX5PrThPvbc//r0=; b=n I9jbXtyXLUHKf/EIg+2Om0HfylrreZoRe7RsxAZNcwX8JyZvecROshBJUP2FfNN2 dCW1u1w7gfruhY7Z7sNaFncQiSRU8vvszSOdmkQgPhHLQ2STYpWzGDAo4LNplH9x w2IODrhtTbN7XQ8prBRKUWOZS1rN2zgY/oOIxNdG6Q+HH/+cjfvEINRZ7Ecu+Gyj tgeZuAnmykbBrZPSfbWne1CovDCY+fjxC4BIbP9gidfvKAYoGCTdTyf/XqRq03A9 2fx355MSAJlbN1PTncfn9rHDl6crB4Lq2nbBYenqKRpO7lscwEOS5LKtQzaPIaOH dKJGDrEH2hTTPub1DXpJg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdduudeliedvucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepoffhfffugggtgffkvfevofgjfhesthejredtredtjeenucfhrhhomheplfgrvhhi vghrucfvihgruceofhhlohhsshesjhgvthhmrdhmvgeqnecuggftrfgrthhtvghrnhepvd dtjeeiheeijedtveeujeevvdekjeeuveekleeijeekfeejhfefveeiffffvdeinecuvehl uhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepfhhlohhsshesjh gvthhmrdhmvgdpnhgspghrtghpthhtohepjedpmhhouggvpehsmhhtphhouhhtpdhrtghp thhtoheprhhosggvrhhtrdhmrgguvghrsegtohhllhgrsghorhgrrdgtohhmpdhrtghpth htohepsggrrhhnrggsrghsrdhpohgtiigvsehiuggvrghsohhnsghorghrugdrtghomhdp rhgtphhtthhopehkihgvrhgrnhdrsghinhhghhgrmhesihguvggrshhonhgsohgrrhgurd gtohhmpdhrtghpthhtoheplhgruhhrvghnthdrphhinhgthhgrrhhtsehiuggvrghsohhn sghorghrugdrtghomhdprhgtphhtthhopehlihgstggrmhgvrhgrqdguvghvvghlsehlih hsthhsrdhlihgstggrmhgvrhgrrdhorhhgpdhrtghpthhtohepjhhohhgrnhhnvghsrdhg ohgvuggvsehoshhsrdhquhgrlhgtohhmmhdrtghomhdprhgtphhtthhopehmiigrmhgrii grlhesrhgvughhrghtrdgtohhm X-ME-Proxy: Feedback-ID: i9dde48b3:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 5EB601EA006B; Mon, 11 May 2026 14:16:08 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface From: Javier Tia Date: Mon, 11 May 2026 12:16:03 -0600 Subject: [PATCH v3 3/3] utils: tuning: Add AIQB parser for Intel IPU6 sensors MIME-Version: 1.0 Message-Id: <20260511-ov2740-tuning-v3-3-8ff3e57c7368@jetm.me> To: libcamera-devel@lists.libcamera.org Cc: Kieran Bingham , Laurent Pinchart , =?utf-8?b?QmFybmFiw6FzIFDFkWN6?= =?utf-8?q?e?= , Milan Zamazal , Robert Mader , Hans de Goede X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=13107; i=floss@jetm.me; h=from:subject:message-id; bh=zLEZJnbL/f9IDk7PLYWHX+loEL0ZBAf+qBOeFcEUo3w=; b=owEB7QES/pANAwAKAbXuwwuoZ3cfAcsmYgBqAhzgVVSsu5Kp0AQ4KZhGdx/5fom+OENXDpTqI IKLRA4DRZiJAbMEAAEKAB0WIQSbE7ILzw7eI0VKk8m17sMLqGd3HwUCagIc4AAKCRC17sMLqGd3 HxgOC/9xh9cNDSpA6ywkE0Sv+wIAk74QIyo051nqYGzCvbVzBUPYPbkHbjkFuGUwkIXtgUCyHTE gZkJjrAff93oucxjjtxbOzeHwE1nWS7QW6A3EMMqPf7ObwSo7qVogmFSzQCq02gh+wTLklI+unq xjD4IJ8EeJ2la1Xj4qp39xAx2MWK9v9UVHnFKPSMbyQF5LanhapjBjk0HZjPWlK0bX1Xf3qXv1i WHpoIgqHvXiysUDsnL3649mtKJlQU5PG6i+dMlZAt/WBza/l+1u6xG8P9DdcOXEHE11pqfTWaEu +z4J3Pr0r9QCDyYPoIqQbO2ouC6ZPUKk7pEHfV3LTF55D6mxz8S8xO165B0ZKpWbf34yMH/yajN 5ySAMFM0Xk+ha4zf9xhspko2r04wfZckjvAxCOpHM04u5JITEWb/Bzmas4PWblhACJj71UpFWog tr/f4xn/X4Sth9L7kLPToAZo3779cUkHDOZ0Al/z+JH0hrvVxIeMJJltU0T80VID/UEco= X-Developer-Key: i=floss@jetm.me; a=openpgp; fpr=9B13B20BCF0EDE23454A93C9B5EEC30BA867771F In-Reply-To: <20260511-ov2740-tuning-v3-0-8ff3e57c7368@jetm.me> References: <20260511-ov2740-tuning-v3-0-8ff3e57c7368@jetm.me> 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a Python script to extract CCMs and AWB chromaticity limits from Intel AIQB binary calibration files, producing a ready-to-use libcamera Simple IPA tuning YAML. AIQB is Intel's proprietary calibration format shipped with Windows camera drivers for Intel IPU6 sensors. Files for Alder Lake and Tiger Lake sensors are available in the ipu6-camera-hal repository under config/linux/ipu6ep/, or can be extracted from OEM Windows driver installers using p7zip and innoextract. The script supports record id=25 (advanced color matrices, float format with CCT in Kelvin directly) and falls back to record id=18 (integer matrices with autodetected scale). Record id=25 is preferred and present in all Alder Lake AIQB files examined. Tested against OV2740_CJFLE23_ADL.aiqb (Lenovo ThinkPad X1 Carbon Gen 10, extracted from n3ace31w.exe). Other AIQB files may require adjustments if the record layout differs. Signed-off-by: Javier Tia --- utils/tuning/parse_aiqb.py | 335 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) diff --git a/utils/tuning/parse_aiqb.py b/utils/tuning/parse_aiqb.py new file mode 100644 index 00000000..2308f967 --- /dev/null +++ b/utils/tuning/parse_aiqb.py @@ -0,0 +1,335 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Parse an Intel AIQB (CPFF) binary to extract CCMs and AWB colour gains +# for use in a libcamera Simple IPA tuning YAML file. +# +# Format reverse-engineered from ipu6-camera-hal headers (ia_cmc_types.h). +# AIQB files are available in the ipu6-camera-hal repository at +# config/linux/ipu6ep/, or can be extracted from OEM Windows camera +# driver installers using p7zip and innoextract. + +import argparse +import os +import struct +import sys +from dataclasses import dataclass + +import yaml + +# ia_mkn_record_header: size(u32), fmt_id(u8), key_id(u8), name_id(u16) +REC_HDR = struct.Struct(' approximate CCT in Kelvin +LIGHT_SOURCE_CCT = { + 1: 2856, # A - Incandescent/Tungsten + 4: 5003, # D50 + 5: 5503, # D55 + 6: 6504, # D65 + 7: 7504, # D75 + 8: 5454, # E (equal energy) + 9: 6430, # F1 daylight fluorescent + 10: 4230, # F2 cool white + 11: 3450, # F3 white + 12: 3000, # F4 warm white + 13: 6350, # F5 + 14: 4150, # F6 + 15: 6500, # F7 D65 sim + 16: 5000, # F8 D50 sim + 17: 4150, # F9 + 18: 5000, # F10 + 19: 4000, # F11 + 20: 3000, # F12 + 22: 2300, # HZ horizon +} + +# Record chain starts here in all AIQB files checked so far +FIRST_RECORD_OFFSET = 0x50 + + +@dataclass +class ColorMatrixRecord: + light_src_type: int + r_per_g_raw: int + b_per_g_raw: int + cie_x: int + cie_y: int + matrix_accurate: tuple + matrix_preferred: tuple + + +class _FlowList(list): + """YAML sequence serialised as a flow sequence (single line).""" + + +class _Dumper(yaml.Dumper): + pass + + +_Dumper.add_representer( + _FlowList, + lambda dumper, data: dumper.represent_sequence( + 'tag:yaml.org,2002:seq', data, flow_style=True + ), +) + + +def walk_records(data): + records = {} + offset = FIRST_RECORD_OFFSET + while offset + REC_HDR_SIZE <= len(data): + size, fmt_id, key_id, name_id = REC_HDR.unpack_from(data, offset) + if size < REC_HDR_SIZE or offset + size > len(data): + break + records[name_id] = (offset, size) + offset += size + return records + + +def extract_general_data(data, offset): + w, h, bd, co = struct.unpack_from(' record_end: + num = max(0, (record_end - mat_offset) // COLOR_MATRIX.size) + print(f" WARNING: record id=18 truncated, reading {num} matrices") + for i in range(num): + unpacked = COLOR_MATRIX.unpack_from(data, mat_offset + i * 84) + rec = ColorMatrixRecord( + light_src_type=unpacked[0], + r_per_g_raw=unpacked[1], + b_per_g_raw=unpacked[2], + cie_x=unpacked[3], + cie_y=unpacked[4], + matrix_accurate=unpacked[5:14], + matrix_preferred=unpacked[14:23], + ) + matrices.append({ + 'light_src': rec.light_src_type, + 'cct': LIGHT_SOURCE_CCT.get(rec.light_src_type), + 'r_per_g_raw': rec.r_per_g_raw, + 'b_per_g_raw': rec.b_per_g_raw, + 'matrix_raw': rec.matrix_accurate, + }) + return matrices + + +def extract_advanced_color_matrices(data, offset, size): + """Parse cmc_advanced_color_matrix_correction (record id=25). + + Layout after the 8-byte record header: + uint16 num_light_srcs + uint16 num_sectors + uint32 hue_of_sectors[num_sectors] + Per light source (24-byte cmc_acm_color_matrices_info_v101_t): + uint32 src_type + float r_per_g + float b_per_g + float cie_x + float cie_y + uint32 cct (Kelvin, directly) + float traditional[9] (3x3 CCM, rows sum to 1.0) + float advanced[num_sectors][9] (per-sector CCMs, skipped) + """ + record_end = offset + size + pos = offset + REC_HDR_SIZE + num_ls, num_sectors = struct.unpack_from(' record_end: + print(" WARNING: record id=25 truncated, stopping early") + break + src_type, rg, bg, cie_x, cie_y, cct_k = info_fmt.unpack_from(data, pos) + pos += 24 + if pos + ccm_fmt.size > record_end: + print(" WARNING: record id=25 truncated, stopping early") + break + trad = ccm_fmt.unpack_from(data, pos) + pos += 36 + matrices.append({ + 'light_src': src_type, + 'cct': cct_k, + 'r_per_g': rg, + 'b_per_g': bg, + 'matrix_float': trad, + }) + if pos + sector_skip > record_end: + print(" WARNING: record id=25 truncated in advanced sectors, stopping early") + break + pos += sector_skip + return matrices + + +def guess_ccm_scale(matrices): + if not matrices: + return 8192 + for scale in (8192, 4096, 2048, 1024): + errors = [] + for m in matrices: + for row in range(3): + s = sum(m['matrix_raw'][row * 3:(row + 1) * 3]) / scale + errors.append(abs(s - 1.0)) + if max(errors) < 0.05: + return scale + return 8192 + + +def main(): + parser = argparse.ArgumentParser( + description='Parse Intel AIQB binary for libcamera Simple IPA YAML', + epilog='Tested on OV2740_CJFLE23_ADL.aiqb only. Other sensors may ' + 'require adjustments.') + parser.add_argument('aiqb', help='Path to .aiqb file') + parser.add_argument('--sensor-name', + help='Sensor name for YAML output (default: derived ' + 'from filename)') + parser.add_argument('--ccm-scale', type=int, default=0, + help='Integer CCM scale for record id=18 (0=autodetect)') + args = parser.parse_args() + + sensor_name = args.sensor_name or os.path.basename(args.aiqb).split('_')[0].lower() + output_path = f'{sensor_name}.yaml' + + with open(args.aiqb, 'rb') as f: + data = f.read() + + print(f"File: {args.aiqb} ({len(data)} bytes)") + + records = walk_records(data) + print(f"Records found: {sorted(records.keys())}\n") + + if CMC_GENERAL_DATA in records: + gd = extract_general_data(data, records[CMC_GENERAL_DATA][0]) + print(f"Sensor: {gd['width']}x{gd['height']}, {gd['bit_depth']}-bit, " + f"color_order={gd['color_order']}") + + if CMC_SENSITIVITY in records: + iso = extract_sensitivity(data, records[CMC_SENSITIVITY][0]) + print(f"Base ISO: {iso}") + + adv_mode = False + if CMC_ADV_COLOR_MATRICES in records: + matrices = extract_advanced_color_matrices(data, *records[CMC_ADV_COLOR_MATRICES]) + adv_mode = True + print(f"\nAdvanced color matrices (id=25, {len(matrices)} entries, float CCMs):") + elif CMC_COLOR_MATRICES in records: + matrices = extract_color_matrices(data, *records[CMC_COLOR_MATRICES]) + print(f"\nColor matrices (id=18, {len(matrices)} entries):") + else: + print("ERROR: no color_matrices record found (id=18 or id=25)") + sys.exit(1) + + ccm_scale = args.ccm_scale or (1 if adv_mode else guess_ccm_scale(matrices)) + + valid_matrices = [] + for m in matrices: + cct = m['cct'] + if not cct: + continue + if adv_mode: + vals = list(m['matrix_float']) + rg = m['r_per_g'] + bg = m['b_per_g'] + else: + vals = [v / ccm_scale for v in m['matrix_raw']] + rg = m['r_per_g_raw'] / 256.0 + bg = m['b_per_g_raw'] / 256.0 + row_sums = [sum(vals[r * 3:(r + 1) * 3]) for r in range(3)] + if max(abs(s - 1.0) for s in row_sums) > 0.05: + # Row sums deviating from 1.0 indicate a bad entry. + # For id=18: the scale factor is wrong (e.g. sums near 2.0 means + # ccm_scale is half the true value); use --ccm-scale to override. + # For id=25: floats are stored directly; deviation means the layout + # does not match ia_cmc_types.h or the entry is corrupt. + print(f" WARNING: CCT={cct}K row sums {[round(s, 4) for s in row_sums]} - skipping") + continue + print(f" CCT={cct}K R/G={rg:.4f} B/G={bg:.4f}") + valid_matrices.append((cct, vals, rg, bg)) + + if not valid_matrices: + print("ERROR: no valid colour matrices extracted") + sys.exit(1) + + min_rg = min(m[2] for m in valid_matrices) + min_bg = min(m[3] for m in valid_matrices) + max_gain_r = round((1.0 / min_rg) * 1.1, 2) if min_rg > 0 else 2.5 + max_gain_b = round((1.0 / min_bg) * 1.1, 2) if min_bg > 0 else 3.2 + print(f"\nSuggested AWB maxGainR={max_gain_r}, maxGainB={max_gain_b} " + f"(from min R/G={min_rg:.4f}, min B/G={min_bg:.4f})") + + sorted_matrices = sorted(valid_matrices) + + colour_gains = [ + {'ct': cct, 'gains': _FlowList([round(1.0 / rg, 4), round(1.0 / bg, 4)])} + for cct, vals, rg, bg in sorted_matrices + ] + + ccms = [ + {'ct': cct, 'ccm': _FlowList([round(v, 4) for v in vals])} + for cct, vals, rg, bg in sorted_matrices + ] + + aiqb_name = os.path.basename(args.aiqb) + doc = { + 'version': 1, + 'algorithms': [ + {'Awb': { + 'algorithm': 'grey', + 'maxGainR': max_gain_r, + 'maxGainB': max_gain_b, + 'speed': 0.25, + 'colourGains': colour_gains, + }}, + {'Ccm': {'ccms': ccms}}, + {'Adjust': {'gamma': 2.2, 'contrast': 1.0, 'saturation': 1.0}}, + {'Agc': {}}, + ], + } + + with open(output_path, 'w') as f: + f.write('# SPDX-License-Identifier: CC0-1.0\n') + f.write(f'# Calibrated from {aiqb_name}\n') + yaml.dump(doc, f, Dumper=_Dumper, default_flow_style=False, + allow_unicode=True, sort_keys=False, version=(1, 1), + explicit_start=True, explicit_end=True) + + print(f"\nWrote {output_path}") + print("NOTE: Add a BlackLevel entry to the YAML with the sensor's black level.") + + +if __name__ == '__main__': + main()