95 lines
3.2 KiB
C++
95 lines
3.2 KiB
C++
#include "fgc/RawImage.h"
|
|
|
|
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::Unknown: break;
|
|
}
|
|
return "Unknown";
|
|
}
|
|
|
|
PixelLayout layoutFromName(const std::string& name) {
|
|
for (PixelLayout l : {PixelLayout::Mono8, PixelLayout::RGB8, PixelLayout::BayerRG8,
|
|
PixelLayout::BayerRG12p})
|
|
if (name == layoutName(l)) return l;
|
|
return PixelLayout::Unknown;
|
|
}
|
|
|
|
bool layoutIsBayer(PixelLayout layout) {
|
|
return layout == PixelLayout::BayerRG8 || layout == PixelLayout::BayerRG12p;
|
|
}
|
|
|
|
int layoutBits(PixelLayout layout) {
|
|
switch (layout) {
|
|
case PixelLayout::Mono8:
|
|
case PixelLayout::RGB8:
|
|
case PixelLayout::BayerRG8: return 8;
|
|
case PixelLayout::BayerRG12p: return 12;
|
|
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: return (n * 3 + 1) / 2;
|
|
case PixelLayout::Unknown: break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
namespace {
|
|
|
|
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));
|
|
}
|
|
|
|
} // 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));
|
|
}
|
|
|
|
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 : 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
|