【问题标题】:Compare a BLOB image to images stored as ORDImage using SQL/MM Still Image使用 SQL/MM Still Image 将 BLOB 图像与存储为 ORDImage 的图像进行比较
【发布时间】:2013-10-24 13:11:18
【问题描述】:

我正在使用 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", ligne 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;

谢谢!

【问题讨论】:

    标签: oracle plsql blob oracle11gr2


    【解决方案1】:

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

    问题只是我在 ORDImage 字段中有一些 null 值...


    我通过尝试将 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 值。

    确实使用 null 参数调用 SI_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 列中删除了所有 null 值,现在一切正常:)


    更进一步:

    这样做的缺点是与存储在表中的所有图像进行比较需要很长时间(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;
    /
    

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

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

    【讨论】:

      【解决方案2】:

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

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

      使用图像的各种属性对其进行哈希处理,而不是文件名本身:大小、宽度、高度、颜色等。

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

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

      【讨论】:

      • 谢谢你的回复,我还在想为什么我的大脑当时没有想到这个。我们最终决定不做图像比较,但如果我不得不回到问题上,我肯定会使用这个解决方案。
      猜你喜欢
      • 2019-12-06
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-16
      • 2016-10-02
      相关资源
      最近更新 更多