Я пытаюсь вычислить яркость пикселя RGB различными способами, в C99 с GCC 9. У меня есть это перечисление:
typedef enum dt_iop_toneequalizer_method_t
{
DT_TONEEQ_MEAN = 0,
DT_TONEEQ_LIGHTNESS,
DT_TONEEQ_VALUE
} dt_iop_toneequalizer_method_t;
, который является пользовательским вводом из графического интерфейса.
Тогда у меня есть несколько функций, соответствующих каждому случаю:
typedef float rgb_pixel[4] __attribute__((aligned(16)));
#pragma omp declare simd aligned(pixel:64)
static float _RGB_mean(const rgb_pixel pixel)
{
return (pixel[0] + pixel[1] + pixel[2] + pixel[3]) / 3.0f;
}
#pragma omp declare simd aligned(pixel:16)
static float _RGB_value(const rgb_pixel pixel)
{
return fmaxf(fmaxf(pixel[0], pixel[1]), pixel[2]);
}
#pragma omp declare simd aligned(pixel:16)
static float _RGB_lightness(const rgb_pixel pixel)
{
const float max_rgb = _RGB_value(pixel);
const float min_rgb = fminf(pixel[0], fminf(pixel[1], pixel[2]));
return (max_rgb + min_rgb) / 2.0f;
}
Тогда цикл над изображением будет:
static void exposure_mask(const float *const restrict in,
float *const restrict out,
const size_t width,
const size_t height,
const dt_iop_toneequalizer_method_t method)
{
#pragma omp parallel for simd default(none) schedule(static) aligned(in, out:64)
for(size_t k = 0; k < 4 * width * height; k += 4)
{
const rgb_pixel pixel = { in[k], in[k + 1], in[k + 2], 0.0f };
out[k / 4] = RGB_light(pixel, method);
}
}
Мой первый подход состоял в том, чтобы использовать функцию RGB_light()
с переключателем / регистром, отображающим method
и функции, но это запускает проверки для каждого пикселя, что довольно дорого.
Моя идея состоит в том, чтобы использовать список или struct
методов, например:
typedef struct RGB_light
{
// Pixel intensity (method == DT_TONEEQ_MEAN)
float (*_RGB_mean)(rgb_pixel pixel);
// Pixel HSL lightness (method == DT_TONEEQ_LIGHTNESS)
float (*_RGB_lightness)(rgb_pixel pixel);
// Pixel HSV value (method == DT_TONEEQ_VALUE)
float (*_RGB_value)(rgb_pixel pixel);
} RGB_light;
затем инициализируйте метод один раз для всех перед циклом, как
static void exposure_mask(const float *const restrict in,
float *const restrict out,
const size_t width,
const size_t height,
const dt_iop_toneequalizer_method_t method)
{
lightness_method = RGB_light[method]; // obviously wrong syntax
#pragma omp parallel for simd default(none) schedule(static) aligned(in, out:64)
for(size_t k = 0; k < 4 * width * height; k += 4)
{
const rgb_pixel pixel = { in[k], in[k + 1], in[k + 2], 0.0f };
out[k / 4] = lightness_method(pixel);
}
}
но мне не удалось перевести эту идею в реальный рабочий код.
Есть что-то похожее на то, что я хочу сделать в Python:
def RGB_value(pixel):
return whatever
def RGB_lightness(pixel):
return whatever
methods = { 1: RGB_value, 2: RGB_lightness }
def loop(image, method):
for pixel in image:
lightness = methods[method](pixel)