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

发布于 2024-07-09 12:58:56 字数 324 浏览 4 评论 0原文

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

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

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?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

鸠魁 2024-07-16 12:58:56

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

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

但这会在增加尺寸时产生块状效果,在减小尺寸时会产生细节损失。 有多种方法可以产生更好看的结果,例如双线性过滤

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

sx,sy = M(dx,dy)

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

但是,如果您不想深入了解图像处理的数学知识,可以使用很多库。

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:

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.

But there are plenty of libraries available if you don't want to get into the mathematics of image processing.

绝對不後悔。 2024-07-16 12:58:56

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

调整大小的映射很容易:

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

旋转的映射只是稍微困难一点。

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

确定网格外像素值的技术称为插值。 此类算法有很多,它们的速度和最终图像质量各不相同。 其中一些按照质量/时间递增的顺序是最近邻滤波器、双线性滤波器、双三次滤波器和 Sinc 滤波器。

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.

请远离我 2024-07-16 12:58:56

没有简单的方法可以实现这一点。 缩放和旋转都不是微不足道的过程。

因此,建议使用二维成像库。 Magick++ 可以是divideandconquer.se 指出的一个想法,但还有其他想法。

There is no simple way of accomplishing this. Neither scaling nor rotating are trivial processes.

It is therefore advisable to use a 2d imaging library. Magick++ can be an idea as divideandconquer.se point out, but there are others.

写下不归期 2024-07-16 12:58:56

您想自己做这些脏活还是可以ImageMagick 为您做?

Do you want to do the dirty work yourself or can ImageMagick do it for you?

一直在等你来 2024-07-16 12:58:56

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

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

编辑:链接在预览中看起来很好,但在发布时被破坏。 这很奇怪。 去google codesearch,分别查询“wxwidgets resamplebicubic”和“virtualdub resample”,得到相同的结果。

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 resample the image, which will give the resulting image a much smoother look. There are lots of methods for resampling, like bilinear, bicubic, lanczos etc.

Take a look at the ResampleBicubic function 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.

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.

甜是你 2024-07-16 12:58:56

目前尚未提及,因此我将指出 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());

OpenCV 网站

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

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.

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:

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.

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...)

/// 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 Website

They have some very nice documentation too.

野味少女 2024-07-16 12:58:56

CxImage是一个处理图像的免费库,它可以做什么你要。
除了一些琐碎的事情之外,我个人没有使用过它,但我多次看到推荐它。

CxImage is a free library for handling images, which can do what you want.
I haven't personally used it except for trivial stuff, but I've seen it recommended repeatedly.

决绝 2024-07-16 12:58:56

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

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 different to white! You can check this: open resized image in Windows Paint and try to fill it with black color. Result will surely amuse you.

走野 2024-07-16 12:58:56

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

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.

辞取 2024-07-16 12:58:56
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;
}
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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文