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

缩放2D图像arrays的最佳方法是什么? 例如,假设我有一个1024 x 2048字节的图像,每个字节都是一个像素。 每个像素都是从0到255的灰度级。我希望能够通过任意因子缩放此图像并获得新图像。 因此,如果我将图像缩放0.68倍,我应该得到一个大小为0.68 * 1024 x 0.68 * 2048的新图像。 一些像素将相互折叠。 而且,如果我按比例缩放3.15,我会得到一个更大的图像,像素被复制。 那么,实现这一目标的最佳方法是什么?

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

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

谷歌它为2d成像库。 Magick ++可以作为divideandconquer.se点的想法,但还有其他。

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

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

但是当减小尺寸时增加尺寸和细节损失会产生块效应。 有一些方法可以产生更好看的结果,例如, 双线性滤波 。

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

 sx,sy = M(dx,dy) 

其中M是将目标像素映射到源图像的矩阵。 同样,您需要进行插值以产生非块状结果。

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

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

resize的映射很容易:

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

轮换映射只是有点困难。

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

用于确定位于网格之外的像素值的技术称为插值。 有许多这样的算法,范围广泛,速度和最终图像质量。 其中一些质量/时间递增的顺序是最近邻,双线性,双三次和Sinc滤波器。

你想自己做肮脏的工作还是ImageMagick能为你做这件事吗?

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

看看wxWidgets的BicubicResample函数。 它适用于所有类型的图像,不仅是灰度图像,而且您应该能够根据您的需要进行调整。 然后还有来自VirtualDub的重新采样代码。 Google Codesearch可能会泄露更多相关代码。

编辑:链接在预览中看起来很好,但在发布时会被破坏。 这很奇怪。 转到谷歌代码搜索并分别查询“wxwidgets resamplebicubic”和“virtualdub resample”以获得相同的结果。

CxImage是一个用于处理图像的免费库,可以执行您想要的操作。 我没有亲自使用过它,除了琐碎的东西,但我已经看过它反复推荐。

它尚未被提及,因此我将指出OpenCV具有缩放和旋转图像的function,以及大量其他实用程序。 它可能包含许多与问题无关的function,但它很容易设置和用于此类库。

您可以尝试手动实现这样的转换,但缩放和旋转的简单方法通常会导致明显的细节丢失。

使用OpenCV,可以像这样进行缩放:

 float scaleFactor = 0.68f; cv::Mat original = cv::imread(path); cv::Mat scaled; cv::resize(original, scaled, cv::Size(0, 0), scaleFactor, scaleFactor, cv::INTER_LANCZOS4); cv::imwrite("new_image.jpg", scaled); 

使用Lanczos插值,可将图像缩小0.68倍。

我不熟悉旋转,但这是OpenCV网站上的一个教程的一部分,我已经编辑了相关部分。 (原文中也有偏斜和翻译……)

 /// Compute a rotation matrix with respect to the center of the image Point center = Point(original.size().width / 2, original.size().height / 2); double angle = -50.0; double scale = 0.6; /// Get the rotation matrix with the specifications above Mat rot_mat( 2, 3, CV_32FC1 ); rot_mat = getRotationMatrix2D(center, angle, scale); /// Rotate the image Mat rotated_image; warpAffine(src, rotated_image, rot_mat, src.size()); 

OpenCV网站

他们也有一些非常好的文档。

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

 point scaling(point p,float sx,float sy) { point s; int c[1][3]; int a[1][3]={px,py,1}; int b[3][3]={sx,0,0,0,sy,0,0,0,1}; multmat(a,b,c); sx=c[0][0]; sy=c[0][1]; return s; } 

查看Intel Performance Primitives 。 我之前使用过它,它在x86上产生了近乎最佳的性能。 还有一个测试程序可以使用各种算法。