Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Comparar uma imagem BLOB com imagens armazenadas como ORDImage usando SQL/MM Still Image


Finalmente voltei ao problema e consegui fazê-lo funcionar.

O problema era simplesmente que eu tinha alguns null valores na ORDImage campo...

Encontrei meu erro tentando armazenar a StillImage objeto diretamente em minhas FOTOS tabela :
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, em seguida, implementar o seguinte exemplo 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;
/ 

Estava funcionando bem ao restringir o phot_id para 10, mesmo substituindo p.phot_source2 com si_mkstillimage1(p.phot_source.source.localdata) (o que estava causando o problema). Mas falhou ao remover o phot_id restrição. Então eu finalmente entendi que eu tinha alguns null valores no phot_source coluna (ORDImage ) que pode causar o problema.

E, de fato, chamando SI_StillImage() construtor com um null parâmetro leva à seguinte mensagem de erro:
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

Eu removi todos os null valores do phot_source coluna e tudo está funcionando bem agora :)

Para ir mais longe:


A desvantagem disso é que leva muito tempo para fazer a comparação com todas as imagens armazenadas na tabela (1155 segundos (cerca de 20 min) por 5.000 fotos). Então, tentei armazenar recursos de imagens diretamente na tabela:
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 então faça a comparação assim:
-- 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;

Mas dá o seguinte erro, pois parece não ser possível comparar recursos de imagem diretamente usando o = operador:
ORA-22901: cannot compare VARRAY or LOB attributes of an object type
ORA-06512: at line 24

Achei que uma solução seria armazenar recursos de imagem como valores numéricos, mas li todo o documentação e não encontrei nenhuma maneira de obter nenhum valor numérico correspondente de um recurso de imagem.

Felizmente, SI_score funções são fornecidas para cada recurso de imagem, então podemos usar o seguinte para comparar as imagens:
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;
/

Reduzi o tempo de 1155 segundos (cerca de 20 min) para 226 segundos (menos de 3 min) por 5.000 imagens.

Eu sei, ainda está muito lento, mas não consigo encontrar outra maneira de melhorar as performances..., se alguém tiver uma ideia não hesite em compartilhar.