glDrawPixels/glCopyPixels 获得放大视图,产生严重夹紧的图像

发布于 2024-07-08 14:46:11 字数 2984 浏览 8 评论 0原文

尽管之前有一个问题(此处提出),但我们的项目仅限于使用 glDrawPixels,因此我们有做一些黑客活动。

功能要求之一是能够在图像的单击区域上显示放大的视图; 因此,在查看图像时,我想单击鼠标,然后在鼠标所在的位置显示 200% 的图像窗口。 当我拖动光标时,窗口应该跟随光标。

上下文设置如下:

大红皮书的代码如下所示:

        Gl.glShadeModel(Gl.GL_FLAT);
        Gl.glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
        Gl.glPixelStorei(Gl.GL_UNPACK_ALIGNMENT, 2);
        Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_LINE);

        Gl.glDisable(Gl.GL_SCISSOR_TEST);
        Gl.glDisable(Gl.GL_ALPHA_TEST);
        Gl.glDisable(Gl.GL_STENCIL_TEST);
        Gl.glDisable(Gl.GL_DEPTH_TEST);
        Gl.glDisable(Gl.GL_BLEND);
        Gl.glDisable(Gl.GL_DITHER);
        Gl.glDisable(Gl.GL_LOGIC_OP);
        Gl.glDisable(Gl.GL_LIGHTING);
        Gl.glDisable(Gl.GL_FOG);
        Gl.glDisable(Gl.GL_TEXTURE_1D);
        Gl.glDisable(Gl.GL_TEXTURE_2D);
        Gl.glPixelTransferi(Gl.GL_MAP_COLOR, Gl.GL_TRUE);
        Gl.glPixelTransferf(Gl.GL_RED_SCALE, 1.0f);
        Gl.glPixelTransferi(Gl.GL_RED_BIAS, 0);
        Gl.glPixelTransferf(Gl.GL_GREEN_SCALE, 1.0f);
        Gl.glPixelTransferi(Gl.GL_GREEN_BIAS, 0);
        Gl.glPixelTransferf(Gl.GL_BLUE_SCALE, 1.0f);
        Gl.glPixelTransferi(Gl.GL_BLUE_BIAS, 0);
        Gl.glPixelTransferi(Gl.GL_ALPHA_SCALE, 1);
        Gl.glPixelTransferi(Gl.GL_ALPHA_BIAS, 0);

然后调用使较小但缩放的图像看起来像

        int width = (int)((this.Width * 0.2)/2.0);
        Gl.glReadBuffer(Gl.GL_FRONT_AND_BACK);
        Gl.glRasterPos2i(0, 0);
        Gl.glBitmap(0, 0, 0, 0, mStartX - (width*2), mStartY, null);

        Gl.glPixelZoom(2.0f, 2.0f);
        Gl.glCopyPixels(mStartX - width, mStartY, width, width, Gl.GL_COLOR);

mStartY 和 mStartX 是单击发生的点。

问题是,显示的窗口确实破坏了查找表,并且实际上将图像限制为基本上黑白二值图像(即没有灰色阴影)。

数据是一个黑白无符号短数组,并使用以下代码设置:

        float step = (65535.0f / (float)(max - min));
        mColorTable = new ushort[65536];
        int i;
        for (i = 0; i < 65536; i++)
        {
            if (i < min)
                mColorTable[i] = 0;
            else if (i > max)
                mColorTable[i] = 65535;
            else
                mColorTable[i] = (ushort)((float)(i - min) * step);
        }       
        .... //some irrelevant code

        Gl.glPixelMapusv(Gl.GL_PIXEL_MAP_R_TO_R, 65536, mColorTable);
        Gl.glPixelMapusv(Gl.GL_PIXEL_MAP_G_TO_G, 65536, mColorTable);
        Gl.glPixelMapusv(Gl.GL_PIXEL_MAP_B_TO_B, 65536, mColorTable);

现在,根据 本文档,我应该使用 GL_PIXEL_MAP_I_TO_I 并将 INDEX_SCALE 和 INDEX_BIAS 设置为零,但这样做不会改变结果,即图像被严重限制。 我所说的“严格夹紧”是指它要么是黑色的,要么是白色的,几乎没有灰色阴影,但原始的未放大图像看起来就像预期的那样。

