libcamera v0.7.2+1-2f862c3e-dirty (2026-10-05T14:46:06UTC)-nvm
Supporting cameras in Linux since 2019
Loading...
Searching...
No Matches
quad_bayer.h
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2/*
3 * Copyright (C) 2026 Frederic Laing
4 */
5
6#pragma once
7
8#include <algorithm>
9#include <array>
10#include <string_view>
11
12#include <libcamera/geometry.h>
13
15#include "libcamera/internal/sensor_cfa_layout.h"
16
17namespace libcamera {
18
19inline bool softwareIspNeedsCellCollapse(std::string_view model)
20{
21 return sensorCfaLayout(model).softwareIspNeedsCellCollapse();
22}
23
24inline Size quadBayerLogicalSize(const Size &physicalSize)
25{
26 return { physicalSize.width / 2, physicalSize.height / 2 };
27}
28
29inline bool isQuadBayerInputSizeSupported(const Size &size)
30{
31 return size.width >= 4 && size.height >= 4 &&
32 size.width % 4 == 0 && size.height % 4 == 0;
33}
34
35inline Rectangle softwareIspViewport(const Size &physicalSize,
36 const Size &outputSize,
37 bool quadBayer)
38{
39 const Size &viewportSize = quadBayer ? outputSize : physicalSize;
40 return { 0, 0, viewportSize.width, viewportSize.height };
41}
42
43inline Rectangle quadBayerStatsWindow(const Size &physicalSize,
44 const Size &logicalOutputSize)
45{
46 Size statsSize = physicalSize;
47 if (static_cast<uint64_t>(physicalSize.width) * logicalOutputSize.height >
48 static_cast<uint64_t>(physicalSize.height) * logicalOutputSize.width) {
49 statsSize.width = static_cast<uint64_t>(physicalSize.height) *
50 logicalOutputSize.width / logicalOutputSize.height;
51 statsSize.width &= ~3U;
52 } else {
53 statsSize.height = static_cast<uint64_t>(physicalSize.width) *
54 logicalOutputSize.height / logicalOutputSize.width;
55 statsSize.height &= ~3U;
56 }
57 return {
58 static_cast<int>(((physicalSize.width - statsSize.width) / 2) & ~3U),
59 static_cast<int>(((physicalSize.height - statsSize.height) / 2) & ~3U),
60 statsSize.width,
61 statsSize.height,
62 };
63}
64
65inline std::array<float, 8> softwareIspTextureCoordinates(const Size &physicalSize,
66 const Rectangle &window,
67 bool quadBayer)
68{
69 if (!quadBayer) {
70 return {
71 0.0f,
72 0.0f,
73 0.0f,
74 1.0f,
75 1.0f,
76 1.0f,
77 1.0f,
78 0.0f,
79 };
80 }
81
82 const float left = static_cast<float>(window.x) / physicalSize.width;
83 const float top = static_cast<float>(window.y) / physicalSize.height;
84 const float right = static_cast<float>(window.x + window.width) / physicalSize.width;
85 const float bottom = static_cast<float>(window.y + window.height) / physicalSize.height;
86 return {
87 left,
88 top,
89 left,
90 bottom,
91 right,
92 bottom,
93 right,
94 top,
95 };
96}
97
98inline Point quadBayerCellOrigin(const Size &physicalSize, const Point &pixel)
99{
100 return {
101 std::clamp(pixel.x & ~1, 0, static_cast<int>(physicalSize.width) - 2),
102 std::clamp(pixel.y & ~1, 0, static_cast<int>(physicalSize.height) - 2),
103 };
104}
105
106inline Point quadBayerOrderShifts(BayerFormat::Order order)
107{
108 switch (order) {
110 return { 0, 0 };
112 return { 2, 0 };
114 return { 0, 2 };
116 return { 2, 2 };
117 default:
118 return { -1, -1 };
119 }
120}
121
122inline bool isQuadBayerInputFormatSupported(PixelFormat inputFormat)
123{
124 const BayerFormat bayerFormat = BayerFormat::fromPixelFormat(inputFormat);
125 return bayerFormat.bitDepth == 10 &&
126 bayerFormat.packing == BayerFormat::Packing::CSI2 &&
127 quadBayerOrderShifts(bayerFormat.order).x >= 0;
128}
129
130template<typename Sample>
131inline auto normalizeQuadBayerTile(Sample sample, BayerFormat::Order order)
132{
133 using Value = decltype(sample(0, 0));
134 const Point redShift = quadBayerOrderShifts(order);
135 const Point red(redShift.x / 2, redShift.y / 2);
136 const Point blue(1 - red.x, 1 - red.y);
137 const Value green0 = sample(1 - red.x, red.y);
138 const Value green1 = sample(red.x, 1 - red.y);
139 return std::array<Value, 3>{
140 sample(red.x, red.y),
141 static_cast<Value>((green0 + green1) / 2),
142 sample(blue.x, blue.y),
143 };
144}
145
146template<typename Sample>
147inline auto averageQuadBayerCell(Sample sample, unsigned int x, unsigned int y)
148{
149 const unsigned int physicalX = x * 2;
150 const unsigned int physicalY = y * 2;
151 return (sample(physicalX, physicalY) +
152 sample(physicalX + 1, physicalY) +
153 sample(physicalX, physicalY + 1) +
154 sample(physicalX + 1, physicalY + 1) + 2) /
155 4;
156}
157
158} /* namespace libcamera */
Class to represent Bayer formats and manipulate them.
Class to represent a raw image Bayer format.
Definition bayer_format.h:23
@ CSI2
Format uses MIPI CSI-2 style packing.
Definition bayer_format.h:35
Order
The order of the colour channels in the Bayer pattern.
Definition bayer_format.h:25
@ BGGR
B then G on the first row, G then R on the second row.
Definition bayer_format.h:26
@ GRBG
G then R on the first row, B then G on the second row.
Definition bayer_format.h:28
@ GBRG
G then B on the first row, R then G on the second row.
Definition bayer_format.h:27
@ RGGB
R then G on the first row, G then B on the second row.
Definition bayer_format.h:29
static BayerFormat fromPixelFormat(PixelFormat format)
Convert a PixelFormat into the corresponding BayerFormat.
Definition bayer_format.cpp:388
libcamera image pixel format
Definition pixel_format.h:17
Describe a point in two-dimensional space.
Definition geometry.h:19
Describe a rectangle's position and dimensions.
Definition geometry.h:247
Describe a two-dimensional size.
Definition geometry.h:51
unsigned int width
The Size width.
Definition geometry.h:63
Data structures related to geometric objects.
Top-level libcamera namespace.
Definition backtrace.h:17