1168 lines
34 KiB
C++
1168 lines
34 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 code related to creating
|
|
the Picture algebra itself. Code relating to the implementation of
|
|
SECONDO types ~picture~ and ~histogram~ are located in other modules.
|
|
|
|
2 Includes and other preparations
|
|
|
|
*/
|
|
|
|
#include "Algebra.h"
|
|
#include "QueryProcessor.h"
|
|
#include "PictureAlgebra.h"
|
|
#include "Symbols.h"
|
|
#include "StringUtils.h"
|
|
#include "hist_hsv.h"
|
|
#include "JPEGPicture.h"
|
|
|
|
using namespace std;
|
|
|
|
extern NestedList* nl;
|
|
extern QueryProcessor *qp;
|
|
|
|
/*
|
|
|
|
3 Generic $picture\to scalar$ type mapping function
|
|
|
|
Multiple SECONDO operators map a ~picture~ object to ~int~, ~bool~ or
|
|
~string~. The following function template is used as an abbreviated way
|
|
to provide the respective type mapping function.
|
|
|
|
The ~enum~ is used to determine the actual return type of the type mapping
|
|
function.
|
|
|
|
*/
|
|
|
|
enum Picture2ScalarTypeMapReturnType { P2STM_INT, P2STM_BOOL, P2STM_STRING };
|
|
|
|
template<Picture2ScalarTypeMapReturnType returnType>
|
|
static ListExpr Picture2ScalarTypeMap(ListExpr args) {
|
|
if (PA_DEBUG)
|
|
cerr << "Picture2ScalarTypeMap() called with returnType="
|
|
<< returnType
|
|
<< endl;
|
|
|
|
if (PA_DEBUG)
|
|
cerr << "Picture2ScalarTypeMap() nl->ListLength(args)="
|
|
<< nl->ListLength(args)
|
|
<< endl;
|
|
if (PA_DEBUG)
|
|
cerr << "Picture2ScalarTypeMap() nl->First(args)="
|
|
<< nl->First(args)
|
|
<< endl;
|
|
|
|
if (nl->ListLength(args) == 1) {
|
|
if (nl->IsEqual(nl->First(args), Picture::BasicType())) {
|
|
if (PA_DEBUG) cerr << "Picture2ScalarTypeMap() #1" << endl;
|
|
|
|
if (returnType == P2STM_INT)
|
|
return nl->SymbolAtom(CcInt::BasicType());
|
|
else if (returnType == P2STM_BOOL)
|
|
return nl->SymbolAtom(CcBool::BasicType());
|
|
else
|
|
return nl->SymbolAtom(CcString::BasicType());
|
|
} else {
|
|
if (PA_DEBUG) cerr << "Picture2ScalarTypeMap() #2" << endl;
|
|
|
|
string lexpr;
|
|
nl->WriteToString(lexpr, nl->First(args));
|
|
ErrorReporter::ReportError(
|
|
"expected 'picture' argument but received '"+lexpr+"'");
|
|
}
|
|
} else
|
|
ErrorReporter::ReportError(
|
|
"expected only one argument but received "
|
|
+ stringutils::int2str(nl->ListLength(args)));
|
|
|
|
return nl->SymbolAtom(Symbol::TYPEERROR());
|
|
}
|
|
|
|
/*
|
|
|
|
4 Operator specifications
|
|
|
|
*/
|
|
|
|
static const string pictureWidthSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture -> int</text--->"
|
|
"<text>_ getWidth</text--->"
|
|
"<text>Return width of JPEG picture.</text--->"
|
|
"<text>pic getWidth</text--->"
|
|
") )";
|
|
|
|
static const string pictureHeightSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture -> int</text--->"
|
|
"<text>_ getHeight</text--->"
|
|
"<text>Return height of JPEG picture.</text--->"
|
|
"<text>pic getHeight</text--->"
|
|
") )";
|
|
|
|
static const string pictureIsGrayscaleSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture -> bool</text--->"
|
|
"<text>_ isgrayscale</text--->"
|
|
"<text>Returns TRUE if JPEG picture is grayscale.</text--->"
|
|
"<text>pic grayscale</text--->"
|
|
") )";
|
|
|
|
static const string pictureFilenameSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture -> string</text--->"
|
|
"<text>_ getFilename</text--->"
|
|
"<text>Returns the filename of the JPEG picture.</text--->"
|
|
"<text>pic getFilename</text--->"
|
|
") )";
|
|
|
|
static const string pictureCategorySpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture -> string</text--->"
|
|
"<text>_ getCategory</text--->"
|
|
"<text>Returns the category of the JPEG picture.</text--->"
|
|
"<text>pic getCategory</text--->"
|
|
") )";
|
|
|
|
static const string pictureDateSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture -> instant</text--->"
|
|
"<text>_ getPictureDate</text--->"
|
|
"<text>Returns the date of the JPEG picture.</text--->"
|
|
"<text>pic getPictureDate</text--->"
|
|
") )";
|
|
|
|
static const string pictureIsPortraitSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture -> bool</text--->"
|
|
"<text>_ isportrait</text--->"
|
|
"<text>Returns TRUE if picture has portrait format.</text--->"
|
|
"<text>pic isportrait</text--->"
|
|
") )";
|
|
|
|
static const string pictureColordistSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture int -> histogram</text--->"
|
|
"<text>_ colordist [ _ ]</text--->"
|
|
"<text>Calculate specified histogram for picture.</text--->"
|
|
"<text>pic colordist [ 0 ]</text--->"
|
|
") )";
|
|
|
|
static const string pictureEqualsSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture picture int int -> real</text--->"
|
|
"<text>p1 p2 equals [ n, t ]</text--->"
|
|
"<text>Returns 0 if pictures are 'similar' in the sense "
|
|
"that abs( avg_i^i+n(p1_hist[i]) - avg_i^[i+n](p2_hist[i])) < t/10000 "
|
|
"If this tolerance is exceeded the sum of all "
|
|
"aberrations will be calculated.</text--->"
|
|
"<text>pic1 pic2 equals [ 5, 100 ]</text--->"
|
|
") )";
|
|
|
|
static const string pictureContainsSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture picture -> bool</text--->"
|
|
"<text>p1 contains p2</text--->"
|
|
"<text>Returns TRUE if the red, green, and blue histogram "
|
|
"curves based on absolute numbers of pixels of p1 are an upper boundary "
|
|
"for the respective curves of p2. This can be used to filter "
|
|
"out candidates "
|
|
"which may contain p2. </text--->"
|
|
"<text>pic1 contains pic2</text--->"
|
|
") )";
|
|
|
|
|
|
static const string pictureSimpleEqualsSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture picture-> bool</text--->"
|
|
"<text>_ sequals _</text--->"
|
|
"<text>Returns TRUE if pictures are identical.</text--->"
|
|
"<text>pic1 equals pic2</text--->"
|
|
") )";
|
|
|
|
static const string pictureLikeSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture int int int int -> bool, "
|
|
"picture real real int int -> bool</text--->"
|
|
"<text>_ like [ _, _, _, _ ]</text--->"
|
|
"<text>TRUE if picture is 'similar' to parameters.</text--->"
|
|
"<text>pic like [ 50, 5, 100, 200 ], "
|
|
"pic like [ 50.0, 5.0, 100, 200 ]</text--->"
|
|
") )";
|
|
|
|
static const string pictureCutSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture int int int int -> picture</text--->"
|
|
"<text>_ cut [ _, _, _, _ ]</text--->"
|
|
"<text>Cut area with specified x, y, width, height.</text--->"
|
|
"<text>pic cut [ 100, 100, 400, 200 ] </text--->"
|
|
") )";
|
|
|
|
static const string pictureScaleSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture int int int int -> picture</text--->"
|
|
"<text>_ scale [ _, _ ]</text--->"
|
|
"<text>Scale picture to specified width and height.</text--->"
|
|
"<text>pic scale [ 800, 533 ] </text--->"
|
|
") )";
|
|
|
|
static const string pictureFlipleftSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture int -> picture</text--->"
|
|
"<text>_ flipleft [ _ ]</text--->"
|
|
"<text>Performs 90 degrees left turns on picture.</text--->"
|
|
"<text>pic flipleft [ 1 ] </text--->"
|
|
") )";
|
|
|
|
static const string pictureMirrorSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture bool -> picture</text--->"
|
|
"<text>_ mirror [ _ ]</text--->"
|
|
"<text>Mirror picture vertically or horizontally.</text--->"
|
|
"<text>pic mirror [ TRUE ] </text--->"
|
|
") )";
|
|
|
|
static const string pictureDisplaySpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture -> bool</text--->"
|
|
"<text>_ display</text--->"
|
|
"<text>Display image, return TRUE on success.</text--->"
|
|
"<text>pic display</text--->"
|
|
") )";
|
|
|
|
static const string pictureExportSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>picture text -> bool</text--->"
|
|
"<text>_ export [ _ ]</text--->"
|
|
"<text>Save picture to file, return TRUE on success.</text--->"
|
|
"<text>pic export [ \"/tmp/schmuh.jpg\" ]</text--->"
|
|
") )";
|
|
|
|
|
|
|
|
static const string pictureImportpictureSpec =
|
|
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
|
|
"( <text>text -> picture</text--->"
|
|
"<text>importPicture( text )</text--->"
|
|
"<text>Load jpeg-picture from file, returns a picture on success. "
|
|
"In the other case the result is undefined. </text--->"
|
|
"<text>importPicture( \"/tmp/schmuh.jpg\" ]</text--->"
|
|
") )";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
5 External declarations
|
|
|
|
Numerous functions and the type constructors are implemented in other modules
|
|
for better structure. As these are used in this module only, we do not
|
|
provide these declarations in PictureAlgebra.h but directly in this section.
|
|
|
|
Each of the following sub-sections contain the declarations for one module.
|
|
|
|
5.1 Implemented in ~PictureAlgebra\_pictimp.cpp~
|
|
|
|
*/
|
|
|
|
ListExpr PictureDateTypeMap(ListExpr args);
|
|
ListExpr PictureExportTypeMap(ListExpr args);
|
|
ListExpr PictureSimpleEqualsTypeMap(ListExpr args);
|
|
ListExpr PictureImportpictureTypeMap(ListExpr args);
|
|
|
|
int PictureFilenameValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
int PictureCategoryValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
int PictureDateValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
int PictureIsPortraitValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
int PictureDisplayValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
int PictureExportValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
int PictureSimpleEqualsValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
|
|
|
|
int PictureImportpictureValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
|
|
|
|
|
|
extern TypeConstructor* picture;
|
|
extern void initPicture();
|
|
|
|
/*
|
|
|
|
5.2 Implemented in ~PictureAlgebra\_attrops.cpp~
|
|
|
|
*/
|
|
|
|
extern int PictureWidthValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
extern int PictureHeightValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
extern int PictureIsGrayscaleValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
|
|
/*
|
|
|
|
5.3 Implemented in ~PictureAlgebra\_histimp.cpp~
|
|
|
|
*/
|
|
|
|
extern TypeConstructor* histogram;
|
|
extern void initHistogram();
|
|
|
|
/*
|
|
|
|
5.4 Implemented in ~PictureAlgebra\_histops.cpp~
|
|
|
|
*/
|
|
|
|
extern ListExpr PictureColordistTypeMap(ListExpr args);
|
|
extern ListExpr PictureEqualsTypeMap(ListExpr args);
|
|
extern ListExpr PictureLikeTypeMap(ListExpr args);
|
|
|
|
extern int PictureColordistValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
extern int PictureEqualsValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
|
|
extern int PictureContainsValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
|
|
|
|
extern ValueMapping pictureLikeValueMap[];
|
|
|
|
extern int PictureLikeSelect(ListExpr args);
|
|
|
|
|
|
/*
|
|
|
|
5.5 Implemented in ~PictureAlgebra\_graphops.cpp~
|
|
|
|
*/
|
|
|
|
extern ListExpr PictureScaleTypeMap(ListExpr args);
|
|
extern ListExpr PictureCutTypeMap(ListExpr args);
|
|
extern ListExpr PictureFlipleftTypeMap(ListExpr args);
|
|
extern ListExpr PictureMirrorTypeMap(ListExpr args);
|
|
|
|
extern int PictureCutValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
extern int PictureScaleValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
extern int PictureFlipleftValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
extern int PictureMirrorValueMap(Word* args,
|
|
Word& result,
|
|
int message,
|
|
Word& local,
|
|
Supplier s);
|
|
|
|
/*
|
|
|
|
6 Operator creation
|
|
|
|
The dummy selection function ~SimpleSelect()~ is required for non-overloaded
|
|
operators.
|
|
|
|
*/
|
|
|
|
static int SimpleSelect(ListExpr args) {
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
|
|
The creation of the actual operators follows. Operator ~like~
|
|
is overloaded.
|
|
|
|
*/
|
|
|
|
static Operator height(
|
|
"getHeight", //name
|
|
pictureHeightSpec, //specification
|
|
PictureHeightValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
Picture2ScalarTypeMap<P2STM_INT> //type mapping
|
|
);
|
|
|
|
static Operator width(
|
|
"getWidth", //name
|
|
pictureWidthSpec, //specification
|
|
PictureWidthValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
Picture2ScalarTypeMap<P2STM_INT> //type mapping
|
|
);
|
|
|
|
static Operator isgrayscale(
|
|
"isgrayscale", //name
|
|
pictureIsGrayscaleSpec, //specification
|
|
PictureIsGrayscaleValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
Picture2ScalarTypeMap<P2STM_BOOL> //type mapping
|
|
);
|
|
|
|
static Operator filename(
|
|
"getFilename", //name
|
|
pictureFilenameSpec, //specification
|
|
PictureFilenameValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
Picture2ScalarTypeMap<P2STM_STRING> //type mapping
|
|
);
|
|
|
|
static Operator category(
|
|
"getCategory", //name
|
|
pictureCategorySpec, //specification
|
|
PictureCategoryValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
Picture2ScalarTypeMap<P2STM_STRING> //type mapping
|
|
);
|
|
|
|
static Operator date(
|
|
"getPictureDate", //name
|
|
pictureDateSpec, //specification
|
|
PictureDateValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
PictureDateTypeMap //type mapping
|
|
);
|
|
|
|
static Operator isportrait(
|
|
"isportrait" , //name
|
|
pictureIsPortraitSpec, //specification
|
|
PictureIsPortraitValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
Picture2ScalarTypeMap<P2STM_BOOL> //type mapping
|
|
);
|
|
|
|
static Operator colordist(
|
|
"colordist", //name
|
|
pictureColordistSpec, //specification
|
|
PictureColordistValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
PictureColordistTypeMap //type mapping
|
|
);
|
|
|
|
static Operator simpleequals(
|
|
"simpleequals", //name
|
|
pictureSimpleEqualsSpec, //specification
|
|
PictureSimpleEqualsValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
PictureSimpleEqualsTypeMap //type mapping
|
|
);
|
|
|
|
static Operator equals(
|
|
"equals", //name
|
|
pictureEqualsSpec, //specification
|
|
PictureEqualsValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
PictureEqualsTypeMap //type mapping
|
|
);
|
|
|
|
static Operator containsOp(
|
|
"contains", //name
|
|
pictureContainsSpec, //specification
|
|
PictureContainsValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
PictureSimpleEqualsTypeMap //type mapping
|
|
);
|
|
|
|
|
|
static Operator like(
|
|
"like", //name
|
|
pictureLikeSpec, //specification
|
|
2, //number of overloaded functions
|
|
pictureLikeValueMap, //value mapping
|
|
PictureLikeSelect, //value mapping selection function
|
|
PictureLikeTypeMap //type mapping
|
|
);
|
|
|
|
static Operator scale(
|
|
"scale", //name
|
|
pictureScaleSpec, //specification
|
|
PictureScaleValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
PictureScaleTypeMap //type mapping
|
|
);
|
|
|
|
static Operator cut(
|
|
"cut", //name
|
|
pictureCutSpec, //specification
|
|
PictureCutValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
PictureCutTypeMap //type mapping
|
|
);
|
|
|
|
static Operator flipleft(
|
|
"flipleft", //name
|
|
pictureFlipleftSpec, //specification
|
|
PictureFlipleftValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
PictureFlipleftTypeMap //type mapping
|
|
);
|
|
|
|
static Operator mirror(
|
|
"mirror", //name
|
|
pictureMirrorSpec, //specification
|
|
PictureMirrorValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
PictureMirrorTypeMap //type mapping
|
|
);
|
|
|
|
static Operator display(
|
|
"display", //name
|
|
pictureDisplaySpec, //specification
|
|
PictureDisplayValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
Picture2ScalarTypeMap<P2STM_BOOL> //type mapping
|
|
);
|
|
|
|
static Operator exportop(
|
|
"export", //name
|
|
pictureExportSpec, //specification
|
|
PictureExportValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
PictureExportTypeMap //type mapping
|
|
);
|
|
|
|
|
|
|
|
static Operator importpictureop(
|
|
"importPicture", //name
|
|
pictureImportpictureSpec, //specification
|
|
PictureImportpictureValueMap, //value mapping
|
|
SimpleSelect, //mapping selection function
|
|
PictureImportpictureTypeMap //type mapping
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
hsv histograms
|
|
|
|
*/
|
|
|
|
GenTC<hist_hsv<8,false> > hist_hsv8;
|
|
GenTC<hist_hsv<16, false> > hist_hsv16;
|
|
GenTC<hist_hsv<32, false> > hist_hsv32;
|
|
GenTC<hist_hsv<64, false> > hist_hsv64;
|
|
GenTC<hist_hsv<128, false> > hist_hsv128;
|
|
GenTC<hist_hsv<256, false> > hist_hsv256;
|
|
GenTC<hist_hsv<256, true> > hist_lab256;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Operators on hsv histograms
|
|
|
|
*/
|
|
|
|
ListExpr distanceTM(ListExpr args){
|
|
string err = "hist_hsvD x hist_hsvD expected";
|
|
if(!nl->HasLength(args,2)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
if(!nl->Equal(nl->First(args), nl->Second(args))){
|
|
return listutils::typeError(err + " (argument types differ)");
|
|
}
|
|
ListExpr a1 = nl->First(args);
|
|
if( !hist_hsv<8, false>::checkType(a1)
|
|
&& !hist_hsv<16, false>::checkType(a1)
|
|
&& !hist_hsv<32, false>::checkType(a1)
|
|
&& !hist_hsv<64, false>::checkType(a1)
|
|
&& !hist_hsv<128, false>::checkType(a1)
|
|
&& !hist_hsv<256, false>::checkType(a1)
|
|
&& !hist_hsv<256, true>::checkType(a1)){
|
|
return listutils::typeError(err);
|
|
}
|
|
return listutils::basicSymbol<CcReal>();
|
|
}
|
|
|
|
|
|
template<unsigned int dim, bool lab>
|
|
int distanceVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
|
|
hist_hsv<dim, lab>* a1 = (hist_hsv<dim, lab>*) args[0].addr;
|
|
hist_hsv<dim, lab>* a2 = (hist_hsv<dim, lab>*) args[1].addr;
|
|
result = qp->ResultStorage(s);
|
|
CcReal* res = (CcReal*) result.addr;
|
|
bool d;
|
|
double dist;
|
|
a1->distance(*a2,d,dist);
|
|
res->Set(d,dist);
|
|
return 0;
|
|
}
|
|
|
|
ValueMapping distanceVM[] = {
|
|
distanceVMT<8, false>,
|
|
distanceVMT<16, false>,
|
|
distanceVMT<32, false>,
|
|
distanceVMT<64, false>,
|
|
distanceVMT<128, false>,
|
|
distanceVMT<256, false>,
|
|
distanceVMT<256, true>,
|
|
};
|
|
|
|
int distanceSelect(ListExpr args){
|
|
ListExpr a1 = nl->First(args);
|
|
if(hist_hsv<8, false>::checkType(a1)) return 0;
|
|
if(hist_hsv<16, false>::checkType(a1)) return 1;
|
|
if(hist_hsv<32, false>::checkType(a1)) return 2;
|
|
if(hist_hsv<64, false>::checkType(a1)) return 3;
|
|
if(hist_hsv<128, false>::checkType(a1)) return 4;
|
|
if(hist_hsv<256, false>::checkType(a1)) return 5;
|
|
if(hist_hsv<256, true>::checkType(a1)) return 6;
|
|
return -1;
|
|
}
|
|
|
|
OperatorSpec distanceSpec(
|
|
"hist_hsvD x hist_hsvD -> real",
|
|
"distance(_,_)",
|
|
"computes the distances between two hsv histograms",
|
|
"query distance(getHSV8(theater) , getHSV8(paper)"
|
|
);
|
|
|
|
Operator distanceOp(
|
|
"distance",
|
|
distanceSpec.getStr(),
|
|
7,
|
|
distanceVM,
|
|
distanceSelect,
|
|
distanceTM
|
|
);
|
|
|
|
|
|
|
|
template<unsigned int dim, bool lab>
|
|
ListExpr getHistHsvTM(ListExpr args){
|
|
string err = "picture expected";
|
|
if(!nl->HasLength(args,1)){
|
|
return listutils::typeError(err + " (wrong number of args)");
|
|
}
|
|
if(!Picture::checkType(nl->First(args))){
|
|
return listutils::typeError(err);
|
|
}
|
|
return listutils::basicSymbol<hist_hsv<dim, lab> >();
|
|
|
|
}
|
|
|
|
class HSV{
|
|
|
|
public:
|
|
HSV(unsigned char r, unsigned char g, unsigned char b){
|
|
|
|
unsigned char rgbMin = std::min (std::min (r, g), b);
|
|
unsigned char rgbMax = std::max (std::max (r, g), b);
|
|
unsigned char delta = rgbMax - rgbMin;
|
|
|
|
// compute h
|
|
if (delta == 0) {
|
|
h = 0;
|
|
} else {
|
|
if (rgbMax == r) {
|
|
h = 60 * (g - b) / delta;
|
|
} else if (rgbMax == g) {
|
|
h = 120 * (g - b) / delta;
|
|
} else { // rgbMax == b
|
|
h = 240 * (g - b) / delta;
|
|
}
|
|
}
|
|
|
|
if (h < 0){
|
|
h += 360;
|
|
}
|
|
|
|
// compute s
|
|
if (rgbMax == 0)
|
|
s = 0;
|
|
else
|
|
s = 255 * delta / rgbMax;
|
|
|
|
// compute v
|
|
v = rgbMax;
|
|
|
|
}
|
|
|
|
int h;
|
|
int s;
|
|
int v;
|
|
};
|
|
|
|
|
|
unsigned* pictureLabOffsetTable = nullptr;
|
|
|
|
|
|
class Lab{
|
|
public:
|
|
Lab (unsigned char r_, unsigned char g_, unsigned char b_){
|
|
double R, G, B;
|
|
double rd = (double) r_ / 255;
|
|
double gd = (double) g_ / 255;
|
|
double bd = (double) b_ / 255;
|
|
|
|
if (rd > 0.04045)
|
|
R = std::pow((rd + 0.055) / 1.055, 2.2);
|
|
else
|
|
R = rd / 12.92;
|
|
|
|
if (gd > 0.04045)
|
|
G = std::pow ((gd + 0.055) / 1.055, 2.2);
|
|
else
|
|
G = gd / 12.92;
|
|
|
|
if (bd > 0.04045)
|
|
B = std::pow ((bd + 0.055) / 1.055, 2.2);
|
|
else
|
|
B = bd / 12.92;
|
|
|
|
// compute X,Y,Z coordinates of r,g,b
|
|
double X = 0.4124 * R + 0.3576 * G + 0.1805 * B;
|
|
double Y = 0.2127 * R + 0.7152 * G + 0.0722 * B;
|
|
double Z = 0.0193 * R + 0.1192 * G + 0.9500 * B;
|
|
|
|
/* used chromacity coordinates of whitepoint D65:
|
|
x = 0.312713, y = 0.329016
|
|
|
|
the respective XYZ coordinates are
|
|
Y = 1,
|
|
X = Y * x / y = 0.9504492183, and
|
|
Z = Y * (1-x-y) / y = 1.0889166480
|
|
*/
|
|
double eps = 0.008856; // = 216 / 24389
|
|
double x = X / 0.95045;
|
|
double y = Y;
|
|
double z = Z / 1.08892;
|
|
long double fx, fy, fz;
|
|
|
|
if (x > eps)
|
|
fx = std::pow (x, 0.333333);
|
|
else
|
|
fx = 7.787 * x + 0.137931;
|
|
|
|
if (y > eps)
|
|
fy = std::pow (y, 0.333333);
|
|
else
|
|
fy = 7.787 * y + 0.137931;
|
|
|
|
if (z > eps)
|
|
fz = std::pow (z, 0.333333);
|
|
else
|
|
fz = 7.787 * z + 0.137931;
|
|
|
|
// compute Lab coordinates
|
|
double Lab_Ld = ((116 * fy) - 16);
|
|
double Lab_ad = (500 * (fx - fy));
|
|
double Lab_bd = (200 * (fy - fz));
|
|
|
|
L = (signed char) Lab_Ld;
|
|
a = (signed char) Lab_ad;
|
|
b = (signed char) Lab_bd;
|
|
}
|
|
|
|
|
|
signed char L, a, b;
|
|
};
|
|
|
|
void initLabOffsetTable(){
|
|
|
|
if(pictureLabOffsetTable != nullptr) {
|
|
return;
|
|
}
|
|
|
|
pictureLabOffsetTable = new unsigned[64*64*64];
|
|
for(signed char r = 0; r < 64; r++)
|
|
for(signed char g = 0; g < 64; g++)
|
|
for(signed char b = 0; b < 64; b++) {
|
|
Lab lab (2 + (r*4), 2 + (g*4), 2 + (b*4));
|
|
|
|
// map values [0, 99] x [-86, 98] x [-107,94] to
|
|
// [0, 3] x [0, 7] x [0, 7] (4 x 8 x 8 = 256 bins)
|
|
int L_offset = (int) (lab.L / 25);
|
|
int a_offset = (int) ((lab.a + 86) / 23.125);
|
|
int b_offset = (int) ((lab.b + 107) / 25.1);
|
|
pictureLabOffsetTable[r*4096 + g*64 + b] =
|
|
64 * L_offset + 8 * a_offset + b_offset;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int getHSVIndex(int h, int s, int v, int dim){
|
|
if(dim==8){
|
|
int h_offset = h / 180; // 2 parts
|
|
int s_offset = s / 128; // 2 parts
|
|
int v_offset = v / 256; // 2 parts
|
|
return 4*h_offset + 2*s_offset + v_offset;
|
|
}
|
|
|
|
if(dim==16){
|
|
int h_offset = h / 90; // 4 parts
|
|
int s_offset = s / 128; // 2 parts
|
|
int v_offset = v / 256; // 2 parts
|
|
return 4*h_offset + 2*s_offset + v_offset;
|
|
}
|
|
|
|
if(dim==32){
|
|
int h_offset = h / 90; // 4 parts
|
|
int s_offset = s / 128; // 2 parts
|
|
int v_offset = v / 128; // 4 parts
|
|
return 8*h_offset + 4*s_offset + v_offset;
|
|
}
|
|
|
|
if(dim == 64){
|
|
int h_offset = h / 90; // 4 parts
|
|
int s_offset = s / 64; // 4 parts
|
|
int v_offset = v / 128; // 4 parts
|
|
return 16*h_offset + 4*s_offset + v_offset;
|
|
|
|
}
|
|
|
|
if(dim==128){
|
|
int h_offset = h / 45; // 8 parts
|
|
int s_offset = s / 64; // 4 parts
|
|
int v_offset = v / 128; // 4 parts
|
|
return 16*h_offset + 4*s_offset + v_offset;
|
|
|
|
}
|
|
|
|
if(dim==256){
|
|
int h_offset = (int) (h / 22.5); // 16 parts
|
|
int s_offset = s / 64; // 4 parts
|
|
int v_offset = v / 128; // 4 parts
|
|
unsigned int res = 16*h_offset + 4*s_offset + v_offset;
|
|
return res;
|
|
}
|
|
assert(false);
|
|
return 0;
|
|
}
|
|
|
|
|
|
template<unsigned int dim, bool lab>
|
|
void getHistHsv(Picture* picture, hist_hsv<dim, lab>* hist){
|
|
if(!picture->IsDefined()){
|
|
hist->SetDefined(false);
|
|
return;
|
|
}
|
|
unsigned long size;
|
|
const char* imgdata = picture->GetJPEGData (size);
|
|
JPEGPicture rgb ((unsigned char *) imgdata, size);
|
|
|
|
initLabOffsetTable();
|
|
|
|
unsigned long int rgbSize;
|
|
unsigned char* rgbData = rgb.GetImageData (rgbSize);
|
|
|
|
const unsigned int numOfPixels = rgbSize / 3;
|
|
|
|
unsigned long hist_abs[dim];
|
|
|
|
for (unsigned int i = 0; i < dim; ++i){
|
|
hist_abs[i] = 0;
|
|
}
|
|
|
|
for (unsigned long pos = 0; pos < (numOfPixels); ++pos) {
|
|
unsigned char r = rgbData[ (3*pos) ];
|
|
unsigned char g = rgbData[ (3*pos) +1];
|
|
unsigned char b = rgbData[ (3*pos) +2];
|
|
unsigned int index;
|
|
if(lab){
|
|
index = pictureLabOffsetTable[ ((r/4)*4096) + ((g/4)*64) + b/4];
|
|
} else {
|
|
HSV hsv (r, g, b);
|
|
index = getHSVIndex(hsv.h, hsv.s, hsv.v, dim);
|
|
}
|
|
++hist_abs[index];
|
|
}
|
|
|
|
delete[] imgdata;
|
|
|
|
hist->set(hist_abs, numOfPixels);
|
|
}
|
|
|
|
|
|
template<unsigned int dim,bool lab>
|
|
int getHistHsvVMT(Word* args, Word& result, int message,
|
|
Word& local, Supplier s){
|
|
Picture* arg = (Picture*) args[0].addr;
|
|
result = qp->ResultStorage(s);
|
|
hist_hsv<dim, lab>* res = (hist_hsv<dim, lab>*) result.addr;
|
|
getHistHsv<dim,lab>(arg, res);
|
|
return 0;
|
|
}
|
|
|
|
OperatorSpec getHistHsv8Spec(
|
|
"picture -> hist_hsv8",
|
|
"getHistHsv8(_)",
|
|
"computes a histogram from a picture",
|
|
"query getHistHsv8(paper)"
|
|
);
|
|
|
|
OperatorSpec getHistHsv16Spec(
|
|
"picture -> hist_hsv16",
|
|
"getHistHsv16(_)",
|
|
"computes a histogram from a picture",
|
|
"query getHistHsv16(paper)"
|
|
);
|
|
|
|
OperatorSpec getHistHsv32Spec(
|
|
"picture -> hist_hsv32",
|
|
"getHistHsv32(_)",
|
|
"computes a histogram from a picture",
|
|
"query getHistHsv32(paper)"
|
|
);
|
|
|
|
OperatorSpec getHistHsv64Spec(
|
|
"picture -> hist_hsv64",
|
|
"getHistHsv64(_)",
|
|
"computes a histogram from a picture",
|
|
"query getHistHsv64(paper)"
|
|
);
|
|
|
|
OperatorSpec getHistHsv128Spec(
|
|
"picture -> hist_hsv128",
|
|
"getHistHsv8(_)",
|
|
"computes a histogram from a picture",
|
|
"query getHistHsv128(paper)"
|
|
);
|
|
|
|
OperatorSpec getHistHsv256Spec(
|
|
"picture -> hist_hsv256",
|
|
"getHistHsv256(_)",
|
|
"computes a histogram from a picture",
|
|
"query getHistHsv256(paper)"
|
|
);
|
|
|
|
OperatorSpec getHistLab256Spec(
|
|
"picture -> hist_lab_256",
|
|
"getHistLab256(_)",
|
|
"computes a histogram from a picture",
|
|
"query getHistLab256(paper)"
|
|
);
|
|
|
|
Operator getHistHsv8Op(
|
|
"getHistHsv8",
|
|
getHistHsv8Spec.getStr(),
|
|
getHistHsvVMT<8, false>,
|
|
Operator::SimpleSelect,
|
|
getHistHsvTM<8, false>
|
|
);
|
|
|
|
Operator getHistHsv16Op(
|
|
"getHistHsv16",
|
|
getHistHsv16Spec.getStr(),
|
|
getHistHsvVMT<16, false>,
|
|
Operator::SimpleSelect,
|
|
getHistHsvTM<16, false>
|
|
);
|
|
|
|
Operator getHistHsv32Op(
|
|
"getHistHsv32",
|
|
getHistHsv32Spec.getStr(),
|
|
getHistHsvVMT<32, false>,
|
|
Operator::SimpleSelect,
|
|
getHistHsvTM<32, false>
|
|
);
|
|
|
|
Operator getHistHsv64Op(
|
|
"getHistHsv64",
|
|
getHistHsv64Spec.getStr(),
|
|
getHistHsvVMT<64, false>,
|
|
Operator::SimpleSelect,
|
|
getHistHsvTM<64, false>
|
|
);
|
|
|
|
Operator getHistHsv128Op(
|
|
"getHistHsv128",
|
|
getHistHsv128Spec.getStr(),
|
|
getHistHsvVMT<128, false>,
|
|
Operator::SimpleSelect,
|
|
getHistHsvTM<128, false>
|
|
);
|
|
|
|
Operator getHistHsv256Op(
|
|
"getHistHsv256",
|
|
getHistHsv256Spec.getStr(),
|
|
getHistHsvVMT<256, false>,
|
|
Operator::SimpleSelect,
|
|
getHistHsvTM<256, false>
|
|
);
|
|
|
|
Operator getHistLab256Op(
|
|
"getHistLab256",
|
|
getHistLab256Spec.getStr(),
|
|
getHistHsvVMT<256, true>,
|
|
Operator::SimpleSelect,
|
|
getHistHsvTM<256, true>
|
|
);
|
|
|
|
/*
|
|
|
|
7 Algebra creation and initialisation
|
|
|
|
*/
|
|
|
|
class PictureAlgebra: public Algebra {
|
|
public:
|
|
PictureAlgebra() : Algebra() {
|
|
if (PA_DEBUG) cerr << "initializing PictureAlgebra" << endl;
|
|
initPicture();
|
|
AddTypeConstructor(picture);
|
|
initHistogram();
|
|
AddTypeConstructor(histogram);
|
|
|
|
picture->AssociateKind(Kind::DATA());
|
|
histogram->AssociateKind(Kind::DATA());
|
|
|
|
AddTypeConstructor(&hist_hsv8);
|
|
AddTypeConstructor(&hist_hsv16);
|
|
AddTypeConstructor(&hist_hsv32);
|
|
AddTypeConstructor(&hist_hsv64);
|
|
AddTypeConstructor(&hist_hsv128);
|
|
AddTypeConstructor(&hist_hsv256);
|
|
AddTypeConstructor(&hist_lab256);
|
|
|
|
hist_hsv8.AssociateKind(Kind::DATA());
|
|
hist_hsv16.AssociateKind(Kind::DATA());
|
|
hist_hsv32.AssociateKind(Kind::DATA());
|
|
hist_hsv64.AssociateKind(Kind::DATA());
|
|
hist_hsv128.AssociateKind(Kind::DATA());
|
|
hist_hsv256.AssociateKind(Kind::DATA());
|
|
hist_lab256.AssociateKind(Kind::DATA());
|
|
|
|
AddOperator(&height);
|
|
AddOperator(&width);
|
|
AddOperator(&isgrayscale);
|
|
AddOperator(&filename);
|
|
AddOperator(&category);
|
|
AddOperator(&date);
|
|
AddOperator(&isportrait);
|
|
AddOperator(&colordist);
|
|
AddOperator(&equals);
|
|
AddOperator(&containsOp);
|
|
AddOperator(&simpleequals);
|
|
AddOperator(&like);
|
|
AddOperator(&scale);
|
|
AddOperator(&cut);
|
|
AddOperator(&flipleft);
|
|
AddOperator(&mirror);
|
|
AddOperator(&display);
|
|
AddOperator(&exportop);
|
|
|
|
AddOperator(&distanceOp);
|
|
AddOperator(&getHistHsv8Op);
|
|
AddOperator(&getHistHsv16Op);
|
|
AddOperator(&getHistHsv32Op);
|
|
AddOperator(&getHistHsv64Op);
|
|
AddOperator(&getHistHsv128Op);
|
|
AddOperator(&getHistHsv256Op);
|
|
AddOperator(&getHistLab256Op);
|
|
|
|
AddOperator(&importpictureop);
|
|
}
|
|
|
|
~PictureAlgebra() {
|
|
if(pictureLabOffsetTable != nullptr) {
|
|
delete[] pictureLabOffsetTable;
|
|
pictureLabOffsetTable = nullptr;
|
|
}
|
|
}
|
|
};
|
|
|
|
extern "C"
|
|
Algebra* InitializePictureAlgebra(NestedList* nlPar, QueryProcessor *qpPar) {
|
|
nl = nlPar;
|
|
qp = qpPar;
|
|
// cerr << "sizeof(Histogram) = " << sizeof(Histogram) << endl;
|
|
// cerr << "sizeof(Picture) = " << sizeof(Picture) << endl;
|
|
return new PictureAlgebra();
|
|
}
|