如何使用 openGL (JGL) 缩放图像?

发布于 2024-08-27 08:58:00 字数 171 浏览 8 评论 0原文

我想使用 openGL 缩放图像,任何人都可以为我提供有关如何执行此操作的代码吗?
PS,我使用 JGL 作为 Java 的 openGL 库。

I want to scale an image using openGL, can anyone provide me with such code about how to do this ?
PS, I am using JGL as an openGL library for Java.

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

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

发布评论

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

评论(1

梦屿孤独相伴 2024-09-03 08:58:00

我将简要介绍这一点,因为您可以找到解决方案几乎每个部分的教程。

您需要从磁盘加载图像并创建纹理。

您需要创建一个具有所需目标尺寸(在您的情况下为双倍宽度、双倍高度)的帧缓冲区对象(FBO)。使 FBO 处于活动状态以进行渲染。

应用纹理渲染全屏四边形。

使用 glReadPixels() 读取结果。

就是这样......纹理映射硬件将为您重新缩放它。但它可能会比在 CPU 上完成时慢,特别是对于“缩放 2 倍”。

编辑:根据OP的要求,有必要包含源代码。

所以...要在 Java 中加载图像,您可以这样做:

BufferedImage img;
try {
    img = ImageIO.read(new File("myLargeImage.jpg"));
} catch (IOException e) { /* ... */ }
int w = img.getWidth(), h = img.getHeight();

对于 JGL,人们可能希望将图像转换为数组:

byte [][][] imageData = new byte[img.getWidth()][img.getHeight()][3]; // alloc buffer for RGB data
for(int y = 0; y < h; ++ y) {
    for(int x = 0; x < w; ++ x) {
        int RGBA = img.getRGB(x, y);
        imageData[x][y][0] = RGBA & 0xff;
        imageData[x][y][1] = (RGBA >> 8) & 0xff;
        imageData[x][y][2] = (RGBA >> 16) & 0xff;
    }
}

请注意,也可能有 alpha 通道(用于透明度),并且这可能是相当慢。也可以使用:

int[] rgbaData = img.GetRGB(0, 0, w, h, new int[w * h], 0, w);

但这不会以 JGL 期望的正确格式返回数据。运气不好。
然后你需要填充纹理:

int[] texId = {0};
gl.glGenTextures(1, texId); // generate texture id for your texture (can skip this line)
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glBindTexture(GL.GL_TEXTURE_2D, texId[0]); // bind the texture
gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); // set alignment of data in memory (a good thing to do before glTexImage)
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP); // set clamp (GL_CLAMP_TO_EDGE would be better)
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); // set linear filtering (so you can scale your image)
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, w, h, 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, imageData); // upload image data to the texture

一旦有了纹理,你就可以绘制东西了。让我们重新采样您的图像:

int newW = ..., newH = ...; // fill-in your values
gl.glViewport(0, 0, newW, newH); // set viewport

gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
gl.glColor3f(1.0f, 1.0f, 1.0f); // set "white" color
gl.glDisable(GL.GL_CULL_FACE); // disable backface culling
gl.glDisable(GL.GL_LIGHTING); // disable lighting
gl.glDisable(GL.GL_DEPTH_TEST); // disable depth test
// setup OpenGL so that it renders texture colors without modification (some of that is not required by default)

gl.glBegin(GL_QUADS);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex2f(-1.0f, -1.0f);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex2f(+1.0f, -1.0f);
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex2f(+1.0f, +1.0f);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex2f(-1.0f, +1.0f);
gl.glEnd();
// draw a fullscreen quad with your texture on it (scaling is performed here)

现在已渲染缩放的图像,需要做的就是下载它。

byte[][][] newImageData = new byte[newW][newH][3];
gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1); // set alignment of data in memory (this time pack alignment; a good thing to do before glReadPixels)
gl.glReadPixels(0, 0, newW, newH, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, newImageData);

然后可以将数据转换为 BufferedImage,就像输入图像 img 转换为 imageData 一样。

