Files
calyp/source/lib/PlaYUVerFrameStatistics.cpp
T
jfmcarreira e0695f9cdc Bugfix in HistogramWidget and PlaYUVerFrameStatistics
Conditions were not proper checking if frame exists
Change on some variables name
Still incomplete the code and some variable must be renamed
to include code style
2014-04-05 14:35:42 +01:00

579 lines
13 KiB
C++
Executable File

/* This file is a part of plaYUVer project
* Copyright (C) 2014 by Luis Lucas (luisfrlucas@gmail.com)
* Joao Carreira (jfmcarreira@gmail.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/**
* \file PlaYUVerFrameStatistics.cpp
* \brief Measure PlaYUVerFrame statistics
* Based on the work of Ricardo N. Rocha Sardo in SCode project
*/
#include <cstdio>
#include <cmath>
#include <cstring>
#include <QtGui>
#include "PlaYUVerFrameStatistics.h"
#include "LibMemory.h"
namespace plaYUVer
{
////////////////////////////////////////////////////////////////////////////////
// Private Data Class
////////////////////////////////////////////////////////////////////////////////
class PlaYUVerFrameStatisticsPrivate
{
public:
/*
// Using a structure instead a class is more fast
// (access with memset() and bytes manipulation).
struct double_packet
{
double luma;
double red;
double green;
double blue;
double alpha;
};
*/
public:
PlaYUVerFrameStatisticsPrivate()
{
parent = 0;
imageData = 0;
histogram = 0;
runningFlag = true;
}
/** The histogram data.*/
Double *histogram;
/** If true, calc the luminosity channel histogram when the image is RGB */
bool calcLuma;
/** If the image is RGB and calcLuma is true, we have 1 more channel */
int histoChannels;
/** Image information.*/
uchar *imageData;
uint imageWidth;
uint imageHeight;
int imageChannels;
Int imageColorSpace;
/** Numbers of histogram segments dependaing of image bytes depth*/
int histoSegments;
/** To post event from thread to parent.*/
QObject *parent;
/** Used to stop thread during calculations.*/
bool runningFlag;
};
////////////////////////////////////////////////////////////////////////////////
// Constructors and Destructor
////////////////////////////////////////////////////////////////////////////////
PlaYUVerFrameStatistics::PlaYUVerFrameStatistics( const PlaYUVerFrame& playuver_frame, QObject *parent, Options options ) :
QThread()
{
// TODO: check the correct pel_format
setup( playuver_frame.getQImageBuffer(), playuver_frame.getWidth(), playuver_frame.getHeight(), playuver_frame.getBitsChannel(), PlaYUVerFrame::RGB8, parent, options );
}
PlaYUVerFrameStatistics::PlaYUVerFrameStatistics( Pel *data, uint width, uint height, int bitsPerChannel, Int pixel_format, QObject *parent, Options options ) :
QThread()
{
// TODO: check the correct pel_format
setup( data, width, height, bitsPerChannel, PlaYUVerFrame::RGB8, parent, options );
}
PlaYUVerFrameStatistics::~PlaYUVerFrameStatistics()
{
stopCalcHistogramValues();
if( d->histogram )
delete[] d->histogram;
delete d;
}
////////////////////////////////////////////////////////////////////////////////
// Setup Function
////////////////////////////////////////////////////////////////////////////////
void PlaYUVerFrameStatistics::setup( Pel *data, uint width, uint height, int bitsPerChannel, Int pixel_format, QObject *parent, Options options )
{
d = new PlaYUVerFrameStatisticsPrivate;
d->imageData = data;
d->imageWidth = width;
d->imageHeight = height;
d->parent = parent;
d->histoSegments = ( bitsPerChannel == 16 ) ? 65536 : 256;
d->imageColorSpace = PlaYUVerFrame::isRGBorYUVorGray( pixel_format );
if( options == CalcLumaWhenRGB )
d->calcLuma = true;
else
d->calcLuma = false;
switch( d->imageColorSpace )
{
case PlaYUVerFrame::COLOR_GRAY:
d->imageChannels = 1;
break;
case PlaYUVerFrame::COLOR_RGB:
case PlaYUVerFrame::COLOR_YUV:
d->imageChannels = 3;
break;
case PlaYUVerFrame::COLOR_ARGB:
d->imageChannels = 4;
break;
default:
d->imageChannels = 1;
}
if( d->calcLuma && ( d->imageColorSpace == PlaYUVerFrame::COLOR_RGB ) )
d->histoChannels = d->imageChannels + 1;
else
d->histoChannels = d->imageChannels;
if( d->imageData && d->imageWidth && d->imageHeight )
{
if( d->parent )
start();
else
run(); //Lukas - substitui calcHistogramValues por run()
}
else
{
if( d->parent )
postProgress( false, false );
}
}
////////////////////////////////////////////////////////////////////////////////
// Accessing Properties
////////////////////////////////////////////////////////////////////////////////
int PlaYUVerFrameStatistics::getHistogramSegment( void )
{
return d->histoSegments;
}
int PlaYUVerFrameStatistics::getRealHistoChannel( int channel )
{
int histoChannel;
switch( d->imageColorSpace )
{
case PlaYUVerFrame::COLOR_GRAY:
if( channel != LumaChannel )
{
return -1;
}
histoChannel = 0;
break;
case PlaYUVerFrame::COLOR_RGB:
if( channel != RedChannel && channel != GreenChannel && channel != BlueChannel && ( channel != LumaChannel && d->calcLuma ) )
{
return -1;
}
else
{
if( channel == RedChannel )
histoChannel = 0;
if( channel == GreenChannel )
histoChannel = 1;
if( channel == BlueChannel )
histoChannel = 2;
if( channel == LumaChannel )
histoChannel = 3;
}
break;
case PlaYUVerFrame::COLOR_ARGB:
if( channel != RedChannel && channel != GreenChannel && channel != BlueChannel && channel != AlphaChannel && ( channel != LumaChannel && d->calcLuma ) )
{
return -1;
}
else
{
if( channel == AlphaChannel )
histoChannel = 0;
if( channel == RedChannel )
histoChannel = 1;
if( channel == GreenChannel )
histoChannel = 2;
if( channel == BlueChannel )
histoChannel = 3;
if( channel == LumaChannel )
histoChannel = 4;
}
break;
case PlaYUVerFrame::COLOR_YUV:
if( channel != YChannel && channel != CbChannel && channel != CrChannel )
{
return -1;
}
else
{
if( channel == YChannel )
histoChannel = 0;
if( channel == CbChannel )
histoChannel = 1;
if( channel == CrChannel )
histoChannel = 2;
}
break;
default:
histoChannel = -1;
}
return histoChannel;
}
////////////////////////////////////////////////////////////////////////////////
// Progress Indicators
////////////////////////////////////////////////////////////////////////////////
void PlaYUVerFrameStatistics::postProgress( bool starting, bool success )
{
EventData *eventData = new EventData();
eventData->starting = starting;
eventData->success = success;
eventData->histogram = this;
QCoreApplication::postEvent( d->parent, eventData );
}
void PlaYUVerFrameStatistics::stopCalcHistogramValues( void )
{
d->runningFlag = false;
wait();
}
////////////////////////////////////////////////////////////////////////////////
// List of threaded operations
////////////////////////////////////////////////////////////////////////////////
void PlaYUVerFrameStatistics::run()
{
calcHistogramValues();
}
void PlaYUVerFrameStatistics::calcHistogramValues()
{
register uint i;
register int j;
if( d->parent )
postProgress( true, false );
getMem1D<Double>( &(d->histogram ), d->histoSegments * d->histoChannels);
if( !d->histogram )
{
qWarning( ) << "PlaYUVerFrameStatistics::calcHistogramValuess: "
"Unable to allocate memory!"
<< endl;
if( d->parent )
postProgress( false, false );
return;
}
// 16 bits image.
if( d->histoSegments == 65536 )
{
unsigned short *data = ( unsigned short* )d->imageData;
unsigned short luma;
for( i = 0; ( i < d->imageHeight * d->imageWidth ) && d->runningFlag; i++ )
{
for( j = 0; j < d->imageChannels; j++ )
{
d->histogram[data[j] + j * d->histoSegments]++;
}
// Calc the luminosity when it's applicable
if( d->calcLuma && d->imageColorSpace == PlaYUVerFrame::COLOR_RGB )
{
luma = ( unsigned short )( 0.299 * data[0] + 0.587 * data[1] + 0.114 * data[2] );
d->histogram[luma + j * d->histoSegments]++;
}
if( d->calcLuma && d->imageColorSpace == PlaYUVerFrame::COLOR_ARGB )
{
luma = ( unsigned short )( 0.299 * data[1] + 0.587 * data[2] + 0.114 * data[3] );
d->histogram[luma + j * d->histoSegments]++;
}
data += d->imageChannels;
}
}
// 8 bits images.
else
{
Pel *data = d->imageData;
Pel luma;
for( i = 0; ( i < d->imageHeight * d->imageWidth ) && d->runningFlag; i++ )
{
for( j = 0; j < d->imageChannels; j++ )
{
d->histogram[data[j] + j * d->histoSegments]++;
}
// Calc the luminosity when it's applicable
if( d->calcLuma && d->imageColorSpace == PlaYUVerFrame::COLOR_RGB )
{
luma = ( uchar )( 0.299 * data[0] + 0.587 * data[1] + 0.114 * data[2] );
d->histogram[luma + j * d->histoSegments]++;
}
if( d->calcLuma && d->imageColorSpace == PlaYUVerFrame::COLOR_ARGB )
{
luma = ( uchar )( 0.299 * data[1] + 0.587 * data[2] + 0.114 * data[3] );
d->histogram[luma + j * d->histoSegments]++;
}
data += d->imageChannels;
}
}
if( d->parent && d->runningFlag )
postProgress( false, true );
}
double PlaYUVerFrameStatistics::getCount( int channel, int start, int end )
{
int i;
int histoChannel;
int indexStart;
double count = 0.0;
if( !d->histogram || start < 0 || end > d->histoSegments - 1 || start > end )
{
return 0.0;
}
histoChannel = getRealHistoChannel( channel );
if( histoChannel == -1 )
{
return 0.0;
}
indexStart = histoChannel * d->histoSegments;
for( i = start; i <= end; i++ )
{
count += d->histogram[indexStart + i];
}
return count;
}
double PlaYUVerFrameStatistics::getPixels()
{
if( !d->histogram )
{
return 0.0;
}
return ( d->imageWidth * d->imageHeight );
}
double PlaYUVerFrameStatistics::getMean( int channel, int start, int end )
{
int i;
int indexStart;
int histoChannel;
double mean = 0.0;
double count;
if( !d->histogram || start < 0 || end > d->histoSegments - 1 || start > end )
{
return 0.0;
}
histoChannel = getRealHistoChannel( channel );
if( histoChannel == -1 )
{
return 0.0;
}
indexStart = histoChannel * d->histoSegments;
for( i = start; i <= end; i++ )
{
mean += i * d->histogram[indexStart + i];
}
count = getCount( channel, start, end );
if( count > 0.0 )
{
return mean / count;
}
return mean;
}
int PlaYUVerFrameStatistics::getMedian( int channel, int start, int end )
{
int i;
int histoChannel;
int indexStart;
double sum = 0.0;
double count;
if( !d->histogram || start < 0 || end > d->histoSegments - 1 || start > end )
{
return 0;
}
histoChannel = getRealHistoChannel( channel );
if( histoChannel == -1 )
{
return 0;
}
indexStart = histoChannel * d->histoSegments;
count = getCount( channel, start, end );
for( i = start; i <= end; i++ )
{
sum += d->histogram[indexStart + i];
if( sum * 2 > count )
return i;
}
return 0;
}
double PlaYUVerFrameStatistics::getStdDev( int channel, int start, int end )
{
int i;
int histoChannel;
int indexStart;
double dev = 0.0;
double count;
double mean;
if( !d->histogram || start < 0 || end > d->histoSegments - 1 || start > end )
{
return 0.0;
}
histoChannel = getRealHistoChannel( channel );
if( histoChannel == -1 )
{
return 0.0;
}
indexStart = histoChannel * d->histoSegments;
mean = getMean( channel, start, end );
count = getCount( channel, start, end );
if( count == 0.0 )
count = 1.0;
/*------------ original
for ( i = start ; i <= end ; i++ )
{
dev += ( i - mean ) * ( i - mean ) * d->histogram[indexStart +i];
}
return sqrt( dev / count );
-----------------------*/
for( i = start; i <= end; i++ )
{
dev += ( i * i ) * d->histogram[indexStart + i];
}
return sqrt( ( dev - count * mean * mean ) / ( count - 1 ) );
}
double PlaYUVerFrameStatistics::getValue( int channel, int bin )
{
double value;
int histoChannel;
int indexStart;
if( !d->histogram || bin < 0 || bin > d->histoSegments - 1 )
return 0.0;
histoChannel = getRealHistoChannel( channel );
if( histoChannel == -1 )
{
return 0.0;
}
indexStart = histoChannel * d->histoSegments;
value = d->histogram[indexStart + bin];
return value;
}
double PlaYUVerFrameStatistics::getMaximum( int channel )
{
double max = 0.0;
int x;
int histoChannel;
int indexStart;
if( !d->histogram )
return 0.0;
histoChannel = getRealHistoChannel( channel );
if( histoChannel == -1 )
{
return 0.0;
}
indexStart = histoChannel * d->histoSegments;
for( x = 0; x < d->histoSegments; x++ )
{
if( d->histogram[indexStart + x] > max )
{
max = d->histogram[indexStart + x];
}
}
return max;
}
} // NAMESPACE