Commit c5758155 authored by Éric Thiébaut's avatar Éric Thiébaut
Browse files

Change API for copy, convert, or pre-process pixels

parent cf4d097f
......@@ -65,9 +65,8 @@ include_HEADERS = \
tao-generic.h \
tao-locks.h \
tao-macros.h \
tao-misc.h \
tao-options.h \
tao-preprocessing.h \
tao-pixels.h \
tao-remote-mirrors.h \
tao-remote-cameras-private.h \
tao-remote-cameras.h \
......@@ -106,7 +105,6 @@ libtao_la_SOURCES = \
rwlocked-objects.c \
options.c \
pixels.c \
preprocessing.c \
semaphores.c \
shared-arrays.c \
shared-cameras.c \
......
......@@ -12,7 +12,7 @@
#ifndef PIXELS_C_
#define PIXELS_C_ 1
#include "tao-misc.h"
#include "tao-pixels.h"
#include "tao-errors.h"
#include "config.h"
......@@ -21,245 +21,362 @@
#include <math.h>
#include <stdbool.h>
// Optimizer and loop vectorization make the following macros efficient.
#define raw_(x,y) raw[(x) + (y)*stride]
#define arr_(x,y) arr[(x) + (y)*width]
#define dat_(x,y) dat[(x) + (y)*width]
#define wgt_(x,y) wgt[(x) + (y)*width]
#define a_(x,y) a[(x) + (y)*width]
#define b_(x,y) b[(x) + (y)*width]
#define q_(x,y) q[(x) + (y)*width]
#define r_(x,y) r[(x) + (y)*width]
static inline float max_flt(float a, float b) { return a >= b ? a : b; }
static inline double max_dbl(double a, double b) { return a >= b ? a : b; }
#define max_(a, b) \
_Generic((a) + (b), \
float: max_flt, \
double: max_dbl)((a), (b))
// FIXME: faster with uint32_t in some cases?
typedef uint16_t unpacked;
static inline unpacked unpack_p12_lo(
unpacked b0,
unpacked b1)
// Inline functions for unpacking 12-bit pixel values packed into 3 bytes.
//
// Argument `arr` is the base address of the row of pixels. Argument `i` is
// the index of the 1st pixel of the pair (`i` must be even). Functions
// `unpack12_1st` and `unpack12_2nd` respectively yield the value of the 1st
// and 2nd pixel of the pair (at respective indices `i` and `i+1` of the row).
static inline uint16_t unpack12_1st(const uint8_t* arr, long i)
{
return (b0 << 4) | (b1 & (unpacked)0x000F);
uint16_t b0 = arr[3*i];
uint16_t b1 = arr[3*i + 1];
return (b0 << 4) | (b1 & (uint16_t)0x000F);
}
static inline unpacked unpack_p12_hi(
unpacked b1,
unpacked b2)
static inline uint16_t unpack12_2nd(const uint8_t* arr, long i)
{
uint16_t b1 = arr[3*i + 1];
uint16_t b2 = arr[3*i + 2];
return (b2 << 4) | (b1 >> 4);
}
#ifdef PACKED_PIXELS
#error PACKED_PIXELS must not be defined
#endif
// Inline functions and generic macro for fast maximum.
static inline float fastmax_flt(float a, float b)
{
return (a >= b ? a : b);
}
static inline double fastmax_dbl(double a, double b)
{
return (a >= b ? a : b);
}
#define fastmax(a, b) \
_Generic((a) + (b), \
float: fastmax_flt, \
double: fastmax_dbl)(a, b)
// Inline functions and generic macro for affine correction.
static inline float correct_flt(float raw, float a, float b)
{
return (raw - b)*a;
}
static inline double correct_dbl(double raw, double a, double b)
{
return (raw - b)*a;
}
#define INP uint8_t
#define OUT uint8_t
#define CONVERT_FUNC tao_convert_u8_pixels_to_u8
#define correct(raw,a,b) \
_Generic((a) + (b), \
float: correct_flt, \
double: correct_dbl)(raw, a, b)
// Inline functions and generic macro for computation of weights.
static inline float weight_flt(float dat, float q, float r)
{
return q/fastmax(r, r + dat);
}
static inline double weight_dbl(double dat, double q, double r)
{
return q/fastmax(r, r + dat);
}
#define weight(dat,q,r) \
_Generic((dat) + (q) + (r), \
float: weight_flt, \
double: weight_dbl)(dat, q, r)
// Optimizer and loop vectorization make the following macros efficient.
#define raw(x,y) raw_[(x) + (y)*stride]
#define arr(x,y) arr_[(x) + (y)*width]
#define dat(x,y) dat_[(x) + (y)*width]
#define wgt(x,y) wgt_[(x) + (y)*width]
#define a(x,y) a_[(x) + (y)*width]
#define b(x,y) b_[(x) + (y)*width]
#define q(x,y) q_[(x) + (y)*width]
#define r(x,y) r_[(x) + (y)*width]
#define ctype_i8 int8_t
#define ctype_u8 uint8_t
#define ctype_i16 int16_t
#define ctype_u16 uint16_t
#define ctype_i32 int32_t
#define ctype_u32 uint32_t
#define ctype_i64 int64_t
#define ctype_u64 uint64_t
#define ctype_flt float
#define ctype_dbl double
#define ctype_p12 uint8_t
#define ctype(sfx) join2(ctype_,sfx)
#define typeid_i8 1
#define typeid_u8 2
#define typeid_i16 3
#define typeid_u16 4
#define typeid_i32 5
#define typeid_u32 6
#define typeid_i64 7
#define typeid_u64 8
#define typeid_flt 9
#define typeid_dbl 10
#define typeid_p12 11
#define typeid(sfx) join2(typeid_,sfx)
#define packed_i8 0
#define packed_u8 0
#define packed_i16 0
#define packed_u16 0
#define packed_i32 0
#define packed_u32 0
#define packed_i64 0
#define packed_u64 0
#define packed_flt 0
#define packed_dbl 0
#define packed_p12 12
#define packed(sfx) join2(packed_,sfx)
#define isfloat_i8 0
#define isfloat_u8 0
#define isfloat_i16 0
#define isfloat_u16 0
#define isfloat_i32 0
#define isfloat_u32 0
#define isfloat_i64 0
#define isfloat_u64 0
#define isfloat_flt 1
#define isfloat_dbl 1
#define isfloat_p12 0
#define isfloat(sfx) join2(isfloat_,sfx)
#define join2(a1,a2) a1##a2
#define xjoin2(a1,a2) join2(a1,a2)
#define join3(a1,a2,a3) a1##a2##a3
#define xjoin3(a1,a2,a3) join3(a1,a2,a3)
#define join4(a1,a2,a3,a4) a1##a2##a3##a4
#define xjoin4(a1,a2,a3,a4) join4(a1,a2,a3,a4)
#define src u8
#define dst u8
#include __FILE__
#define OUT uint16_t
#define CONVERT_FUNC tao_convert_u8_pixels_to_u16
#undef dst
#define dst u16
#include __FILE__
#define OUT uint32_t
#define CONVERT_FUNC tao_convert_u8_pixels_to_u32
#undef dst
#define dst u32
#include __FILE__
#define OUT float
#define CONVERT_FUNC tao_convert_u8_pixels_to_flt
#define PREPROCESS_FUNC tao_preprocess_u8_pixels_to_flt
#undef dst
#define dst flt
#include __FILE__
#define OUT double
#define CONVERT_FUNC tao_convert_u8_pixels_to_dbl
#define PREPROCESS_FUNC tao_preprocess_u8_pixels_to_dbl
#undef dst
#define dst dbl
#include __FILE__
#undef INP
#undef dst
#undef src
#define INP uint16_t
#define OUT uint16_t
#define CONVERT_FUNC tao_convert_u16_pixels_to_u16
#define src p12
#define dst u16
#include __FILE__
#define OUT uint32_t
#define CONVERT_FUNC tao_convert_u16_pixels_to_u32
#undef dst
#define dst u32
#include __FILE__
#define OUT float
#define CONVERT_FUNC tao_convert_u16_pixels_to_flt
#define PREPROCESS_FUNC tao_preprocess_u16_pixels_to_flt
#undef dst
#define dst flt
#include __FILE__
#define OUT double
#define CONVERT_FUNC tao_convert_u16_pixels_to_dbl
#define PREPROCESS_FUNC tao_preprocess_u16_pixels_to_dbl
#undef dst
#define dst dbl
#include __FILE__
#undef INP
#undef dst
#undef src
#define INP uint32_t
#define OUT uint32_t
#define CONVERT_FUNC tao_convert_u32_pixels_to_u32
#define src u16
#define dst u16
#include __FILE__
#define OUT float
#define CONVERT_FUNC tao_convert_u32_pixels_to_flt
#define PREPROCESS_FUNC tao_preprocess_u32_pixels_to_flt
#undef dst
#define dst u32
#include __FILE__
#define OUT double
#define CONVERT_FUNC tao_convert_u32_pixels_to_dbl
#define PREPROCESS_FUNC tao_preprocess_u32_pixels_to_dbl
#undef dst
#define dst flt
#include __FILE__
#undef INP
#define PACKED_PIXELS 12
#define INP uint8_t // buffer of bytes for packed pixels
#define OUT uint16_t
#define CONVERT_FUNC tao_convert_p12_pixels_to_u16
#undef dst
#define dst dbl
#include __FILE__
#define OUT uint32_t
#define CONVERT_FUNC tao_convert_p12_pixels_to_u32
#undef dst
#undef src
#define src u32
#define dst u32
#include __FILE__
#define OUT float
#define CONVERT_FUNC tao_convert_p12_pixels_to_flt
#define PREPROCESS_FUNC tao_preprocess_p12_pixels_to_flt
#undef dst
#define dst flt
#include __FILE__
#define OUT double
#define CONVERT_FUNC tao_convert_p12_pixels_to_dbl
#define PREPROCESS_FUNC tao_preprocess_p12_pixels_to_dbl
#undef dst
#define dst dbl
#include __FILE__
#undef INP
#undef PACKED_PIXELS
#undef dst
#undef src
#include __FILE__
#else // PIXELS_C_ defined.
#else // PIXELS_C_
#if typeid(src) == typeid(dst) && packed(src) == 0
#ifdef CONVERT_FUNC
tao_status CONVERT_FUNC(
OUT* restrict arr,
const INP* restrict raw,
long width,
long height,
long bytes_per_line)
// Copy pixel values.
void xjoin4(tao_pixels_copy_,src,_to_,dst)(
ctype(dst)* restrict dat_,
long width,
long height,
const ctype(src)* restrict raw_,
long stride)
{
if (arr == NULL || raw == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return TAO_ERROR;
}
if (width < 0 || height < 0 || bytes_per_line%sizeof(INP) != 0) {
tao_store_error(__func__, TAO_BAD_SIZE);
return TAO_ERROR;
}
#ifndef PACKED_PIXELS
long stride = bytes_per_line/sizeof(INP);
for (long y = 0; y < height; ++y) {
ctype(dst)* restrict dat = dat_ + y*width;
const ctype(src)* restrict raw = (const ctype(src)* restrict)(
((const uint8_t* restrict)raw_) + y*stride);
for (long x = 0; x < width; ++x) {
arr_(x,y) = (OUT)raw_(x,y);
dat[x] = raw[x];
}
}
#elif PACKED_PIXELS == 12
}
#endif
#if typeid(src) != typeid(dst)
// Convert pixel values.
void xjoin4(tao_pixels_convert_,src,_to_,dst)(
ctype(dst)* restrict dat_,
long width,
long height,
const ctype(src)* restrict raw_,
long stride)
{
#if packed(src) != 0
# if packed(src) == 12
long xm = width - 1;
bool isodd = ((width&1) != 0);
bool isodd = (width & 1) != 0;
# else
# error Unsupported value for `packed`.
# endif
#endif
for (long y = 0; y < height; ++y) {
const uint8_t* restrict ptr = raw + bytes_per_line*y;
ctype(dst)* restrict dat = dat_ + y*width;
const ctype(src)* restrict raw = (const ctype(src)* restrict)(
((const uint8_t* restrict)raw_) + y*stride);
#if packed(src) == 0
for (long x = 0; x < width; ++x) {
dat[x] = raw[x];
}
#elif packed(src) == 12
for (long x = 0; x < xm; x += 2) {
unpacked b0 = ptr[0];
unpacked b1 = ptr[1];
unpacked b2 = ptr[2];
ptr += 3;
arr_(x,y) = unpack_p12_lo(b0, b1);
arr_(x+1,y) = unpack_p12_hi(b1, b2);
dat[x ] = unpack12_1st(raw, x);
dat[x+1] = unpack12_2nd(raw, x);
}
if (isodd) {
unpacked b0 = ptr[0];
unpacked b1 = ptr[1];
arr_(xm,y) = unpack_p12_lo(b0, b1);
dat[xm] = unpack12_1st(raw, xm);
}
#endif
}
#else
# error unexpected PACKED_PIXELS value
#endif // PACKED_PIXELS
return TAO_OK;
}
#endif // CONVERTS_FUNC
#ifdef PREPROCESS_FUNC
tao_status PREPROCESS_FUNC(
OUT* restrict dat,
OUT* restrict wgt,
const INP* restrict raw,
long width,
long height,
long bytes_per_line,
const OUT* restrict a,
const OUT* restrict b,
const OUT* restrict q,
const OUT* restrict r)
#endif
#if isfloat(dst) && !isfloat(src)
// Apply affine pixel correction.
void xjoin4(tao_pixels_preprocess_affine_,src,_to_,dst)(
ctype(dst)* restrict dat_,
long width,
long height,
const ctype(dst)* restrict a_,
const ctype(dst)* restrict b_,
const ctype(src)* restrict raw_,
long stride)
{
if (dat == NULL || raw == NULL || a == NULL || b == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return TAO_ERROR;
}
if (width < 0 || height < 0 || bytes_per_line%sizeof(INP) != 0) {
tao_store_error(__func__, TAO_BAD_SIZE);
return TAO_ERROR;
}
#ifndef PACKED_PIXELS
long stride = bytes_per_line/sizeof(INP);
#if packed(src) != 0
# if packed(src) == 12
long xm = width - 1;
bool isodd = (width & 1) != 0;
# else
# error Unsupported value for `packed`.
# endif
#endif
for (long y = 0; y < height; ++y) {
ctype(dst)* restrict dat = dat_ + y*width;
const ctype(dst)* restrict a = a_ + y*width;
const ctype(dst)* restrict b = b_ + y*width;
const ctype(src)* restrict raw = (const ctype(src)* restrict)(
((const uint8_t* restrict)raw_) + y*stride);
#if packed(src) == 0
for (long x = 0; x < width; ++x) {
dat_(x,y) = ((OUT)raw_(x,y) - b_(x,y))*a_(x,y);
dat[x] = correct(raw[x], a[x], b[x]);
}
if (wgt != NULL) {
if (q != NULL && r != NULL) {
for (long x = 0; x < width; ++x) {
wgt_(x,y) = q_(x,y)/max_(r_(x,y), r_(x,y) + dat_(x,y));
}
} else {
for (long x = 0; x < width; ++x) {
wgt_(x,y) = (OUT)1;
}
}
#elif packed(src) == 12
for (long x = 0; x < xm; x += 2) {
dat[x ] = correct(unpack12_1st(raw, x), a[x], b[x]);
dat[x+1] = correct(unpack12_2nd(raw, x), a[x+1], b[x+1]);
}
if (isodd) {
dat[xm] = correct(unpack12_1st(raw, xm), a[xm], b[xm]);
}
#endif
}
#elif PACKED_PIXELS == 12
}
// Apply affine pixel correction and compute weights.
void xjoin4(tao_pixels_preprocess_full_,src,_to_,dst)(
ctype(dst)* restrict dat_,
ctype(dst)* restrict wgt_,
long width,
long height,
const ctype(dst)* restrict a_,
const ctype(dst)* restrict b_,
const ctype(dst)* restrict q_,
const ctype(dst)* restrict r_,
const ctype(src)* restrict raw_,
long stride)
{
#if packed(src) != 0
# if packed(src) == 12
long xm = width - 1;
bool isodd = ((width&1) != 0);
bool isodd = (width & 1) != 0;
# else
# error Unsupported value for `packed`.
# endif
#endif
for (long y = 0; y < height; ++y) {
const uint8_t* restrict ptr = raw + bytes_per_line*y;
ctype(dst)* restrict dat = dat_ + y*width;
const ctype(dst)* restrict a = a_ + y*width;
const ctype(dst)* restrict b = b_ + y*width;
const ctype(src)* restrict raw = (const ctype(src)* restrict)(
((const uint8_t* restrict)raw_) + y*stride);
#if packed(src) == 0
for (long x = 0; x < width; ++x) {
dat[x] = correct(raw[x], a[x], b[x]);
}
#elif packed(src) == 12
for (long x = 0; x < xm; x += 2) {
unpacked b0 = ptr[0];
unpacked b1 = ptr[1];
unpacked b2 = ptr[2];
ptr += 3;
dat_(x,y) = ((OUT)unpack_p12_lo(b0, b1) - b_(x,y))*a_(x,y);
dat_(x+1,y) = ((OUT)unpack_p12_hi(b1, b2) - b_(x+1,y))*a_(x+1,y);
dat[x ] = correct(unpack12_1st(raw, x), a[x], b[x]);
dat[x+1] = correct(unpack12_2nd(raw, x), a[x+1], b[x+1]);
}
if (isodd) {
unpacked b0 = ptr[0];
unpacked b1 = ptr[1];
dat_(xm,y) = ((OUT)unpack_p12_lo(b0, b1) - b_(xm,y))*a_(xm,y);
dat[xm] = correct(unpack12_1st(raw, xm), a[xm], b[xm]);
}
if (wgt != NULL) {
if (q != NULL && r != NULL) {
for (long x = 0; x < width; ++x) {
wgt_(x,y) = q_(x,y)/max_(r_(x,y), r_(x,y) + dat_(x,y));
}
} else {
for (long x = 0; x < width; ++x) {
wgt_(x,y) = (OUT)1;
}
}
#endif
ctype(dst)* restrict wgt = wgt_ + y*width;
const ctype(dst)* restrict q = q_ + y*width;
const ctype(dst)* restrict r = r_ + y*width;
for (long x = 0; x < width; ++x) {
wgt[x] = weight(dat[x], q[x], r[x]);
}
}
#else
# error unexpected PACKED_PIXELS value
#endif // PACKED_PIXELS
return TAO_OK;
}
#endif // PREPROCESS_FUNC
#undef CONVERT_FUNC
#undef PREPROCESS_FUNC
#undef OUT
#endif
#endif // PIXELS_C_
// preprocessing.c -
//
// Image pre-processing in TAO.
//
//-----------------------------------------------------------------------------
//
// This file if part of TAO real-time software licensed under the MIT license
// (https://git-cral.univ-lyon1.fr/tao/tao-rt).
//
// Copyright (C) 2019-2022, Éric Thiébaut.
#ifndef TAO_PREPROCESSING_C_
//-----------------------------------------------------------------------------
// First `#include` level.
//
#define TAO_PREPROCESSING_C_ 1
#include "tao-preprocessing.h"
// Inline functions for unpacking 12-bit pixel values packed into 3 bytes.
//
// Argument `arr` is the base address of the row of pixels. Argument `i` is
// the index of the 1st pixel of the pair (`i` must be even). Functions
// `unpack12_1st` and `unpack12_2nd` respectively yield the value of the 1st
// and 2nd pixel of the pair (at respective indices `i` and `i+1` of the row).
static inline uint16_t unpack12_1st(const uint8_t* arr, long i)
{
uint16_t b0 = arr[3*i];
uint16_t b1 = arr[3*i + 1];
return (b0 << 4) | (b1 & (uint16_t)0x000F);
}
static inline uint16_t unpack12_2nd(const uint8_t* arr, long i)
{
uint16_t b1 = arr[3*i + 1];
uint16_t b2 = arr[3*i + 2];
return (b2 << 4) | (b1 >> 4);
}
static inline float fastmax_flt(float a, float b)
{
return (a >= b ? a : b);
}
static inline double fastmax_dbl(double a, double b)
{