请注意,我使用了变量 gl,它是 GL 类的一个实例。将代码放入一些 JGL 示例中,它应该可以工作。

需要注意的是,JGL 似乎不支持帧缓冲区对象,因此您会受到 OpenGL 窗口大小的输出图像大小的限制(尝试创建较大的图像将导致黑色边框)。它可以通过使用多通道渲染来解决(逐块渲染图像并在内存中组装完整图像)。

I will be brief on this, as you can find tutorials for pretty much every part of the solution.

You need to load your image from the disk, and create a texture.

You need to create a framebuffer object (FBO) with the desired target dimensions (in your case, double width, double height). Make the FBO active for rendering.

Render a fullscreen quad with your texture applied.

Read the result using glReadPixels().

And that's it ... the texturemapping hardware will take care of rescaling it for you. But it will likely be slower than if done on CPU, especially for "scaling 2x".

EDIT: as requested by OP, it is necessary to include source code.

So ... for loading an image in Java, you would go for this:

BufferedImage img;
try {
    img = ImageIO.read(new File("myLargeImage.jpg"));
} catch (IOException e) { /* ... */ }
int w = img.getWidth(), h = img.getHeight();

For JGL, one might want to convert an image to an array:

byte [][][] imageData = new byte[img.getWidth()][img.getHeight()][3]; // alloc buffer for RGB data
for(int y = 0; y < h; ++ y) {
    for(int x = 0; x < w; ++ x) {
        int RGBA = img.getRGB(x, y);
        imageData[x][y][0] = RGBA & 0xff;
        imageData[x][y][1] = (RGBA >> 8) & 0xff;
        imageData[x][y][2] = (RGBA >> 16) & 0xff;
    }
}

Note that there could be alpha channel as well (for transparency) and that this will likely be quite slow. One could also use:

int[] rgbaData = img.GetRGB(0, 0, w, h, new int[w * h], 0, w);

But that doesn't return the data in the correct format expected by JGL. Tough luck.
Then you need to fill a texture:

int[] texId = {0};
gl.glGenTextures(1, texId); // generate texture id for your texture (can skip this line)
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glBindTexture(GL.GL_TEXTURE_2D, texId[0]); // bind the texture
gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); // set alignment of data in memory (a good thing to do before glTexImage)
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP); // set clamp (GL_CLAMP_TO_EDGE would be better)
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); // set linear filtering (so you can scale your image)
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, w, h, 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, imageData); // upload image data to the texture

Once you have a texture, you can draw stuff. Let's resample your image:

int newW = ..., newH = ...; // fill-in your values
gl.glViewport(0, 0, newW, newH); // set viewport

gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
gl.glColor3f(1.0f, 1.0f, 1.0f); // set "white" color
gl.glDisable(GL.GL_CULL_FACE); // disable backface culling
gl.glDisable(GL.GL_LIGHTING); // disable lighting
gl.glDisable(GL.GL_DEPTH_TEST); // disable depth test
// setup OpenGL so that it renders texture colors without modification (some of that is not required by default)

gl.glBegin(GL_QUADS);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex2f(-1.0f, -1.0f);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex2f(+1.0f, -1.0f);
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex2f(+1.0f, +1.0f);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex2f(-1.0f, +1.0f);
gl.glEnd();
// draw a fullscreen quad with your texture on it (scaling is performed here)

Now that the scaled image is rendered, all that needs to be done, is to download it.

byte[][][] newImageData = new byte[newW][newH][3];
gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1); // set alignment of data in memory (this time pack alignment; a good thing to do before glReadPixels)
gl.glReadPixels(0, 0, newW, newH, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, newImageData);

And then the data can be converted to BufferedImage in similar way the input image img was converted to imageData.

Note that I used variable gl, that is an instance of the GL class. Put the code into some JGL example and it should work.

One word of caution, JGL doesn't seem to support framebuffer objects, so that you are limited by output image size by your OpenGL window size (attempting to create larger images will result in black borders). It can be solved by using multipass rendering (render your image tile by tile and assemble the full image in memory).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文