sql >> Databasteknik >  >> RDS >> Oracle

Jämför en BLOB-bild med bilder lagrade som ORDImage med SQL/MM-stillbild

Jag kom äntligen tillbaka till problemet och fick det att fungera.

Problemet var helt enkelt att jag hade någon null värden i ORDImage fält...

Jag hittade mitt fel genom att försöka lagra Stillbilden objekt direkt till mina FOTO tabell :

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;

och sedan implementera följande minimala exempel :

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

Det fungerade bra när du begränsade phot_id till 10, även genom att ersätta p.phot_source2 med si_mkstillimage1(p.phot_source.source.localdata) (som orsakade problemet). Men det misslyckades när phot_id togs bort restriktion. Så jag förstod äntligen att jag hade någon null värden i phot_source kolumn (ORDImage ) som kan orsaka problemet.

Och verkligen anropar SI_StillImage() konstruktör med en null parametern leder till följande felmeddelande:

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

Jag tog bort alla null värden från phot_source kolumn och allt fungerar bra nu :)

Så här går du vidare:

Nackdelen med detta är att det tar väldigt lång tid att göra jämförelsen med alla bilder som finns lagrade i tabellen (1155 sekunder (cirka 20 min) för 5 000 foton). Så jag har försökt att lagra bildfunktioner direkt i tabellen :

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

Och gör sedan jämförelsen så här :

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

Men det ger följande fel eftersom det inte verkar möjligt att jämföra bildfunktioner direkt med = operatör :

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

Jag trodde att en lösning skulle vara att lagra bildfunktioner som numeriska värden, men jag läste hela dokumentation och jag har inte hittat något sätt att få något motsvarande numeriskt värde från en bildfunktion.

Lyckligtvis, SI_score funktioner finns för varje bildfunktion, så vi kan använda följande för att jämföra bilderna:

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

Jag minskade tiden från 1155 sekunder (cirka 20 min) till 226 sekunder (mindre än 3 min) för 5 000 bilder.

Jag vet, det är fortfarande väldigt långsamt, men jag kan inte hitta något annat sätt att förbättra prestationerna..., om någon har en idé, tveka inte att dela.



  1. Spatial Index används inte

  2. Skillnad mellan BINARY(16) och CHAR(32) vid lagring av MD5 i databasen

  3. MYSQL:DECIMAL med en noggrannhet på 10 siffror efter kommatecken

  4. SQLite Node.js