Bandingkan gambar BLOB dengan gambar yang disimpan sebagai ORDImage menggunakan Gambar Diam SQL/MM

Saya menggunakan Oracle 11g r2.

Saya memiliki tabel yang menyimpan gambar sebagai ORDImage :

PHOTOS (phot_id integer
        , phot_filename varchar2(256)
        , phot_source ordsys.ordimage)

Dan tabel sementara lainnya yang menyimpan gambar yang diunggah oleh pengguna sebagai BLOB.

INSERT_TEMP (itemp_id integer, itemp_source blob)

Saya ingin memindahkan gambar BLOB ke tabel PHOTOS hanya jika belum ada, dengan membandingkan kedua gambar. Saya perlu menggunakan metode SQL/MM Still Image karena metode ORDImageSignature tidak digunakan lagi di Oracle 11g.

Ini kodenya:

 declare
    [...]
 begin
    [...]
    -- get the blob from the temporary table (in_id passed as parameter)
    select itemp_source into l_img_blob from insert_temp where itemp_id = in_id;
    -- build the stillimage object from the blob
    l_img_obj := new si_stillimage(l_img_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 already exists
    select count(*) into l_exist from photos p where SI_ScoreByFtrList(l_featurelist, SI_MkStillImage1(p.phot_source.source.localdata)) = 0;
    if (l_exist > 0) then
       out_message := app_util.get_translated_message('ERR_SIMILAR_PHOTO_ALREADY_EXISTS');
    else
       /* here the blob is inserted into the PHOTOS table as ORDImage successfully */
       out_message := app_util.get_translated_message('SUC_PHOTO_INSERTED');
    end if;
 end;

Gambar berhasil dimasukkan sebagai ORDImage jika saya menghilangkan perbandingan, jika tidak, pengecualian akan dimunculkan (sqlcode: 1, sqlerrm: Pengecualian yang Ditentukan Pengguna), menggunakan DBMS_UTILITY.FORMAT_ERROR_BACKTRACE ia memberi tahu saya hal berikut:

ORA-06512: à "ORDSYS.SI_STILLIMAGE", ligne 27
ORA-06512: à "ORDSYS.SI_MKSTILLIMAGE1", ligne 6
ORA-06512: à "SURV.APP_CORE", ligne 212

baris 212 adalah baris yang memeriksa apakah gambar serupa sudah ada :

 select count(*) into l_exist
 from photos p 
 where SI_ScoreByFtrList(l_featurelist, SI_MkStillImage1(p.phot_source.source.localdata)) = 0;

Tampaknya masalahnya adalah ia tidak menerima p.phot_source.source.localdata sebagai parameter. Apakah Anda tahu bagaimana saya bisa menyelesaikan ini?

Saya juga sudah mencoba:

 select count(*) into l_exist 
 from photos p
 where l_featurelist.si_score(new si_stillimage1(p.phot_source.source.localdata)) = 0;

Terima kasih !


person Yann39    schedule 27.03.2012    source sumber


Jawaban (2)


Saya akhirnya kembali ke masalahnya, dan menyelesaikannya.

Masalahnya hanyalah saya memiliki beberapa nilai null di bidang ORDImage...


Saya menemukan kesalahan saya saat mencoba menyimpan objek StillImage langsung ke tabel FOTO saya :

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;

lalu terapkan contoh minimal berikut :

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

Itu berfungsi dengan baik ketika membatasi phot_id menjadi 10, bahkan dengan mengganti p.phot_source2 dengan si_mkstillimage1(p.phot_source.source.localdata) (yang menyebabkan masalah). Namun gagal saat menghapus batasan phot_id. Jadi saya akhirnya mengerti bahwa saya memiliki beberapa nilai null di kolom phot_source (ORDImage) yang dapat menyebabkan masalah.

Dan memang memanggil konstruktor SI_StillImage() dengan parameter null akan menghasilkan pesan kesalahan berikut:

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

Saya menghapus semua nilai null dari kolom phot_source dan semuanya berfungsi dengan baik sekarang :)


Untuk melangkah lebih jauh:

Kelemahannya adalah memerlukan waktu yang sangat lama untuk melakukan perbandingan dengan semua gambar yang disimpan dalam tabel (1155 detik (sekitar 20 menit) untuk 5000 foto) . Jadi saya mencoba menyimpan fitur gambar langsung ke dalam tabel:

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

Lalu lakukan perbandingan seperti ini:

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

Tapi ini memberikan kesalahan berikut karena sepertinya tidak mungkin membandingkan fitur gambar secara langsung menggunakan operator = :

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

Saya pikir solusinya adalah dengan menyimpan fitur gambar sebagai nilai numerik, tetapi saya membaca keseluruhan dokumentasi dan saya belum menemukan cara untuk mendapatkan nilai numerik yang sesuai dari fitur gambar.

Untungnya, SI_score fungsi disediakan untuk setiap fitur gambar, sehingga kita dapat menggunakan yang berikut ini untuk membandingkan gambar:

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

Saya mengurangi waktu dari 1155 detik (sekitar 20 menit) menjadi 226 detik (kurang dari 3 menit) untuk 5000 gambar.

Saya tahu, ini masih sangat lambat, tetapi saya tidak dapat menemukan cara lain untuk meningkatkan kinerja..., jika ada yang punya ide jangan ragu untuk berbagi.

person Yann39    schedule 27.07.2012

Bahkan ini adalah pertanyaan berumur lebih dari satu tahun yang baru saya temukan ketika mencari jawaban saya sendiri untuk masalah lain. Tapi hanya bertanya-tanya, Mengapa Anda perlu membandingkan gambar berdasarkan atribut, itu lambat.

Solusi terbaik adalah menambahkan bidang hash varchar untuk gambar dan kemudian membandingkan hash tersebut. Jika hash yang sama ditemukan maka gambar sudah ada. Ini bisa menjadi contoh hash md5. Tentu saja Anda perlu menjalankan prosedur ini sekali untuk sudah membuat database gambar yang ada.

Gunakan semua jenis atribut gambar untuk melakukan hash, tetapi bukan nama file itu sendiri: ukuran, lebar, tinggi, semua jenis warna.

Dan ketika pengguna mencoba menambahkan gambar baru, dibutuhkan atribut gambar tersebut, hash bersama-sama dan kemudian bandingkan hash tersebut dengan hash lain di database dan jika cocok maka gambar sudah ada dan abaikan penyisipan.

Versi super cepat untuk membandingkan gambar alih-alih metode "membongkar gambar".

person user2882624    schedule 24.10.2013
comment
Terima kasih atas balasan Anda, saya masih bertanya-tanya mengapa otak saya tidak memikirkan hal ini saat itu. Kami akhirnya memutuskan untuk tidak melakukan perbandingan gambar tetapi jika saya harus kembali ke masalah saya pasti akan menggunakan solusi ini. - person Yann39; 24.10.2013