3

我正在使用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: User-defined Exception),使用 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;

谢谢 !

4

2 回答 2

3

我终于回到了这个问题,并让它发挥作用。

问题只是我在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;
/ 

将其限制为 10 时它工作正常phot_id,即使通过替换p.phot_source2si_mkstillimage1(p.phot_source.source.localdata)导致问题)也是如此。但是在取消phot_id限制时失败了。所以我终于明白我在列(ORDImage)中有一些可能导致问题的值。phot_source

并且确实使用nullSI_StillImage()参数调用构造函数会导致以下错误消息:

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

我从列中删除了所有值,phot_source现在一切正常:)


更进一步:

这样做的缺点是与存储在表中的所有图像进行比较需要很长时间( 5000张照片需要1155 秒(大约 20 分钟))。所以我尝试将图像特征直接存储到表中:

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

对于5000张图像,我将时间从1155 秒(大约 20 分钟)减少到226 秒(不到 3 分钟)

我知道,它仍然很慢,但是我找不到其他提高性能的方法……如果有人有想法,请随时分享。

于 2012-07-27T14:20:02.707 回答
2

即使这是一年多以前的问题,我也是在寻找自己对另一个问题的答案时才发现的。但只是想知道,为什么需要按属性比较图像,这很慢。

最好的解决方案是为图像添加一个哈希 varchar 字段,然后比较这些哈希值。如果找到相同的哈希,则图片已经存在。这可以是示例 md5 哈希。当然,您需要运行一次此程序才能将现有图片数据库化。

使用图像的所有属性对其进行散列,但不使用文件名本身:大小、宽度、高度、颜色等。

当用户尝试添加新图像时,它会获取这些图像属性,将它们散列在一起,然后将该散列与数据库中的其他散列进行比较,如果匹配,则图像已经存在并忽略插入。

比较图像而不是“解包图像”方法的超快速版本。

于 2013-10-24T05:11:18.853 回答