Oracle
 sql >> Base de données >  >> RDS >> Oracle

Comparez une image BLOB à des images stockées en tant qu'ORDImage à l'aide d'une image fixe SQL/MM

Je suis finalement revenu sur le problème et je l'ai fait fonctionner.

Le problème était simplement que j'avais des null valeurs dans ORDImage champ...

J'ai trouvé mon erreur en essayant de stocker la StillImage objet directement dans mes PHOTOS tableau :

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;

puis implémenter l'exemple minimal suivant :

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;
/ 

Cela fonctionnait bien lors de la restriction du phot_id à 10, même en remplaçant p.phot_source2 avec si_mkstillimage1(p.phot_source.source.localdata) (ce qui causait le problème). Mais cela a échoué lors de la suppression du phot_id restriction. J'ai donc finalement compris que j'avais des null valeurs dans phot_source colonne (ORDImage ) qui peut causer le problème.

Et en effet en appelant SI_StillImage() constructeur avec un null paramètre conduit au message d'erreur suivant :

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

J'ai supprimé tous les null valeurs de la phot_source colonne et tout fonctionne bien maintenant :)

Pour aller plus loin :

L'inconvénient est qu'il faut beaucoup de temps pour faire la comparaison avec toutes les images stockées dans le tableau (1155 secondes (environ 20 min) pour 5000 Photos). J'ai donc essayé de stocker les caractéristiques des images directement dans la table :

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

Et ensuite faites la comparaison comme ceci :

-- 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;

Mais cela donne l'erreur suivante car il ne semble pas possible de comparer les caractéristiques de l'image directement en utilisant le = opérateur :

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

Je pensais qu'une solution serait de stocker les caractéristiques de l'image sous forme de valeurs numériques, mais j'ai lu l'intégralité de documentation et je n'ai trouvé aucun moyen d'obtenir une valeur numérique correspondante à partir d'une fonctionnalité d'image.

Heureusement, SI_score des fonctions sont fournies pour chaque fonctionnalité d'image, nous pouvons donc utiliser ce qui suit pour comparer les images :

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;
/

J'ai réduit le temps de 1155 secondes (environ 20 min) à 226 secondes (moins de 3 min) pour 5000 images.

Je sais, c'est encore très lent, mais je ne trouve pas d'autre moyen d'améliorer les performances..., si quelqu'un a une idée n'hésitez pas à partager.