那么,如何避免放大视图的夹紧呢? 我应该创建第二个跟随光标的控件并用第一个控件中的数据填充吗? 这种方法似乎会将数组副本从显卡外部复制到 C# 中,从定义上来说,这几乎会变慢,从而使控件无响应。

哦,我正在使用 C# 和 Tao 框架,如果这很重要的话。

Despite an earlier question (asked here), our project is constrained to using glDrawPixels, so we have to do some hackery.

One of the feature requirements is to be able to have a magnified view show up on a clicked region of an image; so, looking at an image, I want to click the mouse, and have a 200% image window show up where the mouse is. As I drag my cursor, the window should follow the cursor.

The context is set up like:

The Big Red Book has code that looks like this:

        Gl.glShadeModel(Gl.GL_FLAT);
        Gl.glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
        Gl.glPixelStorei(Gl.GL_UNPACK_ALIGNMENT, 2);
        Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_LINE);

        Gl.glDisable(Gl.GL_SCISSOR_TEST);
        Gl.glDisable(Gl.GL_ALPHA_TEST);
        Gl.glDisable(Gl.GL_STENCIL_TEST);
        Gl.glDisable(Gl.GL_DEPTH_TEST);
        Gl.glDisable(Gl.GL_BLEND);
        Gl.glDisable(Gl.GL_DITHER);
        Gl.glDisable(Gl.GL_LOGIC_OP);
        Gl.glDisable(Gl.GL_LIGHTING);
        Gl.glDisable(Gl.GL_FOG);
        Gl.glDisable(Gl.GL_TEXTURE_1D);
        Gl.glDisable(Gl.GL_TEXTURE_2D);
        Gl.glPixelTransferi(Gl.GL_MAP_COLOR, Gl.GL_TRUE);
        Gl.glPixelTransferf(Gl.GL_RED_SCALE, 1.0f);
        Gl.glPixelTransferi(Gl.GL_RED_BIAS, 0);
        Gl.glPixelTransferf(Gl.GL_GREEN_SCALE, 1.0f);
        Gl.glPixelTransferi(Gl.GL_GREEN_BIAS, 0);
        Gl.glPixelTransferf(Gl.GL_BLUE_SCALE, 1.0f);
        Gl.glPixelTransferi(Gl.GL_BLUE_BIAS, 0);
        Gl.glPixelTransferi(Gl.GL_ALPHA_SCALE, 1);
        Gl.glPixelTransferi(Gl.GL_ALPHA_BIAS, 0);

And then the call to make the smaller-but-zoomed image looks like

        int width = (int)((this.Width * 0.2)/2.0);
        Gl.glReadBuffer(Gl.GL_FRONT_AND_BACK);
        Gl.glRasterPos2i(0, 0);
        Gl.glBitmap(0, 0, 0, 0, mStartX - (width*2), mStartY, null);

        Gl.glPixelZoom(2.0f, 2.0f);
        Gl.glCopyPixels(mStartX - width, mStartY, width, width, Gl.GL_COLOR);

where mStartY and mStartX are the points where the click happened.

Problem is, the window that shows up is really mangling the lookup tables, and really clamping the image down to essentially a black-and-white binary image (ie, no shades of grey).

The data is a black-and-white unsigned short array, and is set with this code:

        float step = (65535.0f / (float)(max - min));
        mColorTable = new ushort[65536];
        int i;
        for (i = 0; i < 65536; i++)
        {
            if (i < min)
                mColorTable[i] = 0;
            else if (i > max)
                mColorTable[i] = 65535;
            else
                mColorTable[i] = (ushort)((float)(i - min) * step);
        }       
        .... //some irrelevant code

        Gl.glPixelMapusv(Gl.GL_PIXEL_MAP_R_TO_R, 65536, mColorTable);
        Gl.glPixelMapusv(Gl.GL_PIXEL_MAP_G_TO_G, 65536, mColorTable);
        Gl.glPixelMapusv(Gl.GL_PIXEL_MAP_B_TO_B, 65536, mColorTable);

