缩放2D图像阵列的最佳方法是什么?例如,假设我有一个1024 x 2048字节的图像,每个字节都是一个像素。每个像素都是从0到255的灰度级。我希望能够通过任意因子缩放此图像并获得新图像。因此,如果我将图像缩放0.68倍,我应该得到一个大小为0.68 * 1024 x 0.68 * 2048的新图像。一些像素将相互折叠。并且,如果我按比例缩放3.15,我会得到一个更大的图像,像素被复制。那么,实现这一目标的最佳方法是什么?
接下来,我希望能够将图像旋转任意角度,范围为0到360度(0 - 2Pi)。旋转后裁剪图像不是问题。最好的方法是什么?
答案 0 :(得分:13)
缩放和旋转图像的方法有很多种。最简单的扩展方法是:
dest[dx,dy] = src[dx*src_width/dest_width,dy*src_height/dest_height]
但是在减小尺寸时增加尺寸和丢失细节会产生块效应。有一些方法可以产生更好看的结果,例如bilinear filtering。
对于旋转,可以使用a rotation matrix:
计算src像素位置sx,sy = M(dx,dy)
其中M是将目标像素映射到源图像的矩阵。同样,您需要进行插值以产生非块状结果。
但如果你不想进入图像处理的数学,那么有很多库可用。
答案 1 :(得分:10)
没有“简单”的表达方式。缩放和旋转都不是"trivial" procesis.
谷歌它是一个2d成像库。 Magick++可以作为divideandconquer.se点的想法,但还有其他点。
答案 2 :(得分:10)
您正在做的是将一组输入点映射到一组输出点。问题的第一部分是确定调整大小或旋转的映射;第二部分是处理不完全位于像素边界上的点。
调整大小的映射很简单:
x' = x * (width' / width)
y' = y * (height' / height)
旋转映射只是稍微困难一点。
x' = x * cos(a) + y * sin(a)
y' = y * cos(a) - x * sin(a)
确定位于网格之外的像素值的技术称为插值。有许多这样的算法,范围广泛,速度和最终图像质量。其中一些按质量/时间递增顺序为最近邻,双线性,双三次和Sinc滤波器。
答案 3 :(得分:8)
你想自己做肮脏的工作还是ImageMagick为你做这件事?
答案 4 :(得分:3)
复制或丢弃像素不是最好的方法或图像大小调整,因为结果将显示像素化和jagginess。为了获得最佳效果,您应该重新采样图像,这样可以使得到的图像更加平滑。有许多重采样方法,如双线性,双三次方,lanczos等。
查看wxWidgets中的BicubicResample函数。它适用于所有类型的图像,不仅是灰度图像,而且您应该能够根据您的需要进行调整。然后还有重新采样代码from VirtualDub。 Google Codesearch可能会泄露更多相关代码。
编辑:链接在预览中看起来很好,但在发布时会被破坏。这很奇怪。转到google codesearch并分别查询“wxwidgets resamplebicubic”和“virtualdub resample”以获得相同的结果。
答案 5 :(得分:2)
CxImage 是一个用于处理图片的免费库,可以执行您想要的操作。 除了琐碎的东西,我没有亲自使用它,但我已经看过它反复推荐。
答案 6 :(得分:2)
尚未提及,所以我将指出OpenCV具有缩放和旋转图像的功能,以及大量其他实用程序。 它可能包含许多与问题无关的功能,但它很容易设置和用于此类库。
您可以尝试手动实现这样的转换,但缩放和旋转的简单方法通常会导致明显的细节丢失。
使用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());
答案 7 :(得分:0)
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;
}
答案 8 :(得分:0)
CxImage调整大小的方法会产生奇怪的结果。我使用Resample和Resample2函数以及所有可用的插值方法变体,结果相同。例如,尝试将填充了白色的1024 x 768图像调整为大小为802 x 582.您会发现图像上的像素颜色不同为白色!您可以检查:在Windows Paint中打开已调整大小的图像并尝试用黑色填充它。结果肯定会让你感到愉快。
答案 9 :(得分:0)
查看Intel Performance Primitives。我之前使用过它,它在x86上产生了近乎最佳的性能。还有一个测试程序可以使用各种算法。