เปรียบเทียบรูปภาพ BLOB กับรูปภาพที่จัดเก็บเป็น ORDImage โดยใช้ภาพนิ่ง SQL/MM

ฉันใช้ Oracle 11g r2

ฉันมีตารางที่เก็บภาพเป็น ORDImage :

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

และอีกตารางชั่วคราวที่เก็บรูปภาพที่ผู้ใช้อัพโหลดเป็น BLOB

INSERT_TEMP (itemp_id integer, itemp_source blob)

ฉันต้องการย้ายรูปภาพ BLOB ไปยังตารางรูปถ่ายเฉพาะในกรณีที่ยังไม่มีอยู่ โดยการเปรียบเทียบรูปภาพทั้งสอง ฉันจำเป็นต้องใช้วิธี SQL/MM Still Image เนื่องจากวิธี ORDImageSignature เลิกใช้แล้วใน Oracle 11g

นี่คือรหัส:

 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;

แทรกรูปภาพเป็น ORDImage ได้สำเร็จหากฉันละเว้นการเปรียบเทียบ มิฉะนั้นจะทำให้เกิดข้อยกเว้น (sqlcode: 1, sqlerrm: ข้อยกเว้นที่ผู้ใช้กำหนด) โดยใช้ DBMS_UTILITY.FORMAT_ERROR_BACKTRACE โดยจะแจ้งสิ่งต่อไปนี้:

ORA-06512: ถึง "ORDSYS.SI_STILLIMAGE", เส้น 27
ORA-06512: ถึง "ORDSYS.SI_MKSTILLIMAGE1", เส้น 6
ORA-06512: ถึง "SURV.APP_CORE", เส้น 212

บรรทัด 212 เป็นบรรทัดที่ตรวจสอบว่ามีรูปภาพที่คล้ายกันอยู่แล้วหรือไม่:

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

ดูเหมือนว่าปัญหาคือมันไม่ยอมรับ p.phot_source.source.localdata เป็นพารามิเตอร์ คุณมีความคิดเกี่ยวกับวิธีที่ฉันสามารถแก้ปัญหานี้ได้หรือไม่?

ฉันได้ลองแล้ว:

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

ขอบคุณ !


person Yann39    schedule 27.03.2012    source แหล่งที่มา


คำตอบ (2)


ในที่สุดฉันก็กลับมาที่ปัญหาและทำให้มันใช้งานได้

ปัญหาคือฉันมีค่า null บางส่วนในฟิลด์ ORDImage...


ฉันพบข้อผิดพลาดโดยพยายามจัดเก็บวัตถุ StillImage ลงในตาราง PHOTOS ของฉันโดยตรง :

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;

จากนั้นจึงนำตัวอย่างขั้นต่ำไปใช้ต่อไปนี้ :

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

มันทำงานได้ดีเมื่อจำกัด phot_id ไว้ที่ 10 แม้ว่าจะแทนที่ p.phot_source2 ด้วย si_mkstillimage1(p.phot_source.source.localdata) (ซึ่งเป็นสาเหตุของปัญหา) แต่มันล้มเหลวเมื่อลบข้อจำกัด phot_id ในที่สุดฉันก็เข้าใจว่าฉันมีค่า null ในคอลัมน์ phot_source (ORDImage) ที่อาจทำให้เกิดปัญหาได้

และการเรียก SI_StillImage() Constructor ด้วยพารามิเตอร์ null ทำให้เกิดข้อความแสดงข้อผิดพลาดต่อไปนี้:

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

ฉันลบค่า null ทั้งหมดออกจากคอลัมน์ phot_source แล้วและตอนนี้ทั้งหมดก็ทำงานได้ดี :)


ไปต่อ:

ข้อเสียคือต้องใช้เวลานานมากในการเปรียบเทียบกับรูปภาพทั้งหมดที่จัดเก็บไว้ในตาราง (1155 วินาที (ประมาณ 20 นาที) สำหรับรูปภาพ 5,000 รูป) . ดังนั้นฉันจึงพยายามจัดเก็บคุณสมบัติรูปภาพลงในตารางโดยตรง:

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