Now, according to this documentation, I should use GL_PIXEL_MAP_I_TO_I and set INDEX_SCALE and INDEX_BIAS to zero, but doing that does not change the result, that the image is severely clamped. And by 'severely clamped' I mean it's either black or white, with very few shades of grey, but the original non-magnified image looks like what's expected.

So, how do I avoid the clamping of the magnified view? Should I make a second control that follows the cursor and gets filled in with data from the first control? That approach seems like it would take the array copies outside of the graphics card and into C#, which would almost by definition be slower, and so make the control nonresponsive.

Oh, I'm using C# and the Tao framework, if that matters.

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

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

发布评论

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

评论(3

谷夏 2024-07-15 14:46:11

答案如下。 问题是 LUT 被应用了两次,因此在调用副本之前,调用:

Gl.glPixelTransferi(Gl.GL_MAP_COLOR, Gl.GL_FALSE);

然后,一旦完成,调用:

Gl.glPixelTransferi(Gl.GL_MAP_COLOR, Gl.GL_TRUE);

这样,我所描述的“极端钳位”就被删除了。

@thing2k - 您的解决方案导致复制发生在显卡外部,因此减慢了鼠标拖动的绘图速度,但没有修复双夹。

Here's the answer. The problem is that the LUT is being applied twice, so before calling the copy, call:

Gl.glPixelTransferi(Gl.GL_MAP_COLOR, Gl.GL_FALSE);

Then, once done, call:

Gl.glPixelTransferi(Gl.GL_MAP_COLOR, Gl.GL_TRUE);

That way, the 'extreme clamping' I was describing is removed.

@thing2k-- your solution causes the copy to happen outside the graphics card, so slows down the drawing on mouse drag, but doesn't fix the double clamp.

安人多梦 2024-07-15 14:46:11

拜托,请在顶部和全身撒上大量的糖、糖蜜、糖粉和高果糖玉米糖浆,解释一下为什么你不能只使用纹理映射来绘制这个图像。

纹理映射是 OpenGL 的一个核心、基本、日常、常规、普通、标准、典型、预期且总体上不错的功能。 它的版本是1.4。 为什么不使用它作为起点呢?

Please, pretty please with loads of sugar, molasses, sprinkles and a mist of high-fructose corn syrup on top and all over, explain why you cannot just use texture-mapping to draw this imagery.

Texture-mapping is a core, basic, everyday, run of the mill, garden-variety, standard, typical, expected, and just generally nice feature of OpenGL. It is in version 1.4. Why not use it as a starting point?

墨离汐 2024-07-15 14:46:11

如果我理解正确的话,那么这应该与您使用 glReadPixels 和 glDrawPixels 之后的内容接近。

抱歉,这是 C++ 而不是 C#,但 OpenGL 功能应该仍然相同。

// main.cpp
// glut Text

#ifdef __WIN32__
    #define WIN32_LEAN_AND_MEAN
    #include <windows.h>
#endif
#include <GL/glut.h>
#include <cstdio>

int WIDTH = 800;
int HEIGHT = 600;
int MouseButton, MouseY = 0, MouseX = 0;
const int size = 80;
char *image, rect[size*size*3];
int imagewidth, imageheight;

bool Init()
{
    int offset;
    FILE* file = fopen("image.bmp", "rb");
    if (file == NULL)
        return false;
    fseek(file, 10, SEEK_SET);
    fread(&offset, sizeof(int), 1, file);
    fseek(file, 18, SEEK_SET);
    fread(&imagewidth, sizeof(int), 1, file);
    fread(&imageheight, sizeof(int), 1, file);
    fseek(file, offset, SEEK_SET);
    image = new char[imagewidth*imageheight*3];
    if (image == NULL)
        return false;
    fread(image, 1, imagewidth*imageheight*3, file);
    fclose(file);
    return true;
}

void Reshape(int width, int height)
{
    WIDTH = width;
    HEIGHT = height;
    glViewport(0 , 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, width, 0, height);
}

void Display()
{
    int size2 = size/2;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glRasterPos2i(0,0);
    glPixelZoom(1.f, 1.f);
    glDrawPixels(imagewidth, imageheight, 0x80E0/*GL_RGB*/, GL_UNSIGNED_BYTE, image);
    glReadPixels(MouseX-size2, MouseY-size2, size, size, GL_RGB, GL_UNSIGNED_BYTE, rect);
    glPixelZoom(2.f, 2.f);
    glRasterPos2i(MouseX-size, MouseY-size);
    glDrawPixels(size, size, GL_RGB, GL_UNSIGNED_BYTE, rect);
    glFlush();
    glutSwapBuffers();
}

void Mouse(int button, int state, int x, int y)
{
    if (state == GLUT_DOWN)
        MouseButton &= (1<<button);
    else
        MouseButton &= ~(1<<button);
}

void MouseMove(int x, int y)
{
    MouseX = x;
    MouseY = HEIGHT - y;
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    if (Init() == false)
        return 1;
    glutInitWindowSize(WIDTH, HEIGHT);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutCreateWindow("glut_Text");
    glClearColor(0.25, 0.25, 0.25, 1.0);
    glutReshapeFunc(Reshape);
    glutDisplayFunc(Display);
    glutIdleFunc(Display);
    glutMouseFunc(Mouse);
    glutMotionFunc(MouseMove);
    glutPassiveMotionFunc(MouseMove);

    glutMainLoop();
    return 0;
}

希望这可以帮助。

If I understand you correctly then this should be close to what you after, using glReadPixels and glDrawPixels.

Sorry it's C++ not C# but the OpenGL function should still be the same.

// main.cpp
// glut Text

#ifdef __WIN32__
    #define WIN32_LEAN_AND_MEAN
    #include <windows.h>
#endif
#include <GL/glut.h>
#include <cstdio>

int WIDTH = 800;
int HEIGHT = 600;
int MouseButton, MouseY = 0, MouseX = 0;
const int size = 80;
char *image, rect[size*size*3];
int imagewidth, imageheight;

bool Init()
{
    int offset;
    FILE* file = fopen("image.bmp", "rb");
    if (file == NULL)
        return false;
    fseek(file, 10, SEEK_SET);
    fread(&offset, sizeof(int), 1, file);
    fseek(file, 18, SEEK_SET);
    fread(&imagewidth, sizeof(int), 1, file);
    fread(&imageheight, sizeof(int), 1, file);
    fseek(file, offset, SEEK_SET);
    image = new char[imagewidth*imageheight*3];
    if (image == NULL)
        return false;
    fread(image, 1, imagewidth*imageheight*3, file);
    fclose(file);
    return true;
}

void Reshape(int width, int height)
{
    WIDTH = width;
    HEIGHT = height;
    glViewport(0 , 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, width, 0, height);
}

void Display()
{
    int size2 = size/2;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glRasterPos2i(0,0);
    glPixelZoom(1.f, 1.f);
    glDrawPixels(imagewidth, imageheight, 0x80E0/*GL_RGB*/, GL_UNSIGNED_BYTE, image);
    glReadPixels(MouseX-size2, MouseY-size2, size, size, GL_RGB, GL_UNSIGNED_BYTE, rect);
    glPixelZoom(2.f, 2.f);
    glRasterPos2i(MouseX-size, MouseY-size);
    glDrawPixels(size, size, GL_RGB, GL_UNSIGNED_BYTE, rect);
    glFlush();
    glutSwapBuffers();
}

void Mouse(int button, int state, int x, int y)
{
    if (state == GLUT_DOWN)
        MouseButton &= (1<<button);
    else
        MouseButton &= ~(1<<button);
}

void MouseMove(int x, int y)
{
    MouseX = x;
    MouseY = HEIGHT - y;
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    if (Init() == false)
        return 1;
    glutInitWindowSize(WIDTH, HEIGHT);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutCreateWindow("glut_Text");
    glClearColor(0.25, 0.25, 0.25, 1.0);
    glutReshapeFunc(Reshape);
    glutDisplayFunc(Display);
    glutIdleFunc(Display);
    glutMouseFunc(Mouse);
    glutMotionFunc(MouseMove);
    glutPassiveMotionFunc(MouseMove);

    glutMainLoop();
    return 0;
}

Hope this helps.

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