RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
BayerPhase.h
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2022 Roman Lebedev
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19*/
20
21#pragma once
22
23#include "adt/Array2DRef.h"
24#include "adt/Optional.h"
25#include "adt/Point.h"
27#include <algorithm>
28#include <array>
29#include <cassert>
30#include <cmath>
31#include <cstdint>
32#include <cstdlib>
33#include <iterator>
34#include <utility>
35
36namespace rawspeed {
37
38// Bayer CFA 2x2 pattern has only 3 distinct colors - red, green (x2) and blue,
39// and greens are always on diagonal, thus the actual pattern always looks like:
40// ..........
41// ..RGRGRG..
42// ..GBGBGB..
43// ..RGRGRG..
44// ..GBGBGB..
45// ..RGRGRG..
46// ..GBGBGB..
47// ..........
48// and there are only 4 flavours of the 2x2 pattern, since position is mod-2:
49enum class BayerPhase : uint8_t {
50 // The top-left pixel of the image is red pixel.
51 RGGB = 0b00, // 0
52 // The top-left pixel of the image is green pixel in a green/red row.
53 GRBG = 0b01, // 1
54 // The top-left pixel of the image is green pixel in a green/blue row.
55 GBRG = 0b10, // 2
56 // he top-left pixel of the image is blue pixel.
57 BGGR = 0b11, // 3
58
59 // COLUMN_SHIFT = 0b01,
60 // ROW_SHIFT = 0b10
61};
62
63// R G0 R G0
64// G1 B G1 B
65// R G0 R G0
66// G1 B G1 B
68 auto getCanonicalPosition = [](BayerPhase p) -> iPoint2D {
69 auto i = static_cast<unsigned>(p);
70 return {(i & 0b01) != 0, (i & 0b10) != 0};
71 };
72
73 iPoint2D off = getCanonicalPosition(tgt) - getCanonicalPosition(src);
74 return {std::abs(off.x), std::abs(off.y)};
75}
76
77// NOTE: phase shift is direction-independent (phase order does not matter.)
78template <typename T>
79inline std::array<T, 4> applyPhaseShift(std::array<T, 4> srcData,
80 BayerPhase srcPhase,
81 BayerPhase tgtPhase) {
82 const iPoint2D coordOffset = getTranslationalOffset(srcPhase, tgtPhase);
83 assert(coordOffset >= iPoint2D(0, 0) && "Offset is non-negative.");
84 const Array2DRef<const T> src(srcData.data(), 2, 2);
85
86 std::array<T, 4> tgtData;
87 const Array2DRef<T> tgt(tgtData.data(), 2, 2);
88 for (int row = 0; row < tgt.height(); ++row) {
89 for (int col = 0; col < tgt.width(); ++col) {
90 tgt(row, col) = src((coordOffset.y + row) % 2, (coordOffset.x + col) % 2);
91 }
92 }
93
94 return tgtData;
95}
96
97inline std::array<CFAColor, 4> getAsCFAColors(BayerPhase p) {
98 const BayerPhase basePhase = BayerPhase::RGGB;
99 using enum CFAColor;
100 const std::array<CFAColor, 4> basePat = {RED, GREEN, GREEN, BLUE};
101 return applyPhaseShift(basePat, basePhase, /*tgtPhase=*/p);
102}
103
104// Remap data between these two Bayer phases,
105// while preserving relative order of 'green' values.
106template <typename T>
107inline std::array<T, 4> applyStablePhaseShift(std::array<T, 4> srcData,
108 BayerPhase srcPhase,
109 BayerPhase tgtPhase) {
110 std::array<T, 4> tgtData = applyPhaseShift(srcData, srcPhase, tgtPhase);
111
112 if (!/*rowsSwapped=*/getTranslationalOffset(srcPhase, tgtPhase).y)
113 return tgtData;
114
115 auto is_green = [](const CFAColor& c) { return c == CFAColor::GREEN; };
116
117 const std::array<CFAColor, 4> tgtColors = getAsCFAColors(tgtPhase);
118 auto green0Idx =
119 std::distance(tgtColors.begin(),
120 std::find_if(tgtColors.begin(), tgtColors.end(), is_green));
121 auto green1Idx = std::distance(std::find_if(tgtColors.rbegin(),
122 tgtColors.rend(), is_green),
123 tgtColors.rend()) -
124 1;
125
126 std::swap(tgtData[green0Idx], tgtData[green1Idx]);
127
128 return tgtData;
129}
130
132 if (CFA.getSize() != iPoint2D(2, 2))
133 return {};
134
135 std::array<CFAColor, 4> patData;
136 const Array2DRef<CFAColor> pat(patData.data(), 2, 2);
137 for (int row = 0; row < pat.height(); ++row) {
138 for (int col = 0; col < pat.width(); ++col) {
139 pat(row, col) = CFA.getColorAt(col, row);
140 }
141 }
142
143 for (auto i = static_cast<int>(BayerPhase::RGGB);
144 i <= static_cast<int>(BayerPhase::BGGR); ++i) {
145 if (auto p = static_cast<BayerPhase>(i); getAsCFAColors(p) == patData)
146 return p;
147 }
148
149 return {};
150}
151
152} // namespace rawspeed
assert(dim.area() >=area)
dim y
Definition Common.cpp:51
int RAWSPEED_READONLY height() const
int RAWSPEED_READONLY width() const
CFAColor getColorAt(int x, int y) const
value_type x
Definition Point.h:102
value_type y
Definition Point.h:103
std::array< CFAColor, 4 > getAsCFAColors(BayerPhase p)
Definition BayerPhase.h:97
Optional< BayerPhase > getAsBayerPhase(const ColorFilterArray &CFA)
Definition BayerPhase.h:131
std::array< T, 4 > applyPhaseShift(std::array< T, 4 > srcData, BayerPhase srcPhase, BayerPhase tgtPhase)
Definition BayerPhase.h:79
iPoint2D getTranslationalOffset(BayerPhase src, BayerPhase tgt)
Definition BayerPhase.h:67
std::array< T, 4 > applyStablePhaseShift(std::array< T, 4 > srcData, BayerPhase srcPhase, BayerPhase tgtPhase)
Definition BayerPhase.h:107