RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
RawImageDataFloat.cpp
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2009-2014 Klaus Post
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#include "common/RawImage.h"
22#include "adt/Array1DRef.h"
23#include "adt/Array2DRef.h"
24#include "adt/Casts.h"
26#include "adt/Point.h"
27#include "common/Common.h"
29#include "metadata/BlackArea.h"
30#include <algorithm>
31#include <array>
32#include <cassert>
33#include <cstddef>
34#include <cstdint>
35#include <cstdlib>
36#include <vector>
37
38using std::max;
39using std::min;
40
41namespace rawspeed {
42
47
50
53
54 std::array<float, 4> accPixels;
55 accPixels.fill(0);
56 int totalpixels = 0;
57
58 for (auto area : blackAreas) {
59 /* Make sure area sizes are multiple of two,
60 so we have the same amount of pixels for each CFA group */
61 area.size = area.size - (area.size & 1);
62
63 /* Process horizontal area */
64 if (!area.isVertical) {
65 if (static_cast<int>(area.offset) + static_cast<int>(area.size) >
67 ThrowRDE("Offset + size is larger than height of image");
68 for (uint32_t y = area.offset; y < area.offset + area.size; y++) {
69 for (int x = mOffset.x; x < dim.x + mOffset.x; x++) {
70 accPixels[((y & 1) << 1) | (x & 1)] += img(y, x);
71 }
72 }
73 totalpixels += area.size * dim.x;
74 }
75
76 /* Process vertical area */
77 if (area.isVertical) {
78 if (static_cast<int>(area.offset) + static_cast<int>(area.size) >
80 ThrowRDE("Offset + size is larger than width of image");
81 for (int y = mOffset.y; y < dim.y + mOffset.y; y++) {
82 for (uint32_t x = area.offset; x < area.size + area.offset; x++) {
83 accPixels[((y & 1) << 1) | (x & 1)] += img(y, x);
84 }
85 }
86 totalpixels += area.size * dim.y;
87 }
88 }
89
91 auto blackLevelSeparate1D = *blackLevelSeparate->getAsArray1DRef();
92
93 if (!totalpixels) {
94 for (int& i : blackLevelSeparate1D)
95 i = blackLevel;
96 return;
97 }
98
99 /* Calculate median value of black areas for each component */
100 /* Adjust the number of total pixels so it is the same as the median of each
101 * histogram */
102 totalpixels /= 4;
103
104 for (int i = 0; i < 4; i++) {
105 blackLevelSeparate1D(i) = static_cast<int>(
106 65535.0F * accPixels[i] / implicit_cast<float>(totalpixels));
107 }
108
109 /* If this is not a CFA image, we do not use separate blacklevels, use average
110 */
111 if (!isCFA) {
112 int total = 0;
113 for (int i : blackLevelSeparate1D)
114 total += i;
115 for (int& i : blackLevelSeparate1D)
116 i = (total + 2) >> 2;
117 }
118}
119
122
123 const int skipBorder = 150;
124 int gw = (dim.x - skipBorder) * cpp;
125 // NOTE: lack of whitePoint means that it is pre-normalized.
126 if (blackAreas.empty() && !blackLevelSeparate && blackLevel < 0) { // Estimate
127 float b = 100000000;
128 float m = -10000000;
129 for (int row = skipBorder * cpp; row < (dim.y - skipBorder); row++) {
130 for (int col = skipBorder; col < gw; col++) {
131 const float pixel = img(row, col);
132 b = min(pixel, b);
133 m = max(pixel, m);
134 }
135 }
136 if (blackLevel < 0)
137 blackLevel = static_cast<int>(b);
138 writeLog(DEBUG_PRIO::INFO, "Estimated black:%d", blackLevel);
139 }
140
141 /* If filter has not set separate blacklevel, compute or fetch it */
144
146}
147
148void RawImageDataFloat::scaleValues(int start_y, int end_y) {
150 int gw = dim.x * cpp;
151 std::array<float, 4> mul;
152 std::array<float, 4> sub;
153 assert(blackLevelSeparate->width() == 2 && blackLevelSeparate->height() == 2);
154 auto blackLevelSeparate1D = *blackLevelSeparate->getAsArray1DRef();
155 for (int i = 0; i < 4; i++) {
156 int v = i;
157 if ((mOffset.x & 1) != 0)
158 v ^= 1;
159 if ((mOffset.y & 1) != 0)
160 v ^= 2;
161 mul[i] =
162 65535.0F / static_cast<float>(*whitePoint - blackLevelSeparate1D(v));
163 sub[i] = static_cast<float>(blackLevelSeparate1D(v));
164 }
165 for (int y = start_y; y < end_y; y++) {
166 for (int x = 0; x < gw; x++)
167 img(y, x) = (img(y, x) - sub[(2 * (y & 1)) + (x & 1)]) *
168 mul[(2 * (y & 1)) + (x & 1)];
169 }
170}
171
172/* This performs a 4 way interpolated pixel */
173/* The value is interpolated from the 4 closest valid pixels in */
174/* the horizontal and vertical direction. Pixels found further away */
175/* are weighed less */
176
179
180 std::array<float, 4> values;
181 values.fill(-1);
182 std::array<float, 4> dist = {{}};
183 std::array<float, 4> weight;
184
185 const auto bad =
187 // We can have cfa or no-cfa for RawImageDataFloat
188 int step = isCFA ? 2 : 1;
189
190 // Find pixel to the left
191 int x_find = static_cast<int>(x) - step;
192 int curr = 0;
193 while (x_find >= 0 && values[curr] < 0) {
194 if (0 == ((bad(y, x_find >> 3) >> (x_find & 7)) & 1)) {
195 values[curr] = img(y, x_find + component);
196 dist[curr] = static_cast<float>(static_cast<int>(x) - x_find);
197 }
198 x_find -= step;
199 }
200 // Find pixel to the right
201 x_find = static_cast<int>(x) + step;
202 curr = 1;
203 while (x_find < uncropped_dim.x && values[curr] < 0) {
204 if (0 == ((bad(y, x_find >> 3) >> (x_find & 7)) & 1)) {
205 values[curr] = img(y, x_find + component);
206 dist[curr] = static_cast<float>(x_find - static_cast<int>(x));
207 }
208 x_find += step;
209 }
210
211 // Find pixel upwards
212 int y_find = static_cast<int>(y) - step;
213 curr = 2;
214 while (y_find >= 0 && values[curr] < 0) {
215 if (0 == ((bad(y_find, x >> 3) >> (x & 7)) & 1)) {
216 values[curr] = img(y_find, x + component);
217 dist[curr] = static_cast<float>(static_cast<int>(y) - y_find);
218 }
219 y_find -= step;
220 }
221 // Find pixel downwards
222 y_find = static_cast<int>(y) + step;
223 curr = 3;
224 while (y_find < uncropped_dim.y && values[curr] < 0) {
225 if (0 == ((bad(y_find, x >> 3) >> (x & 7)) & 1)) {
226 values[curr] = img(y_find, x + component);
227 dist[curr] = static_cast<float>(y_find - static_cast<int>(y));
228 }
229 y_find += step;
230 }
231
232 float total_div = 0.000001F;
233
234 // Find x weights
235 if (float total_dist_x = dist[0] + dist[1]; std::abs(total_dist_x) > 0) {
236 weight[0] = dist[0] > 0.0F ? (total_dist_x - dist[0]) / total_dist_x : 0;
237 weight[1] = 1.0F - weight[0];
238 total_div += 1;
239 }
240
241 // Find y weights
242 if (float total_dist_y = dist[2] + dist[3]; std::abs(total_dist_y) > 0) {
243 weight[2] = dist[2] > 0.0F ? (total_dist_y - dist[2]) / total_dist_y : 0;
244 weight[3] = 1.0F - weight[2];
245 total_div += 1;
246 }
247
248 float total_pixel = 0;
249 for (int i = 0; i < 4; i++)
250 if (values[i] >= 0)
251 total_pixel += values[i] * weight[i];
252
253 total_pixel /= total_div;
254 img(y, x + component) = total_pixel;
255
256 /* Process other pixels - could be done inline, since we have the weights */
257 if (cpp > 1 && component == 0)
258 for (int i = 1; i < cpp; i++)
259 fixBadPixel(x, y, i);
260}
261
262void RawImageDataFloat::doLookup(int start_y, int end_y) {
263 ThrowRDE("Float point lookup tables not implemented");
264}
265
267 uint32_t* random) {
268 auto* dest = reinterpret_cast<float*>(dst);
269 if (table == nullptr) {
270 *dest = static_cast<float>(value) * (1.0F / 65535);
271 return;
272 }
273
274 ThrowRDE("Float point lookup tables not implemented");
275}
276
277} // namespace rawspeed
#define ThrowRDE(...)
assert(dim.area() >=area)
dim y
Definition Common.cpp:51
dim x
Definition Common.cpp:50
void doLookup(int start_y, int end_y) override
void fixBadPixel(uint32_t x, uint32_t y, int component=0) override
void setWithLookUp(uint16_t value, std::byte *dst, uint32_t *random) override
void scaleValues(int start_y, int end_y) override
std::array< int, 4 > blackLevelSeparateStorage
Definition RawImage.h:164
Optional< Array2DRef< int > > blackLevelSeparate
Definition RawImage.h:165
CroppedArray2DRef< float > getF32DataAsCroppedArray2DRef() noexcept
Definition RawImage.h:324
Optional< int > whitePoint
Definition RawImage.h:172
Array2DRef< float > getF32DataAsUncroppedArray2DRef() noexcept
Definition RawImage.h:310
std::vector< BlackArea > blackAreas
Definition RawImage.h:174
std::vector< uint8_t, AlignedAllocator< uint8_t, 16 > > mBadPixelMap
Definition RawImage.h:180
void startWorker(RawImageWorker::RawImageWorkerTask task, bool cropped)
Definition RawImage.cpp:271
std::unique_ptr< TableLookUp > table
Definition RawImage.h:206
uint32_t mBadPixelMapPitch
Definition RawImage.h:181
RawImageType dataType
Definition RawImage.h:190
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32
void writeLog(DEBUG_PRIO priority, const char *format,...)
Definition Common.cpp:37
Array2DRef(Array1DRef< T > data, int width, int height, int pitch) -> Array2DRef< T >