sql >> Base de Datos >  >> RDS >> Oracle

Compare una imagen BLOB con imágenes almacenadas como ORDImage usando SQL/MM Still Image

Finalmente volví al problema y lo hice funcionar.

El problema era simplemente que tenía algunos null valores en ORDImage campo...

Encontré mi error al tratar de almacenar la imagen fija objeto directamente en mis FOTOS mesa :

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;

y luego implementar el siguiente ejemplo mínimo :

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

Funcionaba bien al restringir el phot_id a 10, incluso reemplazando p.phot_source2 con si_mkstillimage1(p.phot_source.source.localdata) (que estaba causando el problema). Pero falló al eliminar el phot_id restricción. Así que finalmente entendí que tenía algo de null valores en el phot_source columna (ORDImage ) que pueden causar el problema.

Y de hecho llamando a SI_StillImage() constructor con un null parámetro conduce al siguiente mensaje de error:

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

Eliminé todo null valores de phot_source columna y todo funciona bien ahora :)

Para ir más allá:

La desventaja de esto es que lleva mucho tiempo hacer la comparación con todas las imágenes almacenadas en la tabla (1155 segundos (alrededor de 20 min) por 5000 fotos). Así que he intentado almacenar características de imágenes directamente en la tabla:

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

Y luego haz la comparación así:

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

Pero da el siguiente error ya que parece que no es posible comparar las características de la imagen directamente usando = operador :

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

Pensé que una solución sería almacenar las características de la imagen como valores numéricos, pero leí todo el documentación y no he encontrado ninguna forma de obtener ningún valor numérico correspondiente de una característica de imagen.

Afortunadamente, SI_score Se proporcionan funciones para cada característica de la imagen, por lo que podemos usar lo siguiente para comparar las imágenes:

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

Reduje el tiempo de 1155 segundos (alrededor de 20 min) a 226 segundos (menos de 3 min) por 5000 imágenes.

Lo sé, sigue siendo muy lento, pero no encuentro otra forma de mejorar el rendimiento..., si alguien tiene una idea que no dude en compartirla.