在 C++ 中拉伸和覆盖位图
我正在和维斯一起工作。 Std 2010 Cpp 和我一直在尝试找出如何从两个现有位图创建位图。
我真的不想使用两个 gl_drawbitmap 函数,每个函数一个,而是创建第三个位图和 gl_drawbitmap 将新的一个放到我的窗口上。我还尝试将第二个位图(我们称之为 b2)放置在第一个位图(b1)的中间,因此伪代码看起来有点像:(假设 b2 是 80 x 60)
place b2 on b1 stretched from
(width-wise middle of b1 -40, heightwise middle of b1-30)
to (widthwise middle of b1+40, heightwise middle of b1+30)
我知道glutGet(GLUT_WINDOW_WIDTH/HEIGHT) 来查找当前 WINDOW 的特定测量值,但我不知道如何为位图查找它。我还没有找到它们可行的证据,但是 b1.getHeight() 和 b1.getWidth() 可以解决问题吗?
总的来说,我在弄清楚如何进行两者的实际组合方面遇到了很多麻烦。
void drawbitmap(bitmap* b1, bitmap* b2)
{
...
}
与功能相关,这就是我试图放入代码的内容。
I'm working with Vis. Std 2010 Cpp and I've been trying to figure out how to create a bitmap from two existing bitmaps.
I don't really want to use two gl_drawbitmap functions, one for each, but rather create a third bitmap and gl_drawbitmap THAT new one out onto my window. I also am attempting to get the second bitmap(let's call it b2) to be placed in the middle of the first(b1), so the pseudo code would look kind of like: (assuming b2 is lets say 80 by 60)
place b2 on b1 stretched from
(width-wise middle of b1 -40, heightwise middle of b1-30)
to (widthwise middle of b1+40, heightwise middle of b1+30)
I know of glutGet(GLUT_WINDOW_WIDTH/HEIGHT) to find a current WINDOW's specific measurements, but I don't know how to find it for a bitmap. I haven't been able to find proof that they are viable, but would b1.getHeight() and b1.getWidth() do the trick?
I'm just overall having plenty of trouble figuring out how to do the actual COMBINATION of the two.
void drawbitmap(bitmap* b1, bitmap* b2)
{
...
}
Function related, it's what I'm trying to put the code in.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
无论您使用什么函数来加载图像,都应该为您提供两件事:一是图像信息,例如宽度和高度。另一个是图像数据,它是一个数字数组。
假设您得到图像
b1
和b2
,b1
和b2
是 GLubyte 数组。假设b1_w
、b1_h
、b2_w
和b2_h
是b1
的宽度和高度code> 和b2
(应该由位图加载函数提供给您)。你想要做的事情由两部分组成,首先,你需要拉伸
b1
。其次,你需要把它写在b2
的中间。事实上你可以同时做这两件事,但现在我将把它们分开。拉伸
要拉伸图像,您需要能够进行一些简单的数学运算。在介绍地图之前,我将告诉您图像转换的基本概念(旋转、拉伸等)。您可以做的最简单的事情就是遍历目标图像的像素,将它们转换回原始图片,并决定从原始图片中获取什么颜色并分配给该像素。
例如,如果要将图像的宽度和高度从
w1
和h1
拉伸到w2
和h2
,这是转换:其中
xt
和yt
是目标图像中的坐标,xs
和ys
是目标图像中的坐标源图像。逆变换是:在继续之前,让我们定义一个宏以使生活更轻松。由于数据数组是一维数组,但我们使用 x 和 y 索引,因此我们编写了一个宏来为我们进行转换。
(旁注:请注意,我假设图像以 RGB(或 BGR)格式存储,即每个像素有三个值。另请注意,如果您的图像宽度不是 4 的倍数,则有将是填充,并且每行宽度不会是
width*3
字节,而是width*3+something_to_make_it_divisible_by_4
在第二种情况下,您可以编写如下宏。 this:)
所以你的代码看起来像这样(所有宽度/高度和 x/y 值都是
float
除非另有说明)有三个值分配,因为有三个颜色分量(R,G和 B)。如果您有 alpha 2,请将其设置为 4。如果您使用灰度工作,请将其保留为 1(您明白了)
下一步是像素颜色的实际分配。这是不同的拉伸算法有所不同的地方,拉伸的质量取决于此步骤。
所以,这就是我们的想法。想象一下 xs 和 ys 是完美的四舍五入整数。嗯,这很简单,您只需选择源图像中该像素的颜色并将其放入目标中即可。但是,如果 xs 和 ys 不是整数怎么办?那么你会为目标像素选择哪种颜色呢?这里介绍两种常用的方法。
最近邻
这个很简单。它说,选择最接近您计算的位置的像素的颜色。例如,如果
(xs, ys)
为(12.78, 98.2)
,则选择点的颜色(13, 98)
。这就是您的代码中的内容:线性化
该方法需要一些数学知识。它的意思是,您获取
(xs, ys)
周围四个像素之间的线性化值,并将其选择为目标像素的颜色。怎么样?我会告诉你。想象一下这四个像素和计算出的(xs, ys)
周围四个像素的值是 v_{t,b}{l,r} (上、下、左、右的缩写)为如图所示。要线性化位置
(xs, ys)
的值,您可以获取(floor(xs), ys)
和(ceil(xs) 的线性化值), ys)
并再次对其进行线性化,或者首先对 y 进行相同的操作,然后对 x 进行相同的操作。所以你会得到:最后,你会得到
注意,你应该对图像的每个通道(例如 R、G 和 B)进行线性化,并将适当的 v 放入适当的索引中(INDEX(...)、INDEX(.例如..)+1 和 INDEX(...)+2)。
请注意,在这两种方法中,您都必须检查源图像中的计算索引,这样您就不会超出数组范围。如果这样做,您可以为超出数组边界的像素假设颜色为黑/白/中灰色。或者,您可以检查这些像素,如果像素不在数组中,则可以更改方法以仅处理源图像内的像素。
写在另一张图像上
这部分很简单。您有图像
stretched_b2
,并且希望将其写入b1
。如果您要在b1
中写入stretched_b2
的左下位置是(x_start, y_start)
,您只需编写:图片在这里:
,您已经将
两个部分组合在一起
的部分
现在记住在拉伸部分中,您在中 放置在拉伸部分中的 部分
h2
和w2
是拉伸目标图像的高度和宽度,还记得吗?这就是我在放置部分中所说的h2_stretched
和w2_stretched
。正如您所看到的,这些 for 循环迭代相同的事情。现在,在拉伸部分中,您计算目标图像的值,并在放置部分中将其复制到b1
上。好吧,您可以直接计算值并将其写入b1
中,而不是将其保存在临时目标图像中,这样您就可以得到:最后一点:图像操作虽然很简单,有很多索引检查,很难第一次就正确。为分段错误做好准备,如果您花了一些时间来调试它,也不要感到沮丧。
后注:我解释了这些供您学习,但是对于 OpenGL,如果我是您,我会将两个图像都转换为纹理,在适当的位置绘制
QUADS
,并让 OpenGL 为您拉伸图像。Whatever function you have that loads the image, should give you two things: One is the image info, such as width and height. Another is the image data, which is an array of numbers.
Let's say you get images
b1
andb2
,b1
andb2
being arrays of GLubyte. And let's sayb1_w
,b1_h
,b2_w
andb2_h
are the width and heights ofb1
andb2
(which should be provided to you by the bitmap load function).What you want to do consists of two parts, first, you need to stretch
b1
. Second, you need to write it in the middle ofb2
. In fact you can do both at the same time, but for now, I will keep them separated.Stretching
To stretch an image, you need to be able to do some simple math. Before getting to the map though, I will tell you the basic idea in image transformation (rotation, stretch etc). The simplest thing you can do is to go through the pixels of the target image, transform them back to the original picture, and decide what color to take from the original picture and assign to that pixel.
For example, if you want to stretch an image from width and height
w1
andh1
tow2
andh2
, here's the transformation:where
xt
andyt
are coordinates in the target image andxs
andys
are coordinates in the source image. The inverse transformation is:Before continuing, let's define a macro to make life easier. Since the array of data is a 1d array, but we use x and y indices, we write a macro to do the conversion for us.
(Sidenote: Note that I assumed the image is stored in RGB (or BGR), that is it has three values per pixel. Also note that if your image width is not a multiple of 4, then there would be padding and each row width will not be
width*3
bytes, but would bewidth*3+something_to_make_it_divisible_by_4
. In the second case, you could write the macro like this:)
So your code would look like this (all the width/height and x/y values are
float
unless otherwise specified)There are three value assignments, because there are three color components (R, G and B). If you have alpha two, make it 4. If you are working in grayscale, keep it 1 (you get the idea)
Next step is the actual assignment of the pixel color. This is where different stretching algorithms vary and the quality of your stretching is dependent on this step.
So, here's the idea. Imagine
xs
andys
to turn out to be perfect rounded integers. Well that's easy, you just pick the color of that pixel in the source image and put it in the target. BUT, what ifxs
andys
are not integers? Then which color would you take for the target pixel? Here are two common methods.Nearest Neighbor
This one is easy. It says, choose the color of the pixel that is closest to the location you computed. For example, if
(xs, ys)
was(12.78, 98.2)
, you choose the color of the point(13, 98)
. That is in your code you have:Linearization
This method needs a bit of math. What it says is, you take the linearized value in between the four pixels around
(xs, ys)
and select that as the target pixel's color. How is that? I'll show you. Imagine these four pixels and the computed(xs, ys)
The values of the four surrounding pixels are v_{t,b}{l,r} (abbreviations of top, bottom, left and right) as shown in the picture. To linearize the value for position
(xs, ys)
, you could either get the linearized value of(floor(xs), ys)
and(ceil(xs), ys)
and again linearize for that, or do the same first over y then x which is the same. So you get:Finally, you get
Note that you should do this linearization for every channel of the image (R, G and B for example) and put the appropriate v in the appropriate index (INDEX(...), INDEX(...)+1 and INDEX(...)+2 for example).
Note that in both methods you MUST check for the computed indices in the source image so that you wouldn't go out of the array bounds. If you do, you can assume a color of black/white/midgray for those pixels that go outside the array bounds. Or, you can check for those and if the pixel was out of the array, you change your method to only work with the ones that are inside the source image.
Writing over the other image
This part is simple. You have the image
stretched_b2
and you want to write it onb1
. If the bottom left position where you want to writestretched_b2
inb1
is(x_start, y_start)
, you simply write:You want to place the image here:
so easily, you have
Combining the two parts
Now remember in the stretching section, the part where you had
and in the placing section that you had
Well in the stretching section
h2
andw2
were the height and width of the stretched target image, remember? That's what I calledh2_stretched
andw2_stretched
in the placing section. So as you can see, these for loops iterate the same thing. Now in the stretching section, you compute the value of the target image, and in the placing section you copy it overb1
. Well, instead of keeping it in a temporary target image, you can directly compute the value and write it overb1
, so you'd have:Final note: Image manipulation is although trivial when you say it, has a lot of index checking and it's hard to get it right the first time. Be ready for segmentation faults and don't feel upset if it took you a while to debug it.
Post-final note: I explained these for you to learn, but with OpenGL, if I were you I would turn both images into textures, draw
QUADS
in appropriate positions and have OpenGL stretch the image for you.