Files
secondo/Algebras/Picture/PictureAlgebra_histimp.cpp
2026-01-23 17:03:45 +08:00

978 lines
25 KiB
C++

/*
//paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}]
//paragraph [10] Footnote: [{\footnote{] [}}]
//[ue] [\"{u}]
//[ae] [\"{a}]
//[TOC] [\tableofcontents]
[1] Picture Algebra: Class Definitions
Dezember 2004 Christian Bohnbuck, Uwe Hartmann, Marion Langen and Holger
M[ue]nx during Prof. G[ue]ting's practical course
'Extensible Database Systems' at Fernuniversit[ae]t Hagen.
December 2005, Victor Almeida deleted the deprecated algebra levels
(~executable~, ~descriptive~, and ~hibrid~). Only the executable
level remains. Models are also removed from type constructors.
[TOC]
1 Introduction
See the documentation of ~PictureAlgebra.h~ for a general introduction to
the Picture algebra.
This module contains all methods required for ~Histogram~
to represent a SECONDO ~histogram~ object plus functions required by
SECONDO to use ~Histogram~ plus basic SECONDO operators on ~histogram~.
2 Includes and other preparations
*/
#include <cmath>
#include "NestedList.h"
#include "PictureAlgebra.h"
#include "JPEGPicture.h"
using namespace std;
extern NestedList* nl;
extern QueryProcessor *qp;
static double DIFFERENZ_DELTA = 0.001;
/*
3 Implementation of class ~Histogram~
For further information please check ~PictureAlgebra.h~.
3.1 Constructors and destructors
3.1.1 Constructor
The constructor transforms the specified ~rgbData~ into a
histgram. Furthermore some private variables such as ~channel~ and the
~histogramMaxValue~ etc. are set.
*/
Histogram::Histogram( unsigned char * rgbData,
unsigned long rgbSize,
HistogramChannel _channel): Attribute(true) {
if (PA_DEBUG) cerr << "Histogram::Histogram()-1 called" << endl;
//
// Initialise the histogram array and the channel !
//
histogramMaxValue = 0.0;
channel = HistogramChannel(0);
SetDefined(false);
for ( int i=0; i<256; i++ )
{
histogram[i] = 0.0;
histogram_abs[i] = 0;
}
if (( _channel < 0 ) || ( _channel > 3 ) )
{
cerr << endl << endl
<< "Channel has a wrong value. Valid values are [0, 3]. "
<< "Specified value: " << _channel << endl<< endl;
return;
}
channel = _channel;
SetDefined(true);
unsigned int no;
if ( channel < HistogramChannel(HC_BRIGHTNESS) )
{
//
// Create Histogram for Red, Green, Blue
//
for ( unsigned int i=channel; i<rgbSize; i+=3 )
{
no = (unsigned int) rgbData[i];
if (no > 255)
cerr << "color value out of range: " << no <<", ";
else
{
histogram_abs[ no ]++;
}
}
}
else
{
//
// Create Histogram for BRIGHTNESS
//
double y = 0.0;
int index = 0;
for ( unsigned int i=0; i< rgbSize-3; i+=3 )
{
y = 0.3 * (unsigned int) rgbData[i] +
0.59 * (unsigned int) rgbData[i+1] +
0.11 * (unsigned int) rgbData[i+2];
index = (int) y;
histogram[ index ]++;
}
}
//
// Print out for debug purposes
//
if (PA_DEBUG)
{
cerr << "Histogram::Histogram histogram: " << endl;
for ( int i=0; i< 256; i++ )
{
cerr << histogram[i] ;
if ( (i%10) == 0 )
cerr << endl;
else
cerr << ", ";
}
cerr << endl;
cerr << "Histogram::Histogram channel: " << channel << endl;
cerr << "Max Value: " << histogramMaxValue << endl;
}
}
/*
3.1.2 Constructor
This constructor gets data of a ~histogram~, the channel and the maximum value of
the ~histogram~. These information are saved in the ~histogram~ object.
*/
Histogram::Histogram( double * _histogram,
HistogramChannel _channel,
double maxValue):Attribute(true) {
if (PA_DEBUG) cerr << "Histogram::Histogram()-2 called" << endl;
//
// Initialise the histogram array and the channel !
//
channel = HistogramChannel(0);
SetDefined(false);
for ( int i=0; i<256; i++ )
histogram[i] = 0.0;
//
// Check the specified parameter !
//
if (( _channel < 0 ) || ( _channel > 3 ) )
{
cerr << endl << endl
<< "Channel has a wron value. Valid values are [0, 3]. "
<< "Specified value: " << _channel << endl<< endl;
return;
}
//
// Everything is fine !
//
channel = _channel;
histogramMaxValue = maxValue;
SetDefined(true);
for ( int i=0; i<256; i++ )
{
histogram[i] = _histogram[i];
}
//
// Print out for debug purposes
//
// if (PA_DEBUG)
// {
// cerr << "Histogram::Histogram channel: " << channel << endl;
// cerr << "Histogram::Histogram histogram: " << endl;
// for ( int i=0; i< 256; i++ )
// {
// cerr << histogram[i] ;
// if ( (i%10) == 0 )
// cerr << endl;
// else
// cerr << ", ";
// }
// cerr << endl;
// }
}
/*
3.2 ~Attribute~ implementation
*/
void
Histogram::ScaleValues(double factor) {
for ( int i=0; i<256; i++ )
{
histogram[i] = ((double)histogram_abs[i]) * factor;
}
histogramMaxValue = histogramMaxValue * factor;
}
double
Histogram::CheckSum(double refValue) {
double sum = 0.0;
for ( int i=0; i<256; i++ )
{
sum += histogram[i];
}
if ( sum != refValue ) {
cerr << "color(" << channel
<< ") sum(double) differs by " << refValue - sum << endl;
}
return sum;
}
int
Histogram::CheckSum(int refValue) {
int sum = 0;
for ( int i=0; i<256; i++ )
{
sum += histogram_abs[i];
}
if ( sum != refValue ) {
cerr << "color(" << channel
<< ") sum(int) differs by " << refValue - sum << endl;
}
return sum;
}
size_t Histogram::HashValue(void) const {
if (PA_DEBUG) cerr << "Histogram::HashValue() called" << endl;
unsigned long h = 0;
if ( !IsDefined()) return 0;
for ( int i=0; i<256; i++ )
h += ((int) (histogram[i]*100)) * (i+1) + channel;
return h;
}
void Histogram::CopyFrom(const Attribute* attr) {
if (PA_DEBUG) cerr << "Histogram::CopyFrom() called" << endl;
const Histogram* h = (const Histogram*) attr;
//
// copy all attributes
//
SetDefined( h->IsDefined());
if ( ! IsDefined() )
return;
channel = h->channel;
histogramMaxValue = h->histogramMaxValue;
for ( int i=0; i<256; i++ )
histogram[i] = h->histogram[i];
}
int Histogram::Compare(const Attribute* a) const {
if (PA_DEBUG) cerr << "Histogram::Compare() called" << endl;
const Histogram * h = (const Histogram*) a;
//
// At first, check the channel
//
if ( channel < h->channel )
return -1;
else
if ( channel > h->channel )
return +1;
//
// There is no difference in terms of channel, so check
// the histograms.
//
for ( int i=0; i< 256; i++ )
{
if ( fabs( histogram[i] - h->histogram[i]) < DIFFERENZ_DELTA )
continue;
if ( histogram[i] < h->histogram[i] )
return -1;
else
return 1;
}
//
// In this case, both histograms are equal!
//
return 0;
}
Histogram* Histogram::Clone(void) const {
if (PA_DEBUG) cerr << "Histogram::Clone() called" << endl;
Histogram * h = new Histogram();
h->CopyFrom((const Attribute*) this);
return h;
}
/*
3.3 Methods required for SECONDO operators
3.3.1 Function ~GetHistogramData~
This function returns the data of the ~histogram~.
*/
double* Histogram::GetHistogramData(void) {
if (PA_DEBUG) cerr << "Histogram::GetHistogramData() called" << endl;
return histogram;
}
/*
3.3.2 Function ~GetHistogramChannel~
The function ~GetHistogramChannel~ returns the channel of the ~histogram~.
*/
HistogramChannel Histogram::GetHistogramChannel(void) {
if (PA_DEBUG) cerr << "Histogram::GetHistogramChannel() called" << endl;
return channel;
}
/*
3.3.3 Function ~GetHistogramMaxValue~
~GetHistogramMaxValue~ returns the maximum value of all four ~histograms~.
*/
double Histogram::GetHistogramMaxValue(void) {
if (PA_DEBUG) cerr << "Histogram::GetHistogramMaxValue() called" << endl;
if (PA_DEBUG)
cerr << "Max Value: " << histogramMaxValue << endl;
return histogramMaxValue;
}
/*
3.4 Operators on ~histogram~
3.4.1 Operator ~Equals~
The function compares two ~histogram~ objects whether they are equal or not.
Therefore, it calculates the average values of an specified number ~n~
of values in a row. The ~histogram~ objects are defined as equal if the average values differs less
than ~p/10000~ from each other.
*/
bool Histogram::Equals(Histogram* h, int n, int p, bool& valid, double& diff) {
static const double Tolerance_Unit = 0.0001;
if (PA_DEBUG) cerr << "Histogram::Equals() called" << endl;
if ( n <= 0 )
{
cerr << endl << endl
<< "Function: equals: picture x picture x int x int" << endl
<< "Third argument " << n << " must be positive. "
<< "It will be set to 1."
<< endl << endl;
n=1;
}
if ( n > 256 )
{
cerr << endl << endl
<< "Function: equals: picture x picture x int x int" << endl
<< "Third argmument " << n << " must be lower equal 256. "
<< "It will be set to 1."
<< endl << endl;
n=1;
}
if ( (p<0) || ((double)p > (100/Tolerance_Unit)) )
{
cerr << endl << endl
<< "Function: equals: picture x picture x int x int"
<< endl
<< "The tolerance value must be between 0 and "
<< 100/Tolerance_Unit << endl
<< "Specified value: " << p << " will be set to 100"
<< endl << endl;
p=100;
}
double m1=0, m2=0;
valid = true;
bool isEqual = true;
//
// Create intervals of n numbers in row ! Than calculate the
// average values of these n numbers for comparision.
//
for( int i=0; i<=256-n; i++ )
{
m1 = 0.0;
m2 = 0.0;
for ( int j=i; j<i+n; j++ )
{
m1 += histogram[ j ];
m2 += h->histogram[ j ];
//if (histogram[j] < 0
// || histogram[j] > 100
// || h->histogram[j] < 0
// || h->histogram[j] > 100) {
// cerr << "Histogram::Equals() this looks fishy! j="
// << j
// << " histogram[j]="
// << histogram[j]
// << " h->histogram[j]="
// << h->histogram[j]
// << " this="
// << (int) this
// << " h="
// << (int) h
// << endl;
//}
}
m1 = m1 / (double) n;
m2 = m2 / (double) n;
//
// Check, whether these pictures are equal !
//
double dist = abs( m1 - m2 );
double maxdiff = p * Tolerance_Unit;
if ( dist > maxdiff )
{
if (PA_DEBUG)
cerr << i<< ". [" << m1-maxdiff << ", " << m1+maxdiff
<< "] , m2 = " << m2 << endl;
isEqual = false;
diff += dist;
}
if (PA_DEBUG)
cerr << i<< ". [" << m1-maxdiff << ", "
<< m1+maxdiff << "] (, m1 = " << m1
<< "), m2 = " << m2 << endl;
}
cerr << "histogram difference: " << diff << endl;
if (PA_DEBUG) cerr << "These pictures are "
<< ((isEqual)? "": "not " ) << "equal." << endl;
return( isEqual );
}
/*
3.4.2 Operator ~Like~
This function checks whether ~p~ +- ~t~ percent of all pixel are in the
specified interval [~l~, ~u~].
*/
bool Histogram::Like(int p, int t, int l, int u, bool& valid) {
if (PA_DEBUG) cerr << "Histogram::Like() called (Type:Int)" << endl;
//
// Check the specified arguments
//
if (( p < 0 ) || ( p > 100 ))
{
cerr << endl << endl
<< "Function: like: picture x int x int x int x int" << endl
<< "The second argument must be in the interval "
<< "[0, 100]." << endl
<< "Specified argument: " << p << endl << endl;
valid = false;
return false;
}
if (( t < 0 ) || ( t > 100 ))
{
cerr << endl << endl
<< "Function: like: picture x int x int x int x int" << endl
<< "The third argument must be in the interval "
<< "[0, 100]." << endl
<< "Specified argument: " << t << endl << endl;
valid = false;
return false;
}
//
// Actually, I expect that l < u, but nevertheless, I'll check it.
//
int min = (l<u) ? l:u;
int max = (l<u) ? u:l;
if (( min < 0 ) || ( max > 255 ))
{
cerr << endl << endl
<< "Function: like: picture x int x int x int x int" << endl
<< "The fourth and fifth argument must be in the interval"
<< "[0, 255]." << endl
<< "Specified arguments: " << l << ", " << u << endl << endl;
valid = false;
return false;
}
if (( p-t < 0 ) || ( p+t > 100 ))
{
cerr << endl << endl
<< "Function: like: picture x int x int x int x int" << endl
<< "The values calculated by " << endl
<< " second argument + third argument OR " << endl
<< " second argument - third argument " << endl
<< "must be in the interval [0, 100]." << endl
<< "Specified arguments: " << endl
<< " Second argument: " << p << endl
<< " Third argument: " << t << endl
<< " => 0<= " << p-t<<", "<< p+t <<" <= 100 " << endl << endl;
valid = false;
return false;
}
double percentageOfPixel = 0.0;
valid = true;
for ( int i=min; i<=max; i++ )
{
percentageOfPixel += histogram[i];
}
if (PA_DEBUG)
{
cerr << "[" << p-t << ", " << p+t << "], l:"
<< percentageOfPixel << endl;
cerr << " p-t <= percentageOfPixel: " <<
((p-t)<=percentageOfPixel) << endl;
cerr << " p+t >= percentageOfPixel: " <<
((p+t)>=percentageOfPixel) << endl;
}
if (( ((double)p-t) <= percentageOfPixel ) &&
( percentageOfPixel <= ((double)p+t) ))
{
return true;
}
return false;
}
/*
3.4.3 Operator ~Like~
This function checks whether ~p~ +- ~t~ percent of all pixel are in the
specified interval [~l~, ~u~]. The main differences of this method in
comparision with the method described in 3.4.2 are the specified real
values ~p~ and ~t~.
*/
bool Histogram::Like(double p, double t, int l, int u, bool& valid) {
if (PA_DEBUG) cerr << "Histogram::Like() called Type(Real)" << endl;
//
// Check the specified arguments
//
if (( p < 0.0 ) || ( p > 100.0 ))
{
cerr << endl << endl
<< "Function: like: picture x real x real x int x int" << endl
<< "The second argument must be in the interval "
<< "[0, 100]." << endl
<< "Specified argument: " << p << endl << endl;
valid = false;
return false;
}
if (( t < 0.0 ) || ( t > 100.0 ))
{
cerr << endl << endl
<< "Function: like: picture x real x real x int x int" << endl
<< "The third argument must be in the interval "
<< "[0, 100]." << endl
<< "Specified argument: " << t << endl << endl;
valid = false;
return false;
}
//
// Actually, I expect that l < u, but nevertheless, I'll check it.
//
int min = (l<u) ? l:u;
int max = (l<u) ? u:l;
if (( min < 0 ) || ( max > 255 ))
{
cerr << endl << endl
<< "Function: like: picture x int x int x int x int" << endl
<< "The fourth and fifth argument must be in the interval"
<< "[0, 255]." << endl
<< "Specified arguments: " << l << ", " << u << endl << endl;
valid = false;
return false;
}
if (( p-t < 0.0 ) || ( p+t > 100.0 ))
{
cerr << endl << endl
<< "Function: like: picture x real x real x int x int" << endl
<< "The values calculated by " << endl
<< " second argument + third argument OR " << endl
<< " second argument - third argument " << endl
<< "must be in the interval [0, 100]." << endl
<< "Specified arguments: " << endl
<< " Second argument: " << p << endl
<< " Third argument: " << t << endl
<< " => 0.0<= " << p-t<<", "<< p+t <<" <= 100.0 " << endl << endl;
valid = false;
return false;
}
double percentageOfPixel = 0.0;
valid = true;
for ( int i=min; i<=max; i++ )
{
percentageOfPixel += histogram[i];
}
if (PA_DEBUG)
{
cerr << "[" << p-t << ", " << p+t << "], l:"
<< percentageOfPixel << endl;
}
//
// query pic1 like [ 100,0, 0, 255 ] liefert false !!! Erwartet wurde
// True
//
cerr << " p-t <= percentageOfPixel: " <<
((p-t)<=percentageOfPixel) << endl;
cerr << " p+t >= percentageOfPixel: " <<
((p+t)>=percentageOfPixel) << endl;
if (( (p-t) <= percentageOfPixel ) && ( percentageOfPixel <= (p+t) ))
{
return true;
}
return false;
}
/*
3.4.4 Operator ~Contains~
This function checks whether a histogram based on absolute numbers of pixels
is dominated by another histogram.
*/
bool Histogram::Contains(int pixel_this, Histogram* h, int pixel_h) {
const int tol = 2;
bool isContained=true;
for( int i=0; i<=255; i++ )
{
// The values of this histogram must be greater or equal
// than the one which is tested to be contained.
int diff = histogram_abs[i] - h->histogram_abs[i];
if ( (diff * tol) < -4 ) {
cerr << "Histogram color=" << channel
<< ", diff=" << diff
<< ", index=" << i << endl;
isContained=false;
break;
}
}
return isContained;
}
/*
4 Nested list representaiton of class ~Histogram~
*/
static ListExpr OutHistogram(ListExpr typeInfo, Word value) {
if (PA_DEBUG) cerr << "OutHistogram() called" << endl;
Histogram * h = (Histogram*) value.addr;
if ( h->IsDefined() )
{
double * histoData = h->GetHistogramData();
ListExpr result = nl->OneElemList( nl->RealAtom( histoData[0]));
ListExpr histoDataList = result;
for ( int i=1; i<256; i++ )
{
histoDataList = nl->Append( histoDataList,
nl->RealAtom( histoData[i]) );
}
if (PA_DEBUG)
cerr << "MaxValue: " << h->GetHistogramMaxValue() << endl;
return( nl->ThreeElemList(
(int)nl->IntAtom(h->GetHistogramChannel()),
nl->RealAtom(h->GetHistogramMaxValue()),
result ));
}
return nl->SymbolAtom( "undef" );
}
static Word InHistogram(const ListExpr typeInfo,
const ListExpr instance,
const int errorPos,
ListExpr& errorInfo,
bool& correct) {
if (PA_DEBUG) cerr << "InHistogram() called" << endl;
double histoData[ 256 ];
for ( int i=0; i<256; i++ )
histoData[i] = 0.0;
ListExpr channel;
ListExpr maxValue;
ListExpr color;
if ( nl->ListLength(instance) == 3 )
{
//
// Get & check the channel !
//
channel = nl->First(instance);
if ( ! (nl->IsAtom( channel ) && (nl->AtomType(channel) == IntType )))
{
if (PA_DEBUG)
cerr << "InHistogram() channel as 'Int' expected"
<< endl;
correct = false;
return( SetWord(Address(0)));
}
//
// Get & check the channel !
//
maxValue = nl->Second(instance);
if ( !(nl->IsAtom( maxValue ) && (nl->AtomType(maxValue)==RealType)))
{
if (PA_DEBUG)
cerr << "InHistogram() maxValue as 'Real' expected"
<< endl;
correct = false;
return( SetWord(Address(0)));
}
//
// Get & check the histogram-data !
//
int index = 0;
ListExpr colorList = nl->Third( instance );
while ( ! nl->IsEmpty( colorList ) )
{
color = nl->First( colorList );
colorList = nl->Rest( colorList );
if ( ! (nl->IsAtom(color) && (nl->AtomType(color)==RealType)))
{
if (PA_DEBUG)
cerr << "InHistogram() colorNo. " << index
<< " as 'Int' expected" << endl;
correct = false;
return( SetWord(Address(0)));
}
histoData[ index ] = nl->RealValue(color);
index++;
}
}
else
{
if (PA_DEBUG)
cerr << "InHistogram() Wrong Number of Parameter! Got "
<< nl->ListLength( instance )
<< " parameter, but expected three." << endl;
correct = false;
return( SetWord(Address(0)));
}
correct = true;
return SetWord( new Histogram( histoData,
HistogramChannel(nl->IntValue( channel)),
nl->RealValue(maxValue) ));
}
/*
5 Description Signature Type Constructor of ~Histogram~
*/
static ListExpr HistogramProperty(void) {
return
nl->TwoElemList(
nl->FiveElemList(
nl->StringAtom("Signature"),
nl->StringAtom("Example Type List"),
nl->StringAtom("List Rep"),
nl->StringAtom("Example List"),
nl->StringAtom("Remarks")),
nl->FiveElemList(
nl->StringAtom("-> DATA"),
nl->StringAtom("histogram"),
nl->StringAtom(
"(<channel> <brightness_0> ... <brightness_255>)"),
nl->StringAtom(
"(0 0 0 1 2 .. 255 255)"),
nl->StringAtom("n/a")));
}
/*
6 Persistant storage of ~Histogram~
*/
static Word CreateHistogram(const ListExpr typeInfo) {
if (PA_DEBUG) cerr << "CreateHistogram() called" << endl;
Histogram* h = new Histogram();
return(SetWord( h ));
}
static void DeleteHistogram(const ListExpr typeInfo, Word& w) {
if (PA_DEBUG) cerr << "DeleteHistogram() called" << endl;
delete (Histogram*) w.addr;
w.addr = 0;
}
static void CloseHistogram(const ListExpr typeInfo, Word& w) {
if (PA_DEBUG) cerr << "CloseHistogram() called" << endl;
delete (Histogram *) w.addr;
w.addr = 0;
}
static Word CloneHistogram(const ListExpr typeInfo, const Word& w) {
if (PA_DEBUG) cerr << "CloneHistogram() called" << endl;
return SetWord(((Histogram*) w.addr)->Clone());
}
static int SizeOfHistogram(void) {
if (PA_DEBUG) cerr << "SizeOfHistogram() called" << endl;
return( sizeof(Histogram));
}
/*
7 Kind checking of ~Histogram~
*/
static bool CheckHistogram(ListExpr type, ListExpr& errorInfo) {
if (PA_DEBUG) cerr << "CheckHistogram() called" << endl;
return( nl->IsEqual( type, "histogram" ));
}
/*
8 Cast function of ~Histogram~
*/
static void* CastHistogram(void* addr) {
if (PA_DEBUG) cerr << "CastHistogram() called" << endl;
return new (addr) Histogram;
}
/*
9 Type constructor of ~Histogram~
*/
TypeConstructor* histogram = 0;
void initHistogram(){
histogram = new TypeConstructor(
"histogram", //name
HistogramProperty, //property function describing
// signature
OutHistogram, InHistogram, //Out and In functions
0, 0, //SaveToList and RestoreFromList
// functions
CreateHistogram, DeleteHistogram, //object creation and deletion
0, 0, //object open and save
CloseHistogram, CloneHistogram, //object close and clone
CastHistogram, //cast function
SizeOfHistogram, //sizeof function
CheckHistogram ); //kind checking function
}