Я использую следующий алгоритм для расчета гистограммы из изображения 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;
}
}
В вашей реализации есть как минимум две ошибки.
Я рекомендую также использовать 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;
}
Если максимальная яркость изображения maxBrightness
равен нулю, ваш расчет maxNormalized становится делением на ноль. Я подозреваю, что это где ваша проблема.
Без лучшего понимания, какие условия нормализации вы пытаетесь установить, я не уверен, какую альтернативу предложить вам прямо сейчас.