【问题标题】:Why is iplRotate() not giving me correct results?为什么 iplRotate() 没有给我正确的结果?
【发布时间】:2009-05-15 21:07:06
【问题描述】:

sigh 很抱歉,我正在处理一些图像处理代码中使用英特尔 IPL(图像处理库)。这是我努力让图像正确旋转的故事。

  1. 我有一个源图像。它的尺寸 (w, h) 不一定是正方形。
  2. 它将旋转角度theta
  3. 我已计算出适合尺寸为 (w, h) 的图像旋转角度 theta 所需的输出尺寸。这个大小是(dw, dh)。我已经分配了一个具有该大小的目标缓冲区。
  4. 我想将源图像围绕源图像的中心 (w/2, h/2) 旋转角度 theta 并具有 那个 > 旋转后的图像在我的目标缓冲区居中。

iplRotate() 采用 2 个移位参数,xShiftyShift,表示图像应沿 x 和 y 移动的距离旋转后的轴。

问题是我无法让 iplRotate 在目标图像中居中旋转图像。它总是偏离中心。

我对 xShift 和 yShift 应该是什么的最佳猜测如下:

  • xShift = dw - w
  • yShift = dh - h

但这不起作用,我不确定还可以做什么来计算 xShiftyShift。有人对如何使用 iplRotate 做我想做的事有任何建议吗?

最后一点信息: 我再次尝试使用 iplGetRotateShift() 来计算 xShift 和 yShift,但无济于事。我想这会起作用:

iplGetRotateShift(dw / 2.0, dh / 2.0, theta, &xShift, &yShift);

但事实并非如此。


编辑: 我使用 Intel IPP 6.0 而不是 IPL 重写了代码,我看到了相同的错误结果。我无法想象英特尔在 2 个不同的库中轮换错误,所以我一定做错了某事


编辑: 我尝试了 Dani van der Meer 建议的以下 (IPP) 代码:

xShift = (dw - w) / 2.0;
yShift = (dh - h) / 2.0;
ippiAddRotateShift(w / 2.0, h / 2.0, angle, &xShift, &yShift);

不幸的是,仍然没有运气。那也不行。

【问题讨论】:

  • 我不清楚究竟你想做什么。您想将源图像围绕其原点 (0,0) 旋转某个角度 theta,然后将旋转后的图像置于目标图像的中心?或者,您是否要围绕源图像的中心(w/2、h/2)旋转源图像,然后将其置于目标图像的中心?
  • @jd141,第二个 - 我想围绕源图像的中心(w/2,h/2)旋转源图像,然后将其置于目标图像的中心。 IPL 的文档让我相信这是可能的。

标签: c++ windows image-processing intel-ipp


【解决方案1】:

使用 iplGetRotateShift 时,您需要在源图像中指定旋转中心。如果源图像和目标图像的大小相同,这将很有效。

在您的情况下,您需要额外的转变以使图像在目标图像中居中:

xShift = (dw - w) / 2.0;
yShift = (dh - h) / 2.0;

要结合这两个班次,您需要使用 ippiAddRotateShift 而不是 ippiGetRotateShift。

注意:这些函数是指IPP库5.3版(我有的版本)。我不确定 AddRotateShift 在 IPL 中是否可用。但是您在问题中提到您尝试使用 IPP 进行相同的操作,因此希望您可以使用 IPP 而不是 IPL。

你会得到这样的东西

xShift = (dw - w) / 2.0;
yShift = (dh - h) / 2.0;
ippiAddRotateShift(w / 2.0, h / 2.0, angle, &xShift, &yShift);

如果您在调用 ippiRotate 时使用这些移位,则图像应位于目标图像的中心。

我希望这会有所帮助。

编辑: 这是我用来测试的代码(从 w 到 dw 和 h 到 dh 的变化以及旋转角度都是随机的):

//Ipp8u* dst_p; Initialized somewhere else in the code
//Ipp8u* src_p; Initialized somewhere else in the code
int w = 1032;
int h = 778;
int dw = w - 40; // -40 is just a random change
int dh = h + 200; // 200 is just a random change
int src_step = w * 3;
int dst_step = dw * 3;
IppiSize src_size = { w, h };
IppiRect src_roi  = { 0, 0, w, h };
IppiRect dst_rect = { 0, 0, dw, dh };
double xShift = ((double)dw - (double)w) / 2.0;
double yShift = ((double)dh - (double)h) / 2.0;
ippiAddRotateShift((double)w / 2, (double)h / 2, 37.0, &xShift, &yShift);
ippiRotate_8u_C3R(src_p, src_size, src_step, src_roi, 
          dst_p, dst_step, dst_rect, 37.0, xShift, yShift, IPPI_INTER_NN);

【讨论】:

  • 在 IPL 中非常接近 - 因为没有 iplAddRotateShift,所以我在调用 iplGetRotateShift(x / 2.0, ...) 后才添加 (dx - x) / 2.0。不过,它仍然相差 10-15 像素 - 我将不得不尝试使用 IPP 看看我得到了什么。谢谢!
  • 抱歉,这也不起作用 :-( 我尝试使用 IPP,它给我的结果与 IPL 相同。
  • 很奇怪...我测试了我的代码,它看起来工作正常,图像的中心在 src 和 dst 图像中是相同的。只是为了确保我发布了我用来测试的完整代码块
  • 我会试一试 - 感谢您发布!只是出于好奇,您为什么将 src_step 设置为 (w * 3)? src_p 是 Ipp8u* 类型 - 图像的步骤不会只是 w 吗?
  • 我使用 RGB 图像。每个像素为 3 个字节,因此步长(以字节为单位)为 w * 3。
【解决方案2】:

我以前从未使用过(或听说过)IPL,所以我只是猜测 API 的作用。但是如果 iplRotate 旋转大约 (0, 0) 并且如果 iplGetRotateShift 做类似的事情,为什么不尝试旋转原始“盒子”的其他 3 个角(忽略 (0, 0),因为它保持不变): (w, 0), ( 0, h) 和 (w, h)。

您的结果将是一个带有一些负值的新框。你想“向后移动”,所以如果你明白我的意思,你所拥有的任何负值都会变为零。

【讨论】:

    【解决方案3】:

    根据我对文档的阅读,我认为您使用 iplGetRotateShift 错误。特别是,我认为您需要在源图像中指定旋转中心,而不是目标图像,因此:

    iplGetRotateShift( w / 2.0,  h / 2.0, angle, &xShift, &yShift );
    

    【讨论】:

    • 我已经尝试过了 - 但是,由于我的目标图像是旋转图像的最终大小而不是源图像的大小,因此最终旋转图像偏离中心。
    【解决方案4】:

    如果它仍然不适合您,那么我们可以确认这些假设是有效的吗?特别是第 3 点。您计算 dw 和 dh 的地方。

    数学

    dw = w * |cos(theta)| + h * |sin(θ)|
    dh = h * |cos(theta)| + w * |sin(θ)|

    所以如果 theta = pi/6 说,那么如果 w = 100 和 h = 150 那么大概 dw = 162?

    你得到的不正确位置是否随 theta 而变化?大概它适用于theta = 0? theta=pi/2 和 theta=pi/4 呢?

    【讨论】:

    • 我面前没有代码,但我相当确定这是我用来计算最终目标大小的公式。然而,无论如何,我所做的只是计算目标图像的大小。该大小可以是任何大小 - 我想要的只是旋转图像位于该目标矩形的中心。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 2011-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多