#pragma once #include #include #include namespace fgc { // How a camera frame's bytes are laid out. The camera profile decides which one // arrives (PixelFormat in the XML); the program accepts these and refuses others. // // Mono8 one byte per pixel, grey // RGB8 three bytes per pixel, R G B - de-Bayered on the camera // BayerRG8 one byte per pixel, the raw sensor mosaic: // R G R G ... // G B G B ... // BayerRG12p the same mosaic at 12 bits, packed: two pixels in three bytes // (GenICam "12p": p0 = b0 | (b1 & 0x0F) << 8, // p1 = b1 >> 4 | b2 << 4) // BayerRG12Packed // the same, packed the GigE Vision 1.x way that older GigE // cameras use (the Manta G-1236C on rietschen): the first byte // holds p0's HIGH bits, not its low ones // p0 = b0 << 4 | (b1 & 0x0F), // p1 = b2 << 4 | b1 >> 4 // Same size as BayerRG12p; read as 12p it would scramble every // other pixel. // Mono16 two bytes per pixel, grey, host byte order - the thermal // camera's counts (TarisCameraSource.h), all 16 bits used // // OpenCV names Bayer patterns by the second row, so the camera's BayerRG is // OpenCV's COLOR_BayerBG2* (measured 2026-09-30 against the camera's own RGB8). enum class PixelLayout { Unknown, Mono8, RGB8, BayerRG8, BayerRG12p, Mono16, BayerRG12Packed }; // The GenICam name ("BayerRG12p", "BayerRG12Packed"), or "Unknown". const char* layoutName(PixelLayout layout); // From a GenICam name; Unknown for anything the program does not handle. PixelLayout layoutFromName(const std::string& name); // True for the raw mosaic layouts, which need de-Bayering before saving as colour. bool layoutIsBayer(PixelLayout layout); // Bits per value as delivered: 8, 12 for the 12-bit mosaics, 16 for Mono16. 0 // for Unknown. int layoutBits(PixelLayout layout); // Bytes one frame of width x height takes in this layout (0 for Unknown). size_t layoutFrameBytes(PixelLayout layout, uint32_t width, uint32_t height); // Unpack `pixels` BayerRG12p values from `in` into one 16-bit word each // (0..4095). `in` holds ceil(pixels * 3 / 2) bytes; an odd last pixel uses the // low half of its pair, as GenICam specifies. void unpack12p(const uint8_t* in, uint16_t* out, size_t pixels); // The same for BayerRG12Packed (GigE Vision 1.x packing, see PixelLayout). void unpack12Packed(const uint8_t* in, uint16_t* out, size_t pixels); // Either of the two, by layout: the 12-bit mosaic unpacked to 16-bit words. void unpack12(PixelLayout layout, const uint8_t* in, uint16_t* out, size_t pixels); // Brightness of a frame from a sparse sample of its pixels: every `stride`-th // pixel, so all colour sites of a mosaic are visited. Cheap enough to run on // every frame the camera delivers (a few thousand samples). // mean on a 0..255 scale whatever the bit depth (12-bit values / 16, // 16-bit values / 256) // clipped share of samples at or near white (>= 250 on that scale) struct BrightnessSample { double mean = -1.0; double clipped = -1.0; size_t samples = 0; bool valid() const { return samples > 0; } }; BrightnessSample sampleBrightness(const uint8_t* frame, size_t bytes, PixelLayout layout, uint32_t width, uint32_t height, size_t stride = 997); } // namespace fgc