Inhaltsverzeichnis
Multimedia in der Oracle Datenbank 12c / 18c - Bildbearbeitung in PL/SQL
Start: 05.2017
12c, Basis Funktion aber schon ab Oracle 8i seit 1998 verfügbar
18c
⇒ https://docs.oracle.com/en/database/oracle/oracle-database/18/imurg/index.html
Ziel: Mit der Oracle Multimedia Option Bilder in der Datenbank bearbeiten und in APEX darstellen
Mit Oracle Multimedia 12c (seit 8i / 11g noch unter dem Namen Oracle interMedia vertrieben) steht dem Apex Entwickler ein reichhaltiges Werkzeug für das Metadaten Handling von Bild und Ton Daten in der Oracle Datenbank zur Verfügung.
Mit der Oracle Multimedia 12c lassen sich die Metadaten und Attribute von Multimedia Daten lesen und setzen und viele Eigenschaften von Bild Dateien, wie Größe, Rotation, Schärfe, Kontrast etc., direkt in der Datenbank bearbeiten.
Bestimmte Eigenschaften wie die Farbe eines Bildes lassen sich aus den binären Daten des Bildes ermitteln und werden damit auch suchbar.
Mit diesem umfangreichen Set an Hilfsmitteln lassen sich mit PL/SQL auch komplexere Aufgabenstellung in Oracle Apex relativ einfach integrieren.
Übersicht über die Elemente in der Datenbank:
Die Verarbeitung der Daten wird über Datenbank Objekt Typen durchgeführt:
- Bild Daten ⇒ ORDImage
- Audio Daten ⇒ ORDAudio
- Heterogene Daten ⇒ ORDDoc
- Video Daten ⇒ ORDVideo
Die Speicherung in einer Datenbank Tabelle kann ebenfalls mit diesem Typen durchgeführt werden.
Vorteil der Speicherung als Objekt Type:
- Daten und Eigenschaften über ein Objekt ansprechbar
- Schlankes Datenmodel
Nachteil der Speicherung als Objekt Type:
- Laderoutienen etwas komplexer
- Gefahr von Bugs
- Daten müssen für andere Tools immer extrahiert werden
Übersicht über möglichen Feature (11g) ⇒ http://www.oracle.com/technetwork/database/database-technologies/multimedia/overview/multimedia11gr2-featover-128418.pdf
Installation
Siehe https://docs.oracle.com/database/121/IMURG/ap_instl_upgrd.htm
Benötigt die JAVAVM, XDB, XML Option
Legt folgende User an:
- ORDSYS
- ORDPLUGINS ( hier können eigene Erweiterungen abgelegt werden)
- SI_INFORMTN_SCHEMA
- ORDDATA
- MDSYS - Oracle Multimedia Locatorset
Prüfen ob die Option auch korrekt installiert wurde:
SYS>EXECUTE sys.validate_ordim; PL/SQL PROCEDURE successfully completed. SYS>SELECT version, STATUS FROM dba_registry WHERE comp_id='ORDIM'; VERSION STATUS ------------------------------------------------- -------- 12.1.0.2.0 VALID
Eine Beispiel Anwendung
Für ein Bautagebuch sollen auch die anfallenden Bilddaten gespeichert werden.
Einen User anlegen
Als SYS:
-- create the user CREATE USER conbook IDENTIFIED BY conbook DEFAULT tablespace USERS TEMPORARY tablespace TEMP; ALTER USER conbook quota unlimited ON USERS; GRANT CONNECT, resource TO conbook; -- create the info Archive DIRECTORY CREATE OR REPLACE directory IMG_ARCHIVE AS 'C:\entwicklung\work\OracleMultiMedia\99-Images'; GRANT READ,WRITE ON directory IMG_ARCHIVE TO conbook;
Darauf achten das der Oracle User unter dem die 12c DB läuft, in meinen Fall der User ORARUN, auch die entsprechenden Rechte auf das Verzeichnis besitzt!
Im Dateisystem unter „C:\entwicklung\work\OracleMultiMedia\99-Images“ liegen in meinen Testfall nun 13 Bilder, 1.jpg bis 13.jpg. Diese werden später über das Directory Objekt in die Datenbank geladen.
Tabelle für die Bilddaten
Für das Speichern der Bilddaten wird der Datentyp ORDSYS.ORDIMAGE eingesetzt.
ORDSYS.ORDIMAGE hat die folgenden „Felder“:
------------------- -- TYPE ATTRIBUTES ------------------- source ORDSource, height INTEGER, width INTEGER, contentLength INTEGER, fileFormat VARCHAR2(4000), contentFormat VARCHAR2(4000), compressionFormat VARCHAR2(4000), mimeType VARCHAR2(4000),
Als User conbook
CREATE TABLE CONBOOK.CON_IMAGES ( ID NUMBER(13), name VARCHAR2(256) NOT NULL, remarks VARCHAR2(4000), img ORDSYS.ORDIMAGE, preview ORDSYS.ORDIMAGE ) LOB(img.source.localData) STORE AS SECUREFILE LOB(preview.source.localData) STORE AS SECUREFILE ; ALTER TABLE CONBOOK.CON_IMAGES ADD ( CONSTRAINT CON_IMAGES_PK PRIMARY KEY (ID) ENABLE VALIDATE);
Daten in die Tabelle laden
Einfache Laderoutine:
CREATE OR REPLACE PROCEDURE loadConImg (p_id NUMBER , p_name varchar2 , p_remark varchar2) AS v_img_orig ORDSYS.ORDImage; v_img_preview ORDSYS.ORDImage; v_ctx RAW(64) := NULL; BEGIN -- save metadata and return a referenz on the img object INSERT INTO CON_IMAGES (ID, NAME, REMARKS,img,preview) VALUES (p_id,p_name,p_remark,ORDImage(),ORDSYS.ORDImage.init()) RETURNING img INTO v_img_orig; -- read the image data to the temporary object v_img_orig.importFrom(v_ctx,'file','IMG_ARCHIVE',p_name); -- insert the temporary object into the image tabee UPDATE CON_IMAGES SET img=v_img_orig WHERE id=p_id; commit; --create trumbnail image SELECT img.IMG,img.PREVIEW INTO v_img_orig,v_img_preview FROM CON_IMAGES img WHERE img.id=p_id FOR UPDATE; BEGIN -- create the preview image v_img_orig.processCopy('fileFormat=JFIF CompressionQuality=MAXINTEGRITY maxScale=126 126',v_img_preview); -- only copy --v_img_orig.copy(v_img_preview); EXCEPTION WHEN ORDSYS.ORDImageExceptions.NULL_DESTINATION THEN DBMS_OUTPUT.PUT_LINE('The destination is null'); WHEN ORDSYS.ORDImageExceptions.DATA_NOT_LOCAL THEN DBMS_OUTPUT.PUT_LINE('Data is not local'); WHEN ORDSYS.ORDImageExceptions.NULL_LOCAL_DATA THEN DBMS_OUTPUT.PUT_LINE('dest.source.localData attribute is null'); WHEN others THEN DBMS_OUTPUT.PUT_LINE('Find this SQL ERROR:: '|| SQLCODE || ' - '||SQLERRM); END; UPDATE CON_IMAGES SET preview=v_img_preview WHERE id=p_id; commit; END; /
Damit das Image Objekt auch verwendet werden kann, muss es zuvor initialisiert werden.
Das kann ohne weitere Eigenschaften „leer“ erfolgen mit ORDSYS.ORDImage.init() für das am Anfang noch leere Preview Image oder mit folgenden Konstruktor ORDImage('file','IMG_ARCHIVE',p_name) um eine BFile Referenz auf das Bild im DB Direktory laden zu können oder mit eben als BLOB direkt in die Datenbank laden mit v_img_orig.importFrom(v_ctx,'file','IMG_ARCHIVE',p_name);.
Beispiel für das Laden mit der obigen Routine über SQL*Plus:
DELETE CON_IMAGES; commit; SET serveroutput ON BEGIN FOR i IN 1 .. 13 loop loadConImg ( p_id => i , p_name => to_char(i)||'.JPG' , p_remark => 'This is image '||to_char(i)); END loop; END; / SELECT * FROM CON_IMAGES;
Objekt Eigenschaften von ORDSYS.ORDImage ausgeben
Die wichtigsten Metadaten eines Bildes werden in dem Objekt ORDSYS.ORDImage als Attribute gespeichert.
Ausgeben mit:
SET serveroutput ON DECLARE v_image ORDSYS.ORDImage; BEGIN SELECT img INTO v_image FROM CON_IMAGES img WHERE id = 1; DBMS_OUTPUT.PUT_LINE('image width = ' || v_image.getWidth()); DBMS_OUTPUT.PUT_LINE('image height = ' || v_image.getHeight()); DBMS_OUTPUT.PUT_LINE('image size = ' || v_image.getContentLength()); DBMS_OUTPUT.PUT_LINE('image file type = ' || v_image.getFileFormat()); DBMS_OUTPUT.PUT_LINE('image type = ' || v_image.getContentFormat()); DBMS_OUTPUT.PUT_LINE('image compression = ' || v_image.getCompressionFormat()); DBMS_OUTPUT.PUT_LINE('image mime type = ' || v_image.getMimeType()); END; /
Bzw. in SQL ausgeben:
SELECT i.id , i.img.getHeight() height , i.img.getWidth() width , i.img.getMimetype() mimetype , i.img.getFileFormat() fileformat , i.img.getContentLength() LENGTH FROM CON_IMAGES i ORDER BY i.id /
EXIF Daten aus dem Bildern auslesen
Beispiel:
SET serveroutput ON DECLARE v_image ORDSYS.ORDImage; v_metadata XMLSequenceType; BEGIN SELECT img INTO v_image FROM CON_IMAGES img WHERE id = 1; v_metadata := v_image.getMetadata('ALL'); -- print the namespace of each metadata document FOR i IN 1..v_metadata.count LOOP DBMS_OUTPUT.PUT_LINE('namespace: ' || v_metadata(i).getNamespace() ); DBMS_OUTPUT.PUT_LINE('-----------------------'); DBMS_OUTPUT.PUT_LINE('CLOB Value: ' || v_metadata(i).getCLOBVal()); END LOOP; EXCEPTION WHEN ORDSYS.ORDImageExceptions.NULL_LOCAL_DATA THEN DBMS_OUTPUT.PUT_LINE('source local data is null'); WHEN ORDSYS.ORDImageExceptions.NULL_SOURCE THEN DBMS_OUTPUT.PUT_LINE('source is null'); WHEN OTHERS THEN RAISE; END; /
Am einfachsten wird das am Anfang beim Laden gelesen und dann gleich in einer eigenen CLOB / XML Spalte gespeichert um später weiter verarbeitet werden zu können.
APEX 5.1 Integration
Ein Bild darstellen
In Apex 5 kann sehr einfach ein Bild auf ein auf einer Seite über ein Page Item vom Typ „Display Image“ dargestellt werden.
Dazu muss aber das Bild in einer BLOB Spalte vorliegen!
In unseren Fall liegt das Bild aber in einem Objekt vom Typ ORDSYS.ORDImage, d.h. wir müssen einfach nur den BLOB in dem Objekt auslesen.
Als „Based on“ wählen wir „Blob Column returned by SQL Statement“ .
SQL:
SELECT img.preview.source.localData FROM CON_IMAGES img WHERE img.id=1
Bilder in einem Bericht darstellen
Leider geht es nicht so einfach mit einen „Interactive Report“, wird einfach nur die BLOB Spalte im Bericht referenziert wird nur ein „[unsupported data type]“ angezeigt.
Wird nun die Image Spalte auf den Typ „Display Image“ gesetzt, brauchen wir einen View auf unsere Daten um die BLOB Spalte im Objekt in der Apex Maske auswählen zu können, Apex muss das selber erkennen, wir können die Spalte nicht mit „img.source.localData“ einfach selber angeben.
SQL für die BLOB View:
CREATE OR REPLACE VIEW CONBOOK.V_CON_IMAGES_BLOB AS SELECT ID , NAME , img.img.getMimetype() mimetype , REMARKS , img.img.source.localData IMG , img.PREVIEW.source.localData AS PREVIEW FROM CON_IMAGES img;
Fehler „ORA-06502: PL/SQL: numeric or value error: character to number conversion error“
In der eigentlichen Berichtsabfrage darf nicht der BLOB des Bildes, sondern die Größe des Bildes muss referenziert werden.
SELECT img.preview.getContentLength() AS preview_image , ID , NAME , REMARKS FROM CON_IMAGES img ORDER BY ID
Und schon funktioniert es!
Siehe auch ⇒ http://www.oralytics.com/2016/09/how-to-display-blob-image-in-apex-report.html
Bild bearbeiten
Über die Methode http://docs.oracle.com/database/121/AIVUG/ch_imgref.htm#AIVUG80485 process() kann das Bild Objekt direkt in der Datenbank bearbeitet werden.
Dazu wird in APEX einfach diese Funktion als Source für ein Image Display Item aufgerufen und dabei das entsprechende Kommando übergeben.
In der folgenden Routine wird die Watermark Funktion verwandt um im Fehlerfall den SQL Fehler direkt in das Bild zu schreiben.
Achtung! Hier ist noch ein böser Bug! der Temporäre Speicher wird nicht freigeben wenn die Watermark Funktion verwendet wird!
Beispiel Code um ein Bild zu verarbeiten:
CREATE OR REPLACE FUNCTION imgConverter(p_img_id NUMBER,p_command varchar2 DEFAULT 'maxScale 400 400') RETURN BLOB IS v_img_orig ORDSYS.ORDImage; v_img_work ORDSYS.ORDImage; v_img_blob_error BLOB; v_img_blob BLOB; v_command varchar2(4000):=p_command; --- Error handling v_watermark_prop ORDSYS.ORD_STR_LIST; v_message varchar2(32000); v_error BOOLEAN:=TRUE; v_logging varchar2(2000); BEGIN -- get the original image SELECT img.IMG INTO v_img_orig FROM CON_IMAGES img WHERE img.id=p_img_id; -- init the blob dbms_lob.createtemporary(v_img_blob , TRUE, DBMS_LOB.SESSION); dbms_lob.createtemporary(v_img_blob_error, TRUE, DBMS_LOB.SESSION); BEGIN ORDSYS.ORDImage.processCopy( imageblob => v_img_orig.source.localData ,command => v_command ,dest => v_img_blob); v_error:=FALSE; EXCEPTION WHEN ORDSYS.ORDImageExceptions.NULL_DESTINATION THEN v_message:='The destination is null'; v_error:=TRUE; WHEN ORDSYS.ORDImageExceptions.DATA_NOT_LOCAL THEN v_message:='Data is not local'; v_error:=TRUE; WHEN ORDSYS.ORDImageExceptions.NULL_LOCAL_DATA THEN v_message:='dest.source.localData attribute is null'; v_error:=TRUE; WHEN others THEN v_message:='Find this SQL ERROR:: '|| SQLCODE || ' - '||SQLERRM; v_error:=TRUE; END; IF v_error THEN -- print the error into the image as Watermark --'position=bottomright' v_watermark_prop := ordsys.ord_str_list( 'font_name=Arial', 'font_style=bold', 'font_size=20', 'text_color=red', 'position_x=10', 'position_y=20', 'transparency=1' ); dbms_lob.createtemporary(v_img_blob_error, TRUE, DBMS_LOB.SESSION); ORDSYS.ORDImage.applyWatermark( imageBlob => v_img_orig.source.localData ,added_text => substr(v_message,1,100) ,dest => v_img_blob_error ,logging => v_logging ,watermark_properties => v_watermark_prop ); v_img_work:=ORDSYS.ORDImage(v_img_blob_error); ----------------------------------------- -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 -- dummy process to free memory -- BUG with applyWatermark !! -- if you call ORDSYS.ORDImage.processCopy the memory will be freed sucessfull -- strange behavior -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 ----------------------------------------- ORDSYS.ORDImage.processCopy( imageblob => v_img_orig.source.localData ,command => 'maxScale 200 200' ,dest => v_img_blob); ELSE v_img_work:=ORDSYS.ORDImage(v_img_blob); END IF; -- Free the temporary LOB --DBMS_LOB.CLOSE(v_img_blob); DBMS_LOB.FREETEMPORARY(v_img_blob_error); DBMS_LOB.FREETEMPORARY(v_img_blob); RETURN v_img_work.source.localData ; -- UTL_RAW.CAST_TO_RAW(v_logging); -- END imgConverter;
Demnächst Mehr
Problem mit ORDImage.applyWatermark - data cartridge error IMG-00003: exhausted memory while processing image IMG-003: out of memory in (native) awt jpeg decode-
Da ich ja im obigen Code den BLOB nicht mehr so wirklich freigeben kann, laufen ich schnell nach ein paar Versuchen bei den obigen Oracle Fehler…. daher auch das etwas umständliche Kopieren der LOB's, leider hat das nicht wirklich geholfen, nach 8 Versuchen ist Schluss…. aber nur wenn die Methode ORDImage.applyWatermark betroffen ist!
ERROR: ORA-29400: data cartridge error IMG-00003: exhausted memory while processing image IMG-003: out of memory in (native) awt jpeg decode ORA-06512: at "ORDSYS.ORDIMERRORCODES", line 75 ORA-06512: at "ORDSYS.ORDIMERRORCODES", line 65 ORA-06512: at "ORDSYS.ORDIMG_PKG", line 471 ORA-06512: at "ORDSYS.ORDIMAGE", line 1623 ORA-06512: at "CONBOOK.IMGCONVERTER", line 67 ORA-06512: at line 1
Erste Lösungen:
Java Pool Size vergrößert
ALTER system SET java_pool_size=256M scope=memory sid='*'; -- kontrolle der aktuellen Verwendung mit: SELECT * FROM v$javapool;
Dann funktioniert es etwas länger, Speicher läuft trotzdem voll …..
Laut Support Node ⇒ „ORDSYS.ORDImage Methods Fail Or Slow Down After Extended Processing; Consume Increasing Amounts Of Memory (Doc ID 267880.1)“ ist das Problem seit längeren evlt. bekannt, hier hilft wohl nur einen eigenen Bug dazu für 12c bei Oracle neu zu öffnen.
Ärgerlich …
Solution
Nach dem Aufruf von ORDSYS.ORDImage.applyWatermark nochmals eine gültige Operation mit ORDSYS.ORDImage.processCopy ausführen um den Stack der Session wieder richtig aufzuräumen.
Funktioniert, ist aber nicht sehr schön …..
Bilder hochladen
Wie aber nun die Bilder über die Weboberfläche hochladen?
In APEX 5 wird intern die Tabelle APEX_APPLICATION_TEMP_FILES für das hochladen von Dateien verwendet.
Aus dieser Tabelle holen wir uns die Daten und schreiben die Daten in unsere Bild Tabelle.
Danach nicht vergessen das Bild in der APEX_APPLICATION_TEMP_FILES auch wieder zu löschen ( View auf wwv_flow_file_objects$)!
Um die Datei auszuwählen ein Page Item vom Typ „File Browse“ anlegen (in diesem Beispiel mit dem Namen P1_FILESELECTION )
Einen Submit Button auf der Page anlegen ( Action „Submit Page“)
Für die eigentliche Logik des Umkopieren der Daten dann ein Stück PL/SQL verwenden um die Daten in unsere Struktur einzulesen.
Der PL/SQL code für den „After Submit“ Process der Apex Seite:
DECLARE v_file_count pls_integer:=0; v_img_orig ORDSYS.ORDImage; v_img_preview ORDSYS.ORDImage; v_id CON_IMAGES.id%TYPE; v_message varchar2(4000):='Prozessing File Insert'||'<br/>'; BEGIN IF :P1_FILESELECTION IS NOT NULL THEN v_message:= v_message||' Name of P1_FILESELECTION is '||:P1_FILESELECTION||'<br/>'; SELECT COUNT(ID) INTO v_file_count FROM apex_application_temp_files WHERE name = :P1_FILESELECTION; IF v_file_count > 0 THEN FOR rec IN (SELECT id, application_id, name, filename, mime_type, created_on, blob_content FROM apex_application_temp_files WHERE name = :P1_FILESELECTION ) loop BEGIN v_message:= v_message||' Read Image with filename '||rec.filename||'<br/>'; INSERT INTO CON_IMAGES (ID, NAME, REMARKS,img,preview) VALUES ( CON_IMAGES_SEQ.nextval , rec.filename , rec.filename ||' Mime type'||rec.mime_type||' Uploaded at'||to_char(rec.created_on,'dd.mm.yyyy hh24:mi') , ORDSYS.ORDImage.init() , ORDSYS.ORDImage.init() ) RETURNING id,img INTO v_id,v_img_orig; v_img_orig:=ORDSYS.ORDImage(rec.blob_content); UPDATE CON_IMAGES SET img=v_img_orig WHERE id=v_id; commit; --create trumbnail image SELECT img.IMG,img.PREVIEW INTO v_img_orig,v_img_preview FROM CON_IMAGES img WHERE img.id=v_id FOR UPDATE; -- create the preview image v_img_orig.processCopy('fileFormat=JFIF CompressionQuality=MAXINTEGRITY maxScale=126 126',v_img_preview); -- only copy --v_img_orig.copy(v_img_preview); UPDATE CON_IMAGES SET preview=v_img_preview WHERE id=v_id; commit; EXCEPTION WHEN ORDSYS.ORDImageExceptions.NULL_DESTINATION THEN v_message:=v_message||' The destination is null'||'<br/>'; WHEN ORDSYS.ORDImageExceptions.DATA_NOT_LOCAL THEN v_message:=v_message||' Data is not local'||'<br/>'; WHEN ORDSYS.ORDImageExceptions.NULL_LOCAL_DATA THEN v_message:=v_message||' dest.source.localData attribute is null'||'<br/>'; WHEN others THEN v_message:=v_message||' Find this SQL ERROR:: '|| SQLCODE || ' - '||SQLERRM; END; END loop; -- clean the tempfile BEGIN DELETE apex_application_temp_files WHERE name = :P1_FILESELECTION; commit; EXCEPTION WHEN others THEN v_message:=v_message||' clean tempfile '|| SQLCODE || ' - '||SQLERRM||'<br/>'; END; END IF; END IF; apex_application.g_print_success_message := '<span style="color:yellow">'|| v_message || '</span>'; END;
Bilder vergleichen
Wir legen uns daher nun eine Tabelle mit ein paar Basis Bilder an um den Vergleichsalgorithmus zu testen.
DROP TABLE con_img_templates; CREATE TABLE con_img_templates ( ID NUMBER(13) ,name VARCHAR2(256) NOT NULL ,remarks VARCHAR2(4000) ,img_template ORDSYS.ORDIMAGE ,signature ORDSYS.ORDImageSignature ) LOB(img_template.source.localData) STORE AS SECUREFILE ; ALTER TABLE CONBOOK.con_img_templates ADD ( CONSTRAINT con_img_templates_PK PRIMARY KEY (ID) ENABLE VALIDATE); CREATE SEQUENCE CONBOOK.con_img_templates_SEQ;
In diese Tabelle laden wir nun ein blaues,rotes,gelbes Bild mit 100*100Pixel.
CREATE OR REPLACE PROCEDURE CONBOOK.loadTemplateImg (p_id NUMBER , p_name varchar2 , p_remark varchar2) AS v_img_sig ORDSYS.ORDImageSignature; v_img_orig ORDSYS.ORDImage; v_ctx RAW(4000) := NULL; BEGIN -- save metadata and return a referenz on the img object INSERT INTO con_img_templates (ID, NAME, REMARKS,img_template,signature) VALUES (p_id,p_name,p_remark,ORDImage('file','IMG_ARCHIVE',p_name),ORDImageSignature.init()) RETURNING img_template,signature INTO v_img_orig,v_img_sig; -- read the image data to the temporary object v_img_orig.import(v_ctx); v_img_sig.generateSignature(v_img_orig); -- insert the temporary object into the image tabee UPDATE con_img_templates SET img_template=v_img_orig,signature=v_img_sig WHERE id=p_id; commit; END; /
Laden:
DELETE con_img_templates; commit; SET serveroutput ON BEGIN loadTemplateImg ( p_id => con_img_templates_SEQ.nextval , p_name => 'gruen.png' , p_remark => 'This is image gruen'); loadTemplateImg ( p_id => con_img_templates_SEQ.nextval , p_name => 'weiss.png' , p_remark => 'This is image weiss'); loadTemplateImg ( p_id => con_img_templates_SEQ.nextval , p_name => 'blau.png' , p_remark => 'This is image blau'); loadTemplateImg ( p_id => con_img_templates_SEQ.nextval , p_name => 'gelb.png' , p_remark => 'This is image gelb'); loadTemplateImg ( p_id => con_img_templates_SEQ.nextval , p_name => 'rot.png' , p_remark => 'This is image rot'); END; / SELECT * FROM con_img_templates; commit;
ALTER TABLE con_images ADD (signature ORDSYS.ORDImageSignature); UPDATE con_images SET signature=ORDImageSignature.init();
Vergleichen über den Score:
DECLARE v_i1_img ORDSYS.ORDImage; v_i2_img ORDSYS.ORDImage; v_i1_img_sig ORDSYS.ORDImageSignature; v_i2_img_sig ORDSYS.ORDImageSignature; v_score FLOAT; v_sim FLOAT; v_weight varchar2(256):='color="0.4",texture="0.10",shape="0.3", location="0.2"'; v_name varchar2(255); BEGIN -- read image SELECT img,signature,name INTO v_i1_img , v_i1_img_sig ,v_name FROM CON_IMAGES WHERE id =6 FOR UPDATE; v_i1_img_sig.generateSignature(v_i1_img); FOR rec IN (SELECT img_template ,signature ,name FROM con_img_templates FOR UPDATE) loop -- Compare two images for similarity based on image color: v_score:=ORDSYS.ORDImageSignature.evaluateScore(v_i1_img_sig, rec.signature,v_weight); v_sim:=ORDSYS.ORDImageSignature.ISSIMILAR(v_i1_img_sig, rec.signature, v_weight, 75); DBMS_OUTPUT.PUT_LINE('The score for compare '||rec.name||' with image ' ||v_name||' is ' || v_score); DBMS_OUTPUT.PUT_LINE('The sim score for simalar '||rec.name||' with image ' ||v_name|| 'is ' || v_sim); DBMS_OUTPUT.PUT_LINE('-----------------'); END loop; commit; END; /
see ⇒ https://docs.oracle.com/cd/B14117_01/appdev.101/b10829/mm_imgref002.htm#sthref896
Um ein Bild zu suchen muss immer zuvor ein Beispiel Bild vorgegeben werden, mit diesem wird verglichen See ⇒ https://docs.oracle.com/cd/B14117_01/appdev.101/b10840/mm_cbr.htm#i605493
Quellen
Doku
Oracle Multimedia User's Guide 12c ⇒ http://docs.oracle.com/database/121/IMURG/toc.htm
Support
- Information Center: Oracle Multimedia/Oracle interMedia (Doc ID 1546315.2)
Web
Bücher:
Blogs:
Bild in Apex per Java Script Modal größer darstellen