C/C++ 中的图像缩放和旋转
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/299267/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Image scaling and rotating in C/C++
提问by kafuchau
What is the best way to scale a 2D image array? For instance, suppose I have an image of 1024 x 2048 bytes, with each byte being a pixel. Each pixel is a grayscale level from 0 to 255. I would like to be able to scale this image by an arbitrary factor and get a new image. So, if I scale the image by a factor of 0.68, I should get a new image of size 0.68*1024 x 0.68*2048. some pixels will be collapsed onto each other. And, if I scale by a factor of say 3.15, I would get a larger image with pixels being duplicated. So, what's the best way to accomplish this?
缩放二维图像阵列的最佳方法是什么?例如,假设我有一个 1024 x 2048 字节的图像,每个字节都是一个像素。每个像素都是从 0 到 255 的灰度级别。我希望能够通过任意因子缩放此图像并获得新图像。所以,如果我将图像缩放 0.68 倍,我应该得到一个大小为 0.68*1024 x 0.68*2048 的新图像。一些像素将相互折叠。而且,如果我按 3.15 的系数进行缩放,我会得到一个像素被复制的更大的图像。那么,实现这一目标的最佳方法是什么?
Next, I would like to be able to rotate an image by an arbitrary angle, in the range of 0 to 360 degrees (0 - 2Pi). Cropping of the image after rotating isn't an issue. What would be the best way to do this?
接下来,我希望能够在 0 到 360 度 (0 - 2Pi) 的范围内以任意角度旋转图像。旋转后裁剪图像不是问题。什么是最好的方法来做到这一点?
采纳答案by Pablo Herrero
There is no "simple" way of acommplish that. Both scaling and rotating are not "trivial" procesis.
没有“简单”的方式来实现这一点。缩放和旋转都不是“微不足道”的过程。
Google it for a 2d imaging library. Magick++can be an idea as divideandconquer.se points, but there are others.
用谷歌搜索二维图像库。Magick++可以是一个想法,如分而治之。se 点,但还有其他的。
回答by Skizz
There are many ways to scale and rotate images. The simplest way to scale is:
有多种缩放和旋转图像的方法。最简单的扩展方法是:
dest[dx,dy] = src[dx*src_width/dest_width,dy*src_height/dest_height]
but this produces blocky effects when increasing the size and loss of detail when reducing the size. There are ways to produce better looking results, for example, bilinear filtering.
但是这在增加尺寸时会产生块状效果,而在减小尺寸时会丢失细节。有一些方法可以产生更好看的结果,例如,双线性过滤。
For rotating, the src pixel location can be calculated using a rotation matrix:
对于旋转,可以使用旋转矩阵计算 src 像素位置:
sx,sy = M(dx,dy)
where M is a matrix that maps destination pixels to the source image. Again, you'll need to do interpolation to produce non-blocky results.
其中 M 是将目标像素映射到源图像的矩阵。同样,您需要进行插值以产生非块状结果。
But there are plenty of libraries available if you don't want to get into the mathematics of image processing.
但是如果你不想进入图像处理的数学,有很多可用的库。
回答by Mark Ransom
What you're doing is mapping a set of input points to a set of output points. The first part of the problem is to determine the mapping for your resizing or rotation; the second part is to handle points that don't lie exactly on a pixel boundary.
您正在做的是将一组输入点映射到一组输出点。问题的第一部分是确定调整大小或旋转的映射;第二部分是处理不完全位于像素边界上的点。
Mapping for a resize is easy:
调整大小的映射很容易:
x' = x * (width' / width)
y' = y * (height' / height)
Mapping for rotation is only a little bit harder.
旋转映射只是有点困难。
x' = x * cos(a) + y * sin(a)
y' = y * cos(a) - x * sin(a)
The technique for determining the value of pixels that lie off the grid is called interpolation. There are many such algorithms, ranging widely in speed and final image quality. A few of them in increasing order of quality/time are nearest neighbor, bilinear, bicubic, and Sinc filter.
确定网格外像素值的技术称为插值。有许多这样的算法,在速度和最终图像质量方面差别很大。其中一些按质量/时间递增的顺序是最近邻滤波器、双线性滤波器、双三次滤波器和 Sinc 滤波器。
回答by activout.se
Do you want to do the dirty work yourself or can ImageMagickdo it for you?
你想自己做这些肮脏的工作还是ImageMagick可以为你做?
回答by user38329
Duplicating or discarding pixels is not the best method or image resizing, as the results will show pixelation and jagginess. For the best results, you should resamplethe image, which will give the resulting image a much smoother look. There are lots of methods for resampling, like bilinear, bicubic, lanczos etc.
复制或丢弃像素不是最好的方法或图像调整大小,因为结果会显示像素化和锯齿。为了获得最佳效果,您应该对图像重新采样,这将使生成的图像看起来更加平滑。重采样的方法有很多,比如双线性、双三次、lanczos 等。
Take a look at the ResampleBicubicfunction from wxWidgets. It works will all kinds of images, not only greyscale, but you should be able to adapt it to your needs. Then there's also resampling code from VirtualDub. Google Codesearch may reveal more related code.
看看wxWidgets的ResampleBicubic函数。它适用于各种图像,不仅是灰度,而且您应该能够根据自己的需要进行调整。然后还有来自 VirtualDub的重采样代码。Google Codesearch 可能会显示更多相关代码。
EDIT: the links look fine in the preview, but are broken when posted. This is strange. Go to google codesearch and query for "wxwidgets resamplebicubic" and "virtualdub resample" respectively to get the same results.
编辑:链接在预览中看起来不错,但发布时已损坏。这很奇怪。去谷歌代码搜索并分别查询“wxwidgets resamplebicubic”和“virtualdub resample”得到相同的结果。
回答by Meta
It has not been mentioned yet, so I will point out that OpenCV has functions for scaling and rotating images, as well as an enormous number of other utilities. It may contain many features that are not relevant to the question, but it is very easy to setup and use for a library of its kind.
它还没有被提及,所以我将指出 OpenCV 具有缩放和旋转图像的功能,以及大量其他实用程序。它可能包含许多与问题无关的功能,但它非常容易设置和用于此类库。
You can try to implement transformations like this manually, but the simple approach to scaling and rotating will generally result in a significant loss of detail.
您可以尝试手动实现这样的转换,但是缩放和旋转的简单方法通常会导致大量细节丢失。
Using OpenCV, scaling can be done like so:
使用 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);
This scales the image down by a factor of 0.68 using Lanczos interpolation.
这使用 Lanczos 插值将图像缩小了 0.68 倍。
I am not as familiar with rotations, but here's part of an example from one of the tutorials on the OpenCV website that I have edited down to the relevant parts. (The original had skew and translation in it also...)
我对旋转不太熟悉,但这里是 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());
回答by peterchen
回答by peterchen
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;
}
回答by izogfif
CxImage resizing methods produce strange result. I used Resample and Resample2 functions with all available variations of interpolation methods with same result. For example, try to resize 1024 x 768 image filled with white color to size 802 x 582. You'll find that there are pixels on the image that have color differentto white! You can check this: open resized image in Windows Paint and try to fill it with black color. Result will surely amuse you.
CxImage 调整大小方法会产生奇怪的结果。我将 Resample 和 Resample2 函数与所有可用的插值方法变体一起使用,结果相同。例如,尝试将填充白色的 1024 x 768 图像调整为 802 x 582 大小。您会发现图像上的像素颜色与白色不同!您可以检查一下:在 Windows Paint 中打开调整大小的图像并尝试用黑色填充它。结果肯定会让你开心。
回答by Jon Clegg
Check out the Intel Performance Primitives. I have used it before and it produces near optimal performance on x86. There is also a test program that lets to play with the various algorithms.
查看英特尔性能原语。我以前使用过它,它在 x86 上产生了接近最佳的性能。还有一个测试程序可以使用各种算法。