Сравните изображение 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, так как методы 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

Я думал, что решение будет состоять в том, чтобы хранить функции изображения в виде числовых значений, но я прочитал весь documentation, и я не нашел никакого способа получить соответствующее числовое значение из функции изображения.

К счастью, для каждой функции изображения предусмотрено 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