Порівняйте зображення 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-зображення до таблиці PHOTOS, лише якщо воно ще не існує, шляхом порівняння двох зображень. Мені потрібно використовувати методи 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. Тож я нарешті зрозумів, що в стовпці phot_source (ORDImage) є деякі значення null, які можуть спричинити проблему.

І дійсно, виклик конструктора SI_StillImage() з параметром 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 хвилин) для 5000 фотографій) . Тому я спробував зберегти функції зображень безпосередньо в таблиці:

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

Навіть це запитання понад рік тому, я щойно знайшов його, шукаючи власні відповіді на іншу проблему. Але просто цікаво, чому вам потрібно порівнювати зображення за атрибутами, це повільно.

Найкраще рішення — додати поле хеш-переменної для зображень, а потім порівняти ці хеші. Якщо знайдено той самий хеш, то зображення вже існує. Це може бути, наприклад, хеш md5. Звичайно, вам потрібно один раз запустити цю процедуру для вже наявних зображень у базі даних.

Використовуйте всі типи атрибутів зображення, щоб хешувати його, але не саму назву файлу: розмір, ширину, висоту, колір усіх видів.

І коли користувач намагається додати нове зображення, він бере ці атрибути зображення, хешує їх разом, а потім порівнює цей хеш з іншими хешами в базі даних, і якщо він збігається, зображення вже існує та ігнорує вставку.

Надшвидка версія для порівняння зображень замість методу «розпакування зображення».

person user2882624    schedule 24.10.2013
comment
Дякую за вашу відповідь, я все ще дивуюся, чому мій мозок не подумав про це в той час. Зрештою ми вирішили не порівнювати зображення, але якби мені довелося повернутися до проблеми, я б точно використав це рішення. - person Yann39; 24.10.2013