图像旋转 C/C++中的图像缩放和旋转




图像旋转 (8)

没有“简单”的方式来表达这一点。 缩放和旋转都不是“微不足道”的过程。

谷歌它的二维图像库。 Magick ++可以作为divideandconquer.se的观点,但也有其他的。

缩放2D图像数组的最佳方法是什么? 例如,假设我有一个1024 x 2048字节的图像,每个字节都是一个像素。 每个像素都是从0到255的灰度级别。我希望能够通过任意因子来缩放此图像并获得新图像。 所以,如果我按0.68的比例缩放图像,我会得到一个尺寸为0.68 * 1024 x 0.68 * 2048的新图像。 一些像素将相互折叠。 而且,如果按照3.15的系数进行缩放,则会得到像素重复的较大图像。 那么,完成这个的最好方法是什么?

接下来,我希望能够以0到360度(0 - 2Pi)范围内的任意角度旋转图像。 旋转后裁剪图像不是问题。 什么是最好的方法来做到这一点?


你正在做的是将一组输入点映射到一组输出点。 问题的第一部分是确定调整大小或旋转的映射; 第二部分是处理不完全位于像素边界上的点。

映射调整大小非常简单:

x' = x * (width' / width)
y' = y * (height' / height)

旋转的映射只是有点困难。

x' = x * cos(a) + y * sin(a)
y' = y * cos(a) - x * sin(a)

确定离开网格的像素值的技术称为插值。 有许多这样的算法,在速度和最终图像质量上有很大的提高。 其中一些按质量/时间递增的顺序是最近邻,双线性,双三次和Sinc滤波器。


有很多方法可以缩放和旋转图像。 最简单的方法是:

dest[dx,dy] = src[dx*src_width/dest_width,dy*src_height/dest_height]

但是在减小尺寸时增加尺寸和细节损失时会产生块状效应。 有办法产生更好的结果,例如双线性滤波

对于旋转,可以使用旋转矩阵来计算src像素位置:

sx,sy = M(dx,dy)

其中M是将目标像素映射到源图像的矩阵。 再次,你需要做插值来产生非块状结果。

但是如果你不想进入图像处理的数学,有很多库可用。


point scaling(point p,float sx,float sy) {
    point s;

    int c[1][3];
    int a[1][3]={p.x,p.y,1};
    int b[3][3]={sx,0,0,0,sy,0,0,0,1};

    multmat(a,b,c);

    s.x=c[0][0];
    s.y=c[0][1];

    return s;
}

复制或丢弃像素不是最好的方法或图像调整大小,因为结果将显示像素化和jagginess。 为了获得最佳效果,您应该对图像进行重新采样 ,从而使得图像看起来更平滑。 有很多重采样的方法,比如双线性,双三次,lanczos等等。

看看wxWidgets中的BicubicResample函数。 它的作品将各种图像,不仅灰度,但你应该能够适应你的需求。 然后还有来自VirtualDub的重新采样代码。 Google Codesearch可能会显示更多相关的代码。

编辑:链接在预览中看起来不错,但张贴时被打破。 这很奇怪。 去谷歌代码搜索和分别查询“wxwidgets resamplebicubic”和“virtualdub resample”得到相同的结果。


查看英特尔性能基元 。 我之前使用过它,它在x86上产生接近最佳的性能。 还有一个测试程序,可以使用各种算法。


CxImage调整大小的方法会产生奇怪的结果。 我使用Resample和Resample2函数以及具有相同结果的插值方法的所有可用变体。 例如,尝试调整大小为1024 x 768的1024 x 768图像,并将其填充到大小为802 x 582的白色。您将发现图像上的像素与白色不同 。 您可以检查:在Windows画图中打开调整大小的图像,并尝试用黑色填充它。 结果一定会使你感到愉快。


CxImage是一个免费的库,用于处理图像,它可以做你想做的。 除了微不足道的东西,我没有亲自使用它,但我已经看到它反复推荐。





image-scaling