fwt_software/src/core/RawImage.cpp

134 lines
4.9 KiB
C++

#include "fgc/RawImage.h"
#include <cstring>
namespace fgc {
const char* layoutName(PixelLayout layout) {
switch (layout) {
case PixelLayout::Mono8: return "Mono8";
case PixelLayout::RGB8: return "RGB8";
case PixelLayout::BayerRG8: return "BayerRG8";
case PixelLayout::BayerRG12p: return "BayerRG12p";
case PixelLayout::BayerRG12Packed: return "BayerRG12Packed";
case PixelLayout::Mono16: return "Mono16";
case PixelLayout::Unknown: break;
}
return "Unknown";
}
PixelLayout layoutFromName(const std::string& name) {
for (PixelLayout l : {PixelLayout::Mono8, PixelLayout::RGB8, PixelLayout::BayerRG8,
PixelLayout::BayerRG12p, PixelLayout::BayerRG12Packed,
PixelLayout::Mono16})
if (name == layoutName(l)) return l;
return PixelLayout::Unknown;
}
bool layoutIsBayer(PixelLayout layout) {
return layout == PixelLayout::BayerRG8 || layout == PixelLayout::BayerRG12p ||
layout == PixelLayout::BayerRG12Packed;
}
int layoutBits(PixelLayout layout) {
switch (layout) {
case PixelLayout::Mono8:
case PixelLayout::RGB8:
case PixelLayout::BayerRG8: return 8;
case PixelLayout::BayerRG12p:
case PixelLayout::BayerRG12Packed: return 12;
case PixelLayout::Mono16: return 16;
case PixelLayout::Unknown: break;
}
return 0;
}
size_t layoutFrameBytes(PixelLayout layout, uint32_t width, uint32_t height) {
const size_t n = static_cast<size_t>(width) * height;
switch (layout) {
case PixelLayout::Mono8:
case PixelLayout::BayerRG8: return n;
case PixelLayout::RGB8: return n * 3;
case PixelLayout::BayerRG12p:
case PixelLayout::BayerRG12Packed: return (n * 3 + 1) / 2;
case PixelLayout::Mono16: return n * 2;
case PixelLayout::Unknown: break;
}
return 0;
}
namespace {
inline uint16_t px16(const uint8_t* in, size_t i) {
uint16_t v;
std::memcpy(&v, in + i * 2, sizeof v); // host order, possibly unaligned
return v;
}
inline uint16_t px12p(const uint8_t* in, size_t i) {
const uint8_t* p = in + (i >> 1) * 3;
return (i & 1) == 0 ? static_cast<uint16_t>(p[0] | ((p[1] & 0x0F) << 8))
: static_cast<uint16_t>((p[1] >> 4) | (p[2] << 4));
}
inline uint16_t px12Packed(const uint8_t* in, size_t i) {
const uint8_t* p = in + (i >> 1) * 3;
return (i & 1) == 0 ? static_cast<uint16_t>((p[0] << 4) | (p[1] & 0x0F))
: static_cast<uint16_t>((p[2] << 4) | (p[1] >> 4));
}
} // namespace
void unpack12p(const uint8_t* in, uint16_t* out, size_t pixels) {
const size_t pairs = pixels / 2;
for (size_t k = 0; k < pairs; ++k, in += 3, out += 2) {
out[0] = static_cast<uint16_t>(in[0] | ((in[1] & 0x0F) << 8));
out[1] = static_cast<uint16_t>((in[1] >> 4) | (in[2] << 4));
}
if (pixels & 1) out[0] = static_cast<uint16_t>(in[0] | ((in[1] & 0x0F) << 8));
}
void unpack12Packed(const uint8_t* in, uint16_t* out, size_t pixels) {
const size_t pairs = pixels / 2;
for (size_t k = 0; k < pairs; ++k, in += 3, out += 2) {
out[0] = static_cast<uint16_t>((in[0] << 4) | (in[1] & 0x0F));
out[1] = static_cast<uint16_t>((in[2] << 4) | (in[1] >> 4));
}
if (pixels & 1) out[0] = static_cast<uint16_t>((in[0] << 4) | (in[1] & 0x0F));
}
void unpack12(PixelLayout layout, const uint8_t* in, uint16_t* out, size_t pixels) {
if (layout == PixelLayout::BayerRG12Packed) unpack12Packed(in, out, pixels);
else unpack12p(in, out, pixels);
}
BrightnessSample sampleBrightness(const uint8_t* frame, size_t bytes, PixelLayout layout,
uint32_t width, uint32_t height, size_t stride) {
BrightnessSample s;
const size_t pixels = static_cast<size_t>(width) * height;
if (!frame || layout == PixelLayout::Unknown || stride == 0 ||
bytes < layoutFrameBytes(layout, width, height))
return s;
// Values per pixel (RGB8 has three); sampling every stride-th value keeps
// the colour channels mixed for RGB8 just as for a mosaic.
const size_t values = layout == PixelLayout::RGB8 ? pixels * 3 : pixels;
double sum = 0;
size_t hi = 0;
for (size_t i = 0; i < values; i += stride) {
double v = layout == PixelLayout::BayerRG12p ? px12p(frame, i) / 16.0
: layout == PixelLayout::BayerRG12Packed ? px12Packed(frame, i) / 16.0
: layout == PixelLayout::Mono16 ? px16(frame, i) / 256.0
: frame[i];
sum += v;
hi += v >= 250.0;
++s.samples;
}
if (s.samples) {
s.mean = sum / s.samples;
s.clipped = static_cast<double>(hi) / s.samples;
}
return s;
}
} // namespace fgc