Гистограмма не точна для темных изображений

Я использую следующий алгоритм для расчета гистограммы из изображения YUV420sp. Кажется, работает, но результат не на 100% точен для полностью темного изображения. Когда изображение темное, на левой стороне гистограммы можно ожидать высокого пика, показывающего, что изображение слишком темное, но алгоритм в таком сценарии показывает вместо плоской линии, без пика. На других легких сценариях гистограмма кажется точной.

void calculateHistogram(const unsigned char* yuv420sp, const int yuvWidth, const int yuvHeight, const int histogramControlHeight, int* outHistogramData)
{
const int BINS = 256;

// Clear the output

memset(outHistogramData, 0, BINS * sizeof(int));

// Get YUV brightness values

const int totalPixels = yuvWidth * yuvHeight;

for (int index = 0; index < totalPixels; index++)
{
char brightness = yuv420sp[index];
outHistogramData[brightness]++;
}

// Get the maximum brightness

int maxBrightness = 0;

for (int index = 0; index < BINS; index++)
{
if (outHistogramData[index] > maxBrightness)
{
maxBrightness = outHistogramData[index];
}
}

// Normalize to fit the UI control height

const int maxNormalized = BINS * histogramControlHeight / maxBrightness;

for(int index = 0; index < BINS; index++)
{
outHistogramData[index] = (outHistogramData[index] * maxNormalized) >> 8;
}
}

[Решено galop1n] Хотя реализация Galop1n гораздо приятнее, я обновляю ее с исправлениями на случай, если это пригодится кому-либо.

Изменения:

1) Чтение значений яркости в неподписанный символ вместо символа.

2) Помещен раздел нормализации пользовательского интерфейса в цикл нормализации.

void calculateHistogram(const unsigned char* yuv420sp, const int yuvWidth, const int yuvHeight, const int histogramCanvasHeight, int* outHistogramData)
{
const int BINS = 256;

// Clear the output

memset(outHistogramData, 0, BINS * sizeof(int));

// Get YUV brightness values

const int totalPixels = yuvWidth * yuvHeight;

for (int index = 0; index < totalPixels; index++)
{
unsigned char brightness = yuv420sp[index];
outHistogramData[brightness]++;
}

// Get the maximum brightness

int maxBrightness = 0;

for (int index = 0; index < BINS; index++)
{
if (outHistogramData[index] > maxBrightness)
{
maxBrightness = outHistogramData[index];
}
}

// Normalize to fit the UI control height

for(int index = 0; index < BINS; index++)
{
outHistogramData[index] = outHistogramData[index] * histogramCanvasHeight / maxBrightness;
}
}

0

Решение

В вашей реализации есть как минимум две ошибки.

  1. Индексирование по яркости из-за использования временного типа со знаком char.
  2. На конечный результат нормализации может влиять значение высоты элемента управления и максимальное количество пикселей в ячейке. Из-за этого деление не может быть вынесено за пределы цикла.

Я рекомендую также использовать std::array (требуется c ++ 11) для сохранения результата вместо необработанного указателя, так как существует риск, что вызывающая сторона не выделит достаточно места для того, что будет использовать функцию.

#include <algorithm>
#include <array>

void calculateHistogram(const unsigned char* yuv420sp, const int yuvWidth, const int yuvHeight, const int histogramControlHeight, std::array<int, 256> &outHistogramData ) {
outHistogramData.fill(0);
std::for_each( yuv420sp, yuv420sp + yuvWidth * yuvHeight, [&](int e) {
outHistogramData[e]++;
} );
int maxCountInBins = * std::max_element( begin(outHistogramData), end(outHistogramData) );
for( int &bin : outHistogramData )
bin = bin * histogramControlHeight / maxCountInBins;
}
1

Другие решения

Если максимальная яркость изображения maxBrightness равен нулю, ваш расчет maxNormalized становится делением на ноль. Я подозреваю, что это где ваша проблема.

Без лучшего понимания, какие условия нормализации вы пытаетесь установить, я не уверен, какую альтернативу предложить вам прямо сейчас.

0

По вопросам рекламы [email protected]