แล้วทำการเปรียบเทียบดังนี้:

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

แต่ให้ข้อผิดพลาดต่อไปนี้เนื่องจากดูเหมือนว่าเป็นไปไม่ได้ที่จะเปรียบเทียบคุณลักษณะรูปภาพโดยตรงโดยใช้ตัวดำเนินการ = :

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

ฉันคิดว่าวิธีแก้ปัญหาคือจัดเก็บคุณสมบัติรูปภาพเป็นค่าตัวเลข แต่ฉันอ่าน เอกสารประกอบ และฉันไม่พบวิธีใดในการรับค่าตัวเลขที่เกี่ยวข้องจากคุณลักษณะรูปภาพ

โชคดีที่มีฟังก์ชัน SI_score ไว้สำหรับฟีเจอร์รูปภาพแต่ละรายการ ดังนั้นเราจึงสามารถใช้ฟังก์ชันต่อไปนี้เพื่อเปรียบเทียบรูปภาพได้ :

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

ฉันลดเวลาจาก 1155 วินาที (ประมาณ 20 นาที) เหลือ 226 วินาที (น้อยกว่า 3 นาที) สำหรับรูปภาพ 5000 ภาพ

ฉันรู้ว่ามันยังช้ามาก แต่ฉันไม่สามารถหาวิธีอื่นในการปรับปรุงประสิทธิภาพได้... ใครมีไอเดียก็อย่าลังเลที่จะแบ่งปัน

person Yann39    schedule 27.07.2012

แม้ว่านี่จะเป็นคำถามที่มีอายุมากกว่าหนึ่งปี แต่ฉันเพิ่งพบมันเมื่อค้นหาคำตอบของตัวเองสำหรับปัญหาอื่น แต่แค่สงสัยว่าทำไมคุณต้องเปรียบเทียบรูปภาพตามคุณลักษณะ นั่นจึงช้า

ทางออกที่ดีที่สุดคือการเพิ่มฟิลด์ varchar แฮชสำหรับรูปภาพ แล้วเปรียบเทียบแฮชเหล่านั้น หากพบแฮชเดียวกัน แสดงว่ารูปภาพนั้นมีอยู่แล้ว นี่อาจเป็นตัวอย่างแฮช md5 แน่นอน คุณต้องเรียกใช้ขั้นตอนนี้หนึ่งครั้งเพื่อฐานข้อมูลรูปภาพที่มีอยู่แล้ว

ใช้คุณลักษณะทุกประเภทของรูปภาพเพื่อแฮช แต่ไม่ใช่ชื่อไฟล์: ขนาด ความกว้าง ความสูง การระบายสี ทุกชนิด

และเมื่อผู้ใช้พยายามเพิ่มรูปภาพใหม่ ระบบจะนำแอตทริบิวต์รูปภาพเหล่านั้นมาแฮชเข้าด้วยกันแล้วเปรียบเทียบแฮชนั้นกับแฮชอื่น ๆ ในฐานข้อมูล และหากตรงกัน รูปภาพนั้นมีอยู่แล้วและไม่ต้องสนใจส่วนแทรก

เวอร์ชันที่เร็วเป็นพิเศษในการเปรียบเทียบรูปภาพแทนการใช้วิธี "แกะรูปภาพ"

person user2882624    schedule 24.10.2013
comment
ขอบคุณสำหรับคำตอบ ฉันยังคงสงสัยว่าทำไมตอนนั้นสมองของฉันถึงไม่คิดเรื่องนี้ ในที่สุดเราก็ตัดสินใจว่าจะไม่ทำการเปรียบเทียบรูปภาพ แต่ถ้าฉันต้องกลับไปที่ปัญหา ฉันจะใช้วิธีแก้ปัญหานี้อย่างแน่นอน - person Yann39; 24.10.2013