离散小波变换整数Daub 5/3提升问题

5
我正在尝试对lena图像进行整数到整数的5/3提升。我一直在按照Walker、Nguyen和Chen的论文《基于小功耗低内存的小波图像压缩系统》(链接,截至2015年10月7日仍然有效)进行操作。
但是我遇到了问题。图像似乎并不完全正确。绿色和蓝色通道似乎有些溢出,这意味着后续的小波函数会在不应该有任何高频的地方找到高频。我还相当确定我做错了其他事情,因为我在高频部分的边缘看到了s0图像的一条线。
我的函数如下:
bool PerformHorizontal( Col24* pPixelsIn, Col24* pPixelsOut, int width, int pixelPitch, int height )
{
    const int widthDiv2 = width / 2;
    int y   = 0;
    while( y < height )
    {
        int x = 0;
        while( x < width )
        {
            const int n     = (x)       + (y * pixelPitch);
            const int n2    = (x / 2)   + (y * pixelPitch);

            const int s     = n2;
            const int d     = n2 + widthDiv2;

            // Non-lifting 5 / 3
            /*pPixelsOut[n2 + widthDiv2].r  = pPixelsIn[n + 2].r - ((pPixelsIn[n + 1].r + pPixelsIn[n + 3].r) / 2) + 128;
            pPixelsOut[n2].r                = ((4 * pPixelsIn[n + 2].r) + (2 * pPixelsIn[n + 2].r) + (2 * (pPixelsIn[n + 1].r + pPixelsIn[n + 3].r)) - (pPixelsIn[n + 0].r + pPixelsIn[n + 4].r)) / 8;

            pPixelsOut[n2   + widthDiv2].g  = pPixelsIn[n + 2].g - ((pPixelsIn[n + 1].g + pPixelsIn[n + 3].g) / 2) + 128;
            pPixelsOut[n2].g                = ((4 * pPixelsIn[n + 2].g) + (2 * pPixelsIn[n + 2].g) + (2 * (pPixelsIn[n + 1].g + pPixelsIn[n + 3].g)) - (pPixelsIn[n + 0].g + pPixelsIn[n + 4].g)) / 8;

            pPixelsOut[n2   + widthDiv2].b  = pPixelsIn[n + 2].b - ((pPixelsIn[n + 1].b + pPixelsIn[n + 3].b) / 2) + 128;
            pPixelsOut[n2].b                = ((4 * pPixelsIn[n + 2].b) + (2 * pPixelsIn[n + 2].b) + (2 * (pPixelsIn[n + 1].b + pPixelsIn[n + 3].b)) - (pPixelsIn[n + 0].b + pPixelsIn[n + 4].b)) / 8;*/

            pPixelsOut[d].r = pPixelsIn[n + 1].r    - (((pPixelsIn[n].r         + pPixelsIn[n + 2].r)   >> 1) + 127);
            pPixelsOut[s].r = pPixelsIn[n].r        + (((pPixelsOut[d - 1].r    + pPixelsOut[d].r)      >> 2) - 64);

            pPixelsOut[d].g = pPixelsIn[n + 1].g    - (((pPixelsIn[n].g         + pPixelsIn[n + 2].g)   >> 1) + 127);
            pPixelsOut[s].g = pPixelsIn[n].g        + (((pPixelsOut[d - 1].g    + pPixelsOut[d].g)      >> 2) - 64);

            pPixelsOut[d].b = pPixelsIn[n + 1].b    - (((pPixelsIn[n].b         + pPixelsIn[n + 2].b)   >> 1) + 127);
            pPixelsOut[s].b = pPixelsIn[n].b        + (((pPixelsOut[d - 1].b    + pPixelsOut[d].b)      >> 2) - 64);

            x += 2;
        }
        y++;
    }
    return true;
}

有些问题,但我只是想不通。有没有比我稍微聪明一点的人能指出我错在哪里?需要注意的是,您可以看到Daub 5/3未提升版本的工作代码,这也给我带来了相同的伪影...我很困惑,因为我曾经让它工作过(那是2年前的事了,我现在已经没有那个代码了)。
非常感谢任何帮助 :)
编辑:通过将低通像素夹紧到0至255范围内,我似乎已经消除了溢出问题。但我稍微担心这不是正确的解决方案。有人可以对此发表评论吗?

你好。很遗憾,这篇论文已经不再在线上了。您能否更新链接或提供其他下载方式?我目前也遇到了一些相同的问题(https://dev59.com/l4zda4cB1Zd3GeqPsup0)。如果您已经找到了答案,也许可以帮助回答我的问题? - markus_p
@markus_p:感谢您指出这一点。不幸的是,我再也找不到这篇论文了。所以我已经填写了论文的名称。 - Goz
1
这个链接似乎可以使用 http://people.uwec.edu/walkerjs/media/research_signpost_article.pdf - Ravi
@Ravi:很棒,已更新! - Goz
3个回答

1

您可以进行一些极限值测试,以查看溢出的可能性。例如:

  pPixelsOut[d].r = pPixelsIn[n + 1].r - (((pPixelsIn[n].r  + pPixelsIn[n + 2].r) >> 1) + 127);

If:
  pPixelsIn[n  ].r == 255
  pPixelsIn[n+1].r == 0
  pPixelsIn[n+2].r == 255

Then:
  pPixelsOut[d].r == -382


But if:
  pPixelsIn[n  ].r == 0
  pPixelsIn[n+1].r == 255
  pPixelsIn[n+2].r == 0

Then:
  pPixelsOut[d].r == 128

您有511个可能的值范围(-382..128),因此,为了避免溢出或夹紧,您需要一个额外的位、一些量化或另一种编码类型!


我在你发帖前大约30分钟就得出了同样的结论 :). 我打算尝试将其作为浮点数处理,然后再尝试将其转换回整数。这肯定不会是无损的。话虽如此,低通滤波器逻辑上只会产生偶数,这意味着我只需要7位来编码s1,这意味着我应该能够将符号位隐藏在最低位中... 尽管如此,我认为我会接受有损压缩,因为一旦我把这个工作做好了,最终的压缩肯定会是有损的 :) - Goz
如果想要绘制DWT转换后的图像(例如通过Matlab的imshow()函数),我该如何重新调整值以使它们回到[0...255]范围内? - markus_p

0

我假设数据已经被阈值化了?

我也不明白你为什么要加回+127和-64。


数据是标准的24位PNG格式。我加上128是因为论文上说要这么做。虽然它也说我应该加上128而不是减去64……但是我减去64可以获得更好的结果,这是我上次实现时记住的。 - Goz

0

好的,只要我将我的后向转换数据存储在一个short中,我就可以无损地进行前向转换然后再进行反向转换。显然,这需要比我希望的占用更多的空间,但这为我进入各种压缩算法提供了一个良好的起点。您还可以使用SSE2指令很好地同时压缩2个4组分像素。这是我设计的标准C前向转换:

        const int16_t dr    = (int16_t)pPixelsIn[n + 1].r   - ((((int16_t)pPixelsIn[n].r        + (int16_t)pPixelsIn[n + 2].r)  >> 1));
        const int16_t sr    = (int16_t)pPixelsIn[n].r       + ((((int16_t)pPixelsOut[d - 1].r   + dr)                           >> 2));

        const int16_t dg    = (int16_t)pPixelsIn[n + 1].g   - ((((int16_t)pPixelsIn[n].g        + (int16_t)pPixelsIn[n + 2].g)  >> 1));
        const int16_t sg    = (int16_t)pPixelsIn[n].g       + ((((int16_t)pPixelsOut[d - 1].g   + dg)                           >> 2));

        const int16_t db    = (int16_t)pPixelsIn[n + 1].b   - ((((int16_t)pPixelsIn[n].b        + (int16_t)pPixelsIn[n + 2].b)  >> 1));
        const int16_t sb    = (int16_t)pPixelsIn[n].b       + ((((int16_t)pPixelsOut[d - 1].b   + db)                           >> 2));

        pPixelsOut[d].r = dr;
        pPixelsOut[s].r = sr;

        pPixelsOut[d].g = dg;
        pPixelsOut[s].g = sg;

        pPixelsOut[d].b = db;
        pPixelsOut[s].b = sb;

创建其反转形式非常简单(一个非常简单的代数问题)。值得注意的是,您需要从右到左底部到顶部反转图像。接下来,我将尝试将此数据移入uint8_ts并丢失1或2位精度。对于压缩而言,这真的不是问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接