Nach dem Katalogisieren von Abbildern können Sie ein oder mehrere Abbilder nach Inhalt abfragen. Wenn Sie ein Abbild nach Inhalt abfragen, identifizieren Sie die Eingabe für die Abfrage und eine Zielgruppe von katalogisierten Abbildern. Sie können die Eingabe in einer Abfragezeichenfolge (siehe Abfragezeichenfolge angeben) oder in einem Abfrageobjekt (siehe Abfrageobjekt verwenden) angeben.
Wenn Sie eine Abfragezeichenfolge verwenden, können Sie die Abfrage von der DB2-Befehlszeile aus oder innerhalb eines Programms übergeben. Wenn Sie ein Abfrageobjekt verwenden, hängt es vom Verweis auf das Abfrageobjekt ab, ob Sie die Abfrage von der DB2-Befehlszeile aus oder innerhalb eines Programms übergeben können. Wenn Sie ein Abfrageobjekt benennen und sichern, können Sie anschließend in einer UDF, die eine benannte Abfrage akzeptiert (die UDF QbScoreFromName oder QbScoreTBFromName), mit Hilfe des Namens auf das Abfrageobjekt verweisen. Sie können die UDF von der DB2-Befehlszeile aus oder innerhalb eines Programms aufrufen. Wenn Sie mit Hilfe der Kennung auf das Abfrageobjekt verweisen, können Sie die Abfrage nur innerhalb eines Programms übergeben.
Der Image Extender vergleicht die Merkmalwerte, die in der Abfrage angegeben sind, mit denen der Zielabbilder und berechnet ein Ähnlichkeitsergebnis für jedes Abbild. Dieses Ergebnis zeigt, wie sehr der Merkmalwerte des Zielabbilds den Merkmalwerten ähneln, die in der Abfrage angegeben sind.
Sie können Abbilder abrufen, deren Merkmalwerte denen der Abfrage am ähnlichsten sind. Sie können außerdem ein einzelnes katalogisiertes Abbild abfragen und dessen Ähnlichkeitsergebnis abrufen, oder die Ähnlichkeitsergebnisse für alle katalogisierten Abbilder in einer Tabellenspalte abrufen.
Der Image Extender stellt drei APIs zur Verfügung, um die katalogisierten Abbilder in einer Tabellenspalte abzurufen. Die APIs unterscheiden sich nur insofern, daß sie eine Abfragezeichenfolge oder ein Abfrageobjekt als Eingabe benötigen:
API | Eingabe |
---|---|
QbQueryStringSearch | Abfragezeichenfolge |
QbQuerySearch | Kennung für Abfrageobjekt |
QbQueryNameSearch | Name des Abfrageobjekts |
In jeder der drei APIs können Sie außerdem
Sie können außerdem auf einen Bereich von Ausgabestrukturen zeigen, der die Ergebnisse der Suche enthalten soll. Daraufhin gibt der Image Extender in diesen Strukturen die Kennungen der Zielabbilder zurück, deren Merkmalwerte denen der Abfrage am ähnlichsten sind. Er gibt außerdem ein Ähnlichkeitsergebnis für jedes Abbild zurück, das angibt, wie sehr der Merkmalwert des Abbilds dem der Abfrage ähnelt. Die Struktur ist in der Kopfdatei für QBIC, dmbqbapi.h, wie folgt definiert:
typedef struct{ char imageHandle[MMDB_BASE_HANDLE_LEN+1]; SQLDOUBLE SCORE } QbResult;
Sie müssen einen Bereich zuordnen, der groß genug ist, um die maximale angegebene Anzahl von Ergebnissen zu speichern, und Sie müssen in der API auf den Bereich zeigen. Sie müssen außerdem auf einen Zähler zeigen. Der Image Extender setzt den Wert des Zählers auf die Anzahl der Ergebnisse, die er zurückgibt.
Im folgenden Beispiel wird die API QbQueryStringSearch verwendet, um die katalogisierten Abbilder in einer Tabellenspalte anhand des Inhalts abzufragen. Beachten Sie, daß der Zeiger auf den Abfragebereich auf den Wert Null gesetzt ist.
QbResult returns[MaxQueryReturns]; SQLINTEGER maxResults=qbiMaxQueryReturns; SQLINTEGER count; QbQueryHandle qHandle; QbResult results[qbiMaxQueryReturns]; rc=QbQueryStringSearch( "QbColorFeatureClass color=<255, 0, 0>" /*query string */ "employee", /* user table */ "picture", /* image column */ maxResults, /* maximum number of results */ 0, /* query scope pointer * / qbiArray, /* store results in an array */ &count, /* count of returned images */ results); /* array of returned results */
Es folgt eine Anforderung unter Verwendung der API QbQuerySearch. Beachten Sie, daß die Kennung für das Abfrageobjekt als Eingabe angegeben ist.
QbResult returns[MaxQueryReturns]; SQLINTEGER maxResults=qbiMaxQueryReturns; SQLINTEGER count; QbQueryHandle qHandle; QbResult results[qbiMaxQueryReturns]; rc=QbQuerySearch( qHandle, / query object handle */ "employee", /* user table */ "picture", /* image column */ maxResults, /* maximum number of results */ 0, /* query scope pointer * / qbiArray, /* store results in an array */ &count, /* count of returned images */ results); /* array of returned results */
Es folgt eine Anforderung unter Verwendung der API QbQueryNameSearch. Beachten Sie, daß der Name (und nicht die Kennung) für das Abfrageobjekt als Eingabe angegeben ist.
QbQueryHandle qHandle; char qName[18]; char qDesc[250]; char results[qbiMaxQueryReturns]; SQLINTEGER maxResults=qbiMaxQueryReturns; /* Name the query object*/ strcpy(qName,"fshavgcol"); strcpy(qDesc,"average color query, created 10/15/96"); rc=QbQueryNameCreate( qHandle, /* query object handle */ qName, /* query object name */ qDesc); /* query object description */ /* Issue the query */ rc=QbQueryNameSearch( qName, /* query object name */ "employee", /* user table */ "picture", /* image column */ maxResults, /* maximum number of results */ 0, /* query scope pointer * / qbiArray, /* store results in an array */ &count, /* count of returned images */ results); /* array of returned results */
Der Image Extender stellt vier UDFs zur Verfügung, die Sie in einer SQL-Anweisung verwenden können, um
das Ähnlichkeitsergebnis eines katalogisierten Abbilds in einer Tabellenspalte abzurufen. Das Ähnlichkeitsergebnis ist ein Gleitkommawert mit doppelter Genauigkeit im Bereich von 0,0 bis gegen Unendlichkeit. Je niedriger das Ähnlichkeitsergebnis, desto mehr stimmen die Merkmalwerte des Abbilds mit den Merkmalwerten überein, die in der Abfrage angegeben sind. Ein Ähnlichkeitsergebnis von 0,0 bedeutet, daß das Abbild exakt übereinstimmt.
Zu den UDFs gehören:
Verwenden Sie die UDF QbScoreFromStr oder QbScoreFromName, um das Ähnlichkeitsergebnis eines einzelnen katalogisierten Abbilds abzurufen. Verwenden Sie die UDF QbScoreTBFromStr oder QbScoreTBFromName, um das Ähnlichkeitsergebnis von mehreren katalogisierten Abbildern in einer Tabellenspalte abzurufen.
Verwenden Sie die UDF QbScoreFromStr oder QbScoreFromName, um das Ähnlichkeitsergebnis eines einzelnen katalogisierten Abbilds in einer Tabellenspalte abzurufen. Geben Sie eine Abfragezeichenfolge als Eingabe für die UDF QbScoreFromStr an. Geben Sie den Namen eines Abfrageobjekts als Eingabe für die UDF QbScoreFromName an. Geben Sie bei beiden UDFs auch den Namen der Tabellenspalte an, die das Zielabbild enthält.
In der folgenden Abfrage wird die UDF QbScoreFromStr verwendet, um die katalogisierten Abbilder in einer Tabellenspalte zu suchen, deren Ähnlichkeitsergebnis für die Durchschnittsfarbe sehr nah an Rot liegt.
SELECT name, description FROM fabric WHERE (QbScoreFromStr( 'QbColorFeatureClass color=<255, 0, 0>', /* query string * swatch_img))>0.9 /* table column */
Im folgenden C-Programmierungsbeispiel wird die UDF QbScoreFromName, verwendet, um eine ähnliche Anforderung zu stellen. Beachten Sie, daß als Eingabeparameter der Name eines Abfrageobjekts (statt einer Abfragezeichenfolge) angegeben wird:
EXEC SQL SELECT name, description INTO :hvName, :hvDesc FROM fabric WHERE (QbScoreFromName( 'fshavgcol', /* query object name * swatch_img))<0.1; /* table column */
Sie können auch QbScore verwenden, sie ist aber veraltet: DB2 Extender Version 1 bot eine UDF mit dem Namen QbScore, mit der das Ähnlichkeitsergebnis eines Abbilds abgerufen wurde. Die Eingabeparameter für die UDF QbScore und deren Ergebnisse stimmen mit denen der UDF QbScoreFromName überein. Die UDF QbScore wird von DB2 Extender Version 5 akzeptiert, allerdings wird QbScoreFromName bevorzugt.
Verwenden Sie die UDF QbScoreTBFromStr oder QbScoreTBFromName, um das Ähnlichkeitsergebnis von mehreren katalogisierten Abbildern in einer Tabellenspalte abzurufen. Beide UDFs geben eine zweispaltige Tabelle mit Abbildkennungen und Ähnlichkeitsergebnissen zurück; die Zeilen in der Tabelle sind absteigend nach Ähnlichkeitsergebnis sortiert. Der Name der Kennungsspalte in der Ergebnistabelle ist IMAGE_ID, der Name der Ähnlichkeitsergebnisspalte ist SCORE.
Geben Sie eine Abfragezeichenfolge als Eingabe für die UDF an. Geben Sie den Namen eines Abfrageobjekts als Eingabe für die UDF QbScoreTBFromName an. Geben Sie bei beiden UDFs auch den Namen der Tabelle und der Spalte an, die die Zielabbilder enthält. Sie können außerdem die maximale Anzahl an Zeilen angeben, die in der Ergebnistabelle zurückgegeben werden sollen. Wenn Sie keine maximale Anzahl an Ergebniszeilen angeben, gibt die UDF für jedes katalogisierte Abbild in der Zieltabellenspalte eine Zeile zurück.
In der folgenden Abfrage wird die UDF QbScoreTBFromStr verwendet, um die zehn katalogisierten Abbilder in einer Tabellenspalte zu suchen, deren Textur der eines Abbilds in einer Server-Datei am ähnlichsten ist.
SELECT name, description FROM fabric WHERE CAST (swatch_img as varchar(250))IN SELECT CAST (image_id as varchar(25)) FROM TABLE (QbScoreTBFromStr (QbTextureFeatureClass file=<server,"patterns/ptrn07.gif">' /*query string */ 'fabric', /* table */ 'swatch_img', /* table column */ 10)) /* maximum number of results */ AS T1));
Im folgenden C-Programmierungsbeispiel wird die UDF QbScoreTBFromName verwendet. Beachten Sie, daß als Eingabeparameter der Name eines Abfrageobjekts (statt einer Abfragezeichenfolge) angegeben wird. Beachten Sie außerdem, daß keine Eingabe für die maximale Ergebnisanzahl angegeben ist, so daß die UDF für jedes katalogisierte Abbild in der Zieltabellenspalte ein Ergebnis zurückgibt:
SELECT name, description INTO :hvName, :hvDesc FROM fabric WHERE CAST (swatch_img as varchar(250)) IN (SELECT CAST (image_id as varchar(250)) FROM TABLE (QbScoreTBFromName 'fstxtr', /* query object name */ 'fabric', /* table */ 'swatch_img')) /* table column */ AS T1));
Die folgende Abbildung zeigt Teile eines in C geschriebenen Programms, mit eine QBIC-Abfrage erstellt und ausgeführt wird. Der Code in der Abbildung fragt Abbilder nach Durchschnittsfarbe ab. Er fordert den Benutzer zur Eingabe des Namens einer Farbe oder Abbilddatei auf. Der Benutzer kann auch ein Abbild, das von einer Abfrage zurückgegeben wird, als ein Beispielabbild für eine nachfolgende Abfrage verwenden. Das Programm verwendet danach die benannte Farbe oder die Farbe des Abbilds als Durchschnittsfarbe, um eine Spalte mit Abbildern abzufragen.
Das vollständige Programm befindet sich in der Datei QBICDEMO.C im Unterverzeichnis SAMPLES. Das vollständige Programm kann verwendet werden, um Abbilder nach Histogrammfarbe oder positionsgebundener Farbe sowie nach Durchschnittsfarbe abzufragen. Um das vollständige Programm ausführen zu können, müssen Sie die Beispielprogramme ENABLE, POPULATE und QBCATDMO ausführen (die sich auch im Unterverzeichnis SAMPLES befinden). Weitere Informationen zu Beispielprogrammen befinden sich im Anhang B. Beispielprogramme und Multimediadateien.
Beachten Sie folgende Punkte in dem Beispielprogramm:
(1)Die Kopfdatei dmbqbapi wird eingeschlossen.
(2)Der Benutzer wird zur Eingabe von Datenbankinformationen aufgefordert.
(3)Eine Verbindung zur Datenbank wird hergestellt.
(4)Ein Abfrageobjekt wird erstellt.
(5)Ein Merkmal wird zu einem Abfrageobjekt hinzugefügt.
(6)Der Benutzer wird zur Eingabe des Eingabetyps aufgefordert (Farbname, Abbilddatei oder zuvor abgerufenes Abbild).
(7)Die Datenquelle für das Merkmal wird angegeben. Die Datenquelle ist eine explizite Angabe für die Durchschnittsfarbe.
(8)Die Abfrage wird ausgeführt. Der Image Extender durchsucht die gesamte Spalte mit Abbildern. Außerdem wird 10 als maximale Anzahl von Abbildern angegeben, die zurückgegeben werden sollen.
(9)Das nächste Abbild aus der Gruppe der zurückgegebenen Abbilder wird angezeigt. Weitere Informationen zur Anzeige von Abbildern befinden sich im Abschnitt Abbild oder Videovollbild in normaler Größe anzeigen.
(10)Das Abfrageobjekt wird gelöscht.
Das Unterverzeichnis SAMPLES enthält ein weiteres Programm, das die Erstellung und Verwendung einer QBIC-Abfrage demonstriert. Das Programm in der Datei QBICPICK.C bietet dem Benutzer die Möglichkeit, die Suchkriterien für eine QBIC-Abfrage grafisch anzugeben. Beispielsweise bietet das Programm ein Farbauswahlmenü, mit dem die Durchschnittsfarbe ausgewählt werden kann. Das Programm setzt die Auswahl in eine Abfragezeichenfolge um.
Abbildung 21. Programm für QBIC-Abfragebeispiel
#include <sql.h> #include <sqlcli.h> #include <sqlcli1.h> #include <dmbqbqpi.h> (1) #include <stdio.h> #include <string.h> #include <malloc.h> #include <color.h> #include <ctype.h> #define MaxQueryReturns 10 #define MaxDatabaseNameLength SQL_SH_IDENT #define MaxUserIdLength SQL_SH_IDENT #define MaxPasswordLength SQL_SH_IDENT #define MaxTableNameLength SQL_LG_IDENT #define MaxColumnNameLength SQL_LG_IDENT static char databaseName[MaxDatabaseNameLength+1]; static char userid[MaxUserIdLength+1]; static char password[MaxPasswordLength+1]; static char tableName[MaxTableNameLength+1]; static char columnName[MaxColumnNameLength+1]; static char line[4000]; static QbResult results[MaxQueryReturns]; static long currentImage = -1; static long imageCount = 0; static char* tableAndColumn; static QbQueryHandle averageHandle = 0; static QbQueryHandle histogramHandle = 0; static QbQueryHandle drawHandle = 0; static QbQueryHandle lastHandle = 0; static SQLHENV henv; static SQLHDBC hdbc; static SQLHSTMT hstmt; static SQLRETURN rc; static char* listQueries = "SELECT NAME,DESCRIPTION FROM MMDBSYS.QBICQUERIES ORDER BY NAME"; static char* menu[] = { /* 12345678901234567890123456789012345678901234567890123456789012345678901234567890 */ "", "+-----------------------------------------------------------------------------+", "| AVERAGE COLOR colorname |", "| AVERAGE FILE filename format |", "| AVERAGE LAST |", "| Press Enter to display the next image in the series |", "+-----------------------------------------------------------------------------+", "", 0 }; static char* help[] = { "", "AVERAGE Execute an average color query", " COLOR Specifies the color to query for", " FILE Specifies the file to compute the average color from", " LAST Specifies the last displayed image be used to compute the color", " NEXT Displays the next image from the current query or nothing if", " all of the image have been displayed." "", ">>pause<<", 0 }; /******************************************************************************/ /* doNext() */ /******************************************************************************/ static void doNext(void) { int ret; if (currentImage < imageCount) currentImage++; if (currentImage < imageCount) ret = DBiBrowse("/usr/local/bin/xv %s", MMDB_PLAY_HANDLE, results[currentImage].imageHandle, MMDB_PLAY_NO_WAIT); (9) } /******************************************************************************/ /* doAverage() */ /******************************************************************************/ static void doAverage(void) { QbQueryHandle qohandle = 0; QbImageSource is; char* type; char* arg1; char* arg2; type = nextWord(0); if (abbrev(type, "color", 1)) { is.type = qbiSource_AverageColor; arg1 = nextWord(0); if (arg1 == 0) { printf("AVERAGE COLOR command requires a colorname argument.\n"); return; } if (getColor(arg1, &is.averageColor) == 0) { printf("The colorname entered was not recognized.\n"); return; } } else if (abbrev(type, "file", 1)) { is.type = qbiSource_ClientFile; arg1 = nextWord(0); if (arg1 == 0) { printf("AVERAGE FILE command requires a filename argument.\n"); return; } arg2 = nextWord(0); if (arg2 == 0) { printf("AVERAGE FILE command requires a file format argument.\n"); return; } strcpy(is.clientFile.fileName, arg1); strcpy(is.clientFile.format, arg2); } else if (abbrev(type, "last", 1)) { is.type = qbiSource_ImageHandle; if (0 <= currentImage &&; currentImage < imageCount) strcpy(is.imageHandle, results[currentImage]imageHandle); else { printf("No last image for AVERAGE LAST command\n"); return; } } else { printf("AVERAGE command only supports COLOR, FILE, and LAST types.\n"); return; } _QbQuerySetFeatureData(averageHandle, "QbColorFeatureClass", &is); (7) _QbQuerySearch(averageHandle, tableAndColumn, "IMAGE", MaxQueryReturns, 0, 0, &imageCount, results); (8) lastHandle = averageHandle; currentImage = -1; } /******************************************************************************/ /* commandLoop() */ /******************************************************************************/ void commandLoop(void) { int done = 0; while (!done) { (6) displayText(menu); printf("%d", currentImage + 1); if (0 <= currentImage &&; currentImage < imageCount) printf(" %8.6f", results[currentImage].score); printf("> "); gets(line); done = processCommand(line); } } /******************************************************************************/ /* main() */ /******************************************************************************/ void main(void) { char* inst; int i; printf("\n\n"); printf("Please enter: database_name [user_id] [password] "\n"); (2) gets(line); if (copyWord(line, databaseName, sizeof(databaseName)) == 0) exit(0); copyWord(0, userid, sizeof(userid)); copyWord(0, password, sizeof(password)); printf("\n"); if (SQLAllocEnv(&henv) != SQL_SUCCESS) sqlError(SQL_NULL_HSTMT); if (SQLAllocConnect(henv, &hdbc) != SQL_SUCCESS) sqlError(SQL_NULL_HSTMT); if (SQLConnect(hdbc, (3) (SQLCHAR*)databaseName, SQL_NTS, (SQLCHAR*)userid, SQL_NTS, (SQLCHAR*)password, SQL_NTS) != SQL_SUCCESS) sqlError(SQL_NULL_HSTMT); printf("Initializing . . .\n"); inst = getenv("DB2INSTANCE"); if (inst != 0 &&; strcmp(inst, "keeseyt") == 0) tableAndColumn = "KEESEY.TEST"; else tableAndColumn = "QBICDEMO.TEST"; _QbQueryCreate(&averageHandle); (4) _QbQueryAddFeature(averageHandle, "QbColorFeatureClass"); _QbQueryCreate(&histogramHandle); _QbQueryAddFeature(histogramHandle, "QbColorHistogramFeatureClass"); _QbQueryCreate(&drawHandle); _QbQueryAddFeature(drawHandle, "QbDrawFeatureClass"); (5) commandLoop(); _QbQueryDelete(drawHandle); _QbQueryDelete(histogramHandle); (10) _QbQueryDelete(averageHandle); if (SQLDisconnect(hdbc) != SQL_SUCCESS) sqlError(SQL_NULL_HSTMT); if (SQLFreeConnect(hdbc) != SQL_SUCCESS) sqlError(SQL_NULL_HSTMT); if (SQLFreeEnv(henv) != SQL_SUCCESS) sqlError(SQL_NULL_HSTMT); } |