sql >> Database >  >> RDS >> Oracle

Vergelijk een BLOB-afbeelding met afbeeldingen die zijn opgeslagen als ORDImage met behulp van SQL/MM Still Image

Ik kwam eindelijk terug op het probleem en kreeg het aan het werk.

Het probleem was gewoon dat ik wat null . had waarden in de ORDImage veld...

Ik heb mijn fout gevonden door te proberen de StillImage . op te slaan object rechtstreeks in mijn FOTO'S tafel :

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;

en vervolgens het volgende minimale voorbeeld implementing implementeren :

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

Het werkte prima bij het beperken van de phot_id tot 10, zelfs door p.phot_source2 . te vervangen met si_mkstillimage1(p.phot_source.source.localdata) (wat het probleem veroorzaakte). Maar het mislukte bij het verwijderen van de phot_id beperking. Dus ik begreep eindelijk dat ik wat null . had waarden in de phot_source kolom (ORDImage ) die het probleem kan veroorzaken.

En inderdaad het aanroepen van SI_StillImage() constructor met een null parameter leidt tot de volgende foutmelding:

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

Ik heb alle null . verwijderd waarden uit de phot_source kolom en alles werkt nu goed :)

Om verder te gaan:

Het nadeel hiervan is dat het erg lang duurt om de vergelijking te maken met alle afbeeldingen die in de tabel zijn opgeslagen (1155 seconden (ongeveer 20 min) voor 5000 foto's). Dus ik heb geprobeerd de functies van afbeeldingen rechtstreeks in de tabel op te slaan:

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

En doe dan de vergelijking als volgt:

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

Maar het geeft de volgende foutmelding omdat het niet mogelijk lijkt om afbeeldingskenmerken rechtstreeks te vergelijken met de = operator :

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

Ik dacht dat een oplossing zou zijn om afbeeldingskenmerken op te slaan als numerieke waarden, maar ik las de hele documentatie en ik heb geen enkele manier gevonden om een ​​corresponderende numerieke waarde van een afbeeldingsfunctie te krijgen.

Gelukkig, SI_score Er zijn functies voorzien voor elke afbeeldingsfunctie, dus we kunnen het volgende gebruiken om de afbeeldingen te vergelijken:

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

Ik heb de tijd teruggebracht van 1155 seconden (ongeveer 20 min) tot 226 seconden (minder dan 3 min) voor 5000 afbeeldingen.

Ik weet het, het is nog steeds erg traag, maar ik kan geen andere manier vinden om de prestaties te verbeteren..., als iemand een idee heeft, aarzel dan niet om het te delen.



  1. MySQL Galera-cluster herstellen van een asynchrone slaaf

  2. totaal voor limiet in mysql krijgen met dezelfde query?

  3. SQL Server - CASE gebruiken in WHERE-clausule

  4. Gegevensrijen retourneren uit een pl/sql-blok