Implementing an RGB algorithm for changing image contrast

While working on a program designed to process a video stream, it became necessary to implement an algorithm for changing the image contrast.
Since the program was intended for video processing, the implementation required high performance, including the ability to process Full HD video resolution. The code was written in C ++ using the OpenMP library.
There are several algorithms for changing contrast, some of which are considered in this article [1].
Consider the RGB algorithm for changing contrast.
First, we calculate the average brightness of the image lAB. We use the OpenMP directive to parallelize the loop:
#pragma omp parallel for private(valueB,valueG,valueR) reduction(+:lAB) schedule(static,1)
for (int j = 0; j < ptrImage->imageSize; j = j+3)
{
valueB = ptrImage->imageData[j];
valueG = ptrImage->imageData[j+1];
valueR = ptrImage->imageData[j+2];
lAB += (int)(valueR * 0.299 + valueG * 0.587 + valueB * 0.114);
}
//средняя яркость
lAB /= imageRows * imageCols;
Then, for each image pixel for each of the color components R, G, and B, we must find the deviation from the average brightness value delta, and multiply this deviation by the gain (attenuation) of the contrast k. Performing this directly on all pixels in an image is too expensive an operation. Therefore, given that we convert all the color components of the pixel in the same way, we introduce an array of 256 values that will represent the palette for each color component. The index of the array corresponds to the old value of the color component, and the value of the array corresponds to the converted one. Thus, applying the previously described transformations to change the contrast to the palette, we obtain:
//Коэффициент коррекции
double k = 1.0 + correction / 100.0;
for (int i = 0; i < 256; i++)
{
int delta = (int)i - lAB;
int temp = (int)(lAB + k *delta);
if (temp < 0)
temp = 0;
if (temp >= 255)
temp = 255;
b[i] = (unsigned char)temp;
}
And then, we apply new values for the pixels of the entire image, comparing the old value of the color component of the pixel with the new one, using the resulting palette array:
#pragma omp parallel for firstprivate(b)
for (int j = 0; j < ptrImage->imageSize; j++)
{
unsigned char value = ptrImage->imageData[j];
ptrImage->imageData[j] = (unsigned char)b[value];
}
The entire source code of the function to change the contrast:
const int L = 256;
void AddContrastFilter(IplImage* ptrImage, int _correction)
{
// установить число потоков в 4, равным количеству процессоров в системе
omp_set_num_threads(4);
int correction = _correction;
//палитра
int b[L];
//Число строк и столбцов
int imageRows = ptrImage->height;
int imageCols = ptrImage->width;
int lAB = 0;
unsigned char valueB = 0;
unsigned char valueG= 0;
unsigned char valueR= 0;
//Находим яркость всех пикселей
#pragma omp parallel for private(valueB,valueG,valueR) reduction(+:lAB) schedule(static,1)
for (int j = 0; j < ptrImage->imageSize; j = j+3)
{
valueB = ptrImage->imageData[j];
valueG = ptrImage->imageData[j+1];
valueR = ptrImage->imageData[j+2];
lAB += (int)(valueR * 0.299 + valueG * 0.587 + valueB * 0.114);
}
//средняя яркость всех пикселей
lAB /= imageRows * imageCols;
//Коэффициент коррекции
double k = 1.0 + correction / 100.0;
//RGB алгоритм изменения контраста
for (int i = 0; i < L; i++)
{
int delta = (int)i - lAB;
int temp = (int)(lAB + k *delta);
if (temp < 0)
temp = 0;
if (temp >= 255)
temp = 255;
b[i] = (unsigned char)temp;
}
#pragma omp parallel for firstprivate(b)
for (int j = 0; j < ptrImage->imageSize; j++)
{
unsigned char value = ptrImage->imageData[j];
ptrImage->imageData[j] = (unsigned char)b[value];
}
return 0;
}
It turned out to me that changing the contrast of a Full HD frame on a four-core Intel Xeon processor takes about 8 ms in time.
References
1. Conversion of contrast in software: http://www.kweii.com/site/color_theory/Contrast100_en.pdf