Oracle
 sql >> Database >  >> RDS >> Oracle

Confronta un'immagine BLOB con le immagini archiviate come ORDImage utilizzando SQL/MM Still Image

Alla fine sono tornato al problema e l'ho fatto funzionare.

Il problema era semplicemente che avevo un po' di null valori nella ORDImage campo...

Ho trovato il mio errore cercando di memorizzare la StillImage oggetto direttamente nelle mie FOTO tabella :

alter table PHOTOS add phot_source2 SI_Stillimage;
update photos p set p.phot_source2 = si_stillimage(p.phot_source.source.localData) where p.phot_id < 10;

e quindi implementando il seguente esempio minimo :

DECLARE
    l_img_obj   si_stillimage;
    l_avgcolor  si_averagecolor;
    l_colorhist si_colorhistogram;
    l_poscolor  si_positionalcolor;
    l_texture   si_texture;
    l_featurelist   si_featurelist;
    l_blob      BLOB;
    l_exist     INTEGER;
BEGIN
    -- get the blob from the ordimage
    SELECT p.phot_source.source.localdata
    INTO l_blob FROM photos p
    WHERE phot_id = 2;
    -- build the stillimage object from the blob
    l_img_obj := NEW si_stillimage(l_blob);
    -- get image features and build the featureList object
    l_avgcolor    := NEW si_averagecolor(l_img_obj);
    l_colorhist   := NEW si_colorhistogram(l_img_obj);
    l_poscolor    := NEW si_positionalcolor(l_img_obj);
    l_texture     := NEW si_texture(l_img_obj);
    l_featurelist := NEW si_featurelist(l_avgcolor, 1, l_colorhist, 1, l_poscolor, 1, l_texture, 1);
    -- check if a similar image is found in the table
    SELECT 1
    INTO l_exist
    FROM photos p
    WHERE si_scorebyftrlist(l_featurelist, p.phot_source2) = 0
    AND phot_id < 10
    AND rownum = 1;
    -- show message if at least one similar photo has been found
    IF (l_exist = 1) THEN       
        dbms_output.put_line('A similar photo has been found');
    END IF;
END;
/ 

Funzionava bene quando si limitava il phot_id a 10, anche sostituendo p.phot_source2 con si_mkstillimage1(p.phot_source.source.localdata) (che stava causando il problema). Ma non è riuscito durante la rimozione di phot_id restrizione. Così ho finalmente capito che avevo un po' di null valori nel phot_source colonna (ORDImage ) che possono causare il problema.

E in effetti chiamando SI_StillImage() costruttore con un null parametro porta al seguente messaggio di errore:

ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at "ORDSYS.SI_STILLIMAGE", line 27
ORA-06512: at "ORDSYS.SI_MKSTILLIMAGE1", line 6
ORA-06512: at line 24

Ho rimosso tutti i null valori da phot_source colonna e ora funziona tutto bene :)

Per andare oltre:

Lo svantaggio di questo è che ci vuole molto tempo per fare il confronto con tutte le immagini memorizzate nella tabella (1155 secondi (circa 20 min) per 5000 fotografie). Quindi ho provato a memorizzare le caratteristiche delle immagini direttamente nella tabella:

alter table photos add (
    phot_averagecolor si_averagecolor,
    phot_colorhistogram si_colorhistogram,
    phot_positionalcolor si_positionalcolor,
    phot_texture si_texture
)

update photos p set
    p.phot_averagecolor = si_averagecolor(si_stillimage(p.phot_source.source.localData)),
    p.phot_colorhistogram = si_colorhistogram(si_stillimage(p.phot_source.source.localData)),
    p.phot_positionalcolor = si_positionalcolor(si_stillimage(p.phot_source.source.localData)),
    p.phot_texture = si_texture(si_stillimage(p.phot_source.source.localData))
where p.phot_id < 10

E poi fai il confronto in questo modo:

-- get the blob from the ordimage
SELECT p.phot_source.source.localdata
INTO l_blob FROM photos p
WHERE phot_id = 2;
-- build the stillimage object from the blob
l_img_obj := NEW si_stillimage(l_blob);
-- get image features and build the featureList object
l_avgcolor    := si_averagecolor(l_img_obj);
l_colorhist   := si_colorhistogram(l_img_obj);
l_poscolor    := si_positionalcolor(l_img_obj);
l_texture     := si_texture(l_img_obj);
l_featurelist := NEW si_featurelist(l_avgcolor, 1, l_colorhist, 1, l_poscolor, 1, l_texture, 1);
-- check if a similar image is found in the table
SELECT 1
INTO l_exist
FROM photos p
WHERE p.phot_averagecolor = l_avgcolor
AND p.phot_colorhistogram = l_colorhist
AND p.phot_positionalcolor = l_poscolor
AND p.phot_texture = l_texture
AND p.phot_id < 10
AND rownum = 1;

Ma dà il seguente errore in quanto non sembra possibile confrontare le caratteristiche dell'immagine direttamente usando il = operatore :

ORA-22901: cannot compare VARRAY or LOB attributes of an object type
ORA-06512: at line 24

Ho pensato che una soluzione sarebbe stata quella di memorizzare le caratteristiche dell'immagine come valori numerici, ma ho letto l'intero documentazione e non ho trovato alcun modo per ottenere alcun valore numerico corrispondente da una funzione dell'immagine.

Fortunatamente, SI_score le funzioni sono fornite per ciascuna caratteristica dell'immagine, quindi possiamo utilizzare quanto segue per confrontare le immagini:

DECLARE
    l_img_obj   si_stillimage;
    l_blob      BLOB;
    l_exist     INTEGER;
BEGIN
    -- get the blob from the ordimage
    SELECT p.phot_source.source.localdata
    INTO l_blob FROM photos p
    WHERE phot_id = 2;
    -- build the stillimage object from the blob
    l_img_obj := NEW si_stillimage(l_blob);
    -- check if a similar image is found in the table
    SELECT 1
    INTO l_exist
    FROM photos p
    WHERE p.phot_averagecolor.SI_Score(l_img_obj) = 0
    AND p.phot_colorhistogram.SI_Score(l_img_obj) = 0
    AND p.phot_positionalcolor.SI_Score(l_img_obj) = 0
    AND p.phot_texture.SI_Score(l_img_obj) = 0
    AND rownum = 1;
    -- show message
    dbms_output.put_line(l_count || ' similar photo(s) found');
END;
/

Ho ridotto il tempo da 1155 secondi (circa 20 minuti) a 226 secondi (meno di 3 minuti) per 5000 immagini.

Lo so, è ancora molto lento, ma non riesco a trovare un altro modo per migliorare le prestazioni..., se qualcuno ha un'idea non esiti a condividere.