如何实现对千兆像素的位图平移/缩放?位图、缩放、如何实现、像素

由网友(安之素年)分享简介:在我的项目,我使用(uncom pressed 16位灰度)千兆像素只有来自高分辨率扫描仪用于测量目的的图像。由于这些位图不能加载到内存中(主要是由于内存碎片),我使用的是瓷砖(和瓷砖TIFF等格式的光盘)。 (见StackOverflow在此专题)In my project, I'm using (uncompre...

在我的项目,我使用(uncom pressed 16位灰度)千兆像素只有来自高分辨率扫描仪用于测量目的的图像。由于这些位图不能加载到内存中(主要是由于内存碎片),我使用的是瓷砖(和瓷砖TIFF等格式的光盘)。 (见StackOverflow在此专题)

In my project, I'm using (uncompressed 16-bit grayscale) gigapixel images which come from a high resolution scanner for measurement purposes. Since these bitmaps can not be loaded in memory (mainly due to memory fragmentation) I'm using tiles (and tiled TIFF on disc). (see StackOverflow topic on this)

我需要实现平移/缩放,如谷歌地图或的DeepZoom的方式。我要申请在$ P $前飞在屏幕上psenting它的图像处理,所以我不能用precooked库,它直接访问一个图像文件。用于变焦我打算保持在我的文件(金字塔存储)一个多分辨率图像。最有用的步骤似乎是+ 200%,50%并显示所有

I need to implement panning/zooming in a way like Google Maps or DeepZoom. I have to apply image processing on the fly before presenting it on screen, so I can not use a precooked library which directly accesses an image file. For zooming I intend to keep a multi-resolution image in my file (pyramid storage). The most useful steps seem to be +200%, 50% and show all.

我的code群是目前C#和.NET 3.5。目前,我认为形式类型,除非WPF给了我在这方面的巨大优势。我有一个可以返回底层图像的任何(处理)的部分方法。

My code base is currently C# and .NET 3.5. Currently I assume Forms type, unless WPF gives me great advantage in this area. I have got a method which can return any (processed) part of the underlying image.

具体问题:

在如何实现这个平移/变焦按需生成图像部分提示或引用 在任何code可以用来作为基础(preferably商业或LGPL / BSD许可证一样) 可以的DeepZoom用于此(即是有办法,我可以提供一个函数,瓷砖在正确的resulution当前缩放级别?)(我需要有像素精确的解决仍然)

推荐答案

我决定试试自己的东西。我想出了一个简单的GDI + code,它使用我已经拿到了地砖。我只是过滤掉哪些是相关的当前剪切区域的部分。它的工作原理像变魔术一样!请在下面找到我的code。 (表格设置双缓冲的最好成绩)

I decided to try something myself. I came up with a straightforward GDI+ code, which uses the tiles I've already got. I just filter out the parts which are relevant for current clipping region. It works like magic! Please find my code below. (Form settings double buffering for the best results)

 protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        Graphics dc = e.Graphics;
        dc.ScaleTransform(1.0F, 1.0F);
        Size scrollOffset = new Size(AutoScrollPosition);

        int start_x = Math.Min(matrix_x_size, 
                             (e.ClipRectangle.Left - scrollOffset.Width) / 256);
        int start_y = Math.Min(matrix_y_size, 
                             (e.ClipRectangle.Top - scrollOffset.Height) / 256);
        int end_x = Math.Min(matrix_x_size, 
                        (e.ClipRectangle.Right - scrollOffset.Width + 255) / 256);
        int end_y = Math.Min(matrix_y_size, 
                      (e.ClipRectangle.Bottom - scrollOffset.Height + 255) / 256);

        // start * contain the first and last tile x/y which are on screen 
        // and which need to be redrawn.
        // now iterate trough all tiles which need an update 
        for (int y = start_y; y < end_y; y++)
            for (int x = start_x; x < end_x; x++)
            {  // draw bitmap with gdi+ at calculated position.
                dc.DrawImage(BmpMatrix[y, x], 
                           new Point(x * 256 + scrollOffset.Width, 
                                     y * 256 + scrollOffset.Height));
            }
    }

要测试它,我已经创建了80×80 256瓦(420兆像素)的矩阵。当然,我会添加一些延迟加载在现实生活中。我可以离开砖出(空)如果没有加载它们。事实上,我已经要求我的委托人坚持8 GB的在他的机器,所以我没有理会表现太多。一旦装瓷砖可以保留在内存中。

To test it, I've created a matrix of 80x80 of 256 tiles (420 MPixel). Of course I'll have to add some deferred loading in real life. I can leave tiles out (empty) if they are not yet loaded. In fact, I've asked my client to stick 8 GByte in his machine so I don't have to bother about performance too much. Once loaded tiles can stay in memory.

public partial class Form1 : Form
{
    bool dragging = false;
    float Zoom = 1.0F;
    Point lastMouse;
    PointF viewPortCenter;

    private readonly Brush solidYellowBrush = new SolidBrush(Color.Yellow);
    private readonly Brush solidBlueBrush = new SolidBrush(Color.LightBlue);
    const int matrix_x_size = 80;
    const int matrix_y_size = 80;
    private Bitmap[,] BmpMatrix = new Bitmap[matrix_x_size, matrix_y_size];
    public Form1()
    {
        InitializeComponent();

        Font font = new Font("Times New Roman", 10, FontStyle.Regular);
        StringFormat strFormat = new StringFormat();
        strFormat.Alignment = StringAlignment.Center;
        strFormat.LineAlignment = StringAlignment.Center;
        for (int y = 0; y < matrix_y_size; y++)
            for (int x = 0; x < matrix_x_size; x++)
            {
                BmpMatrix[y, x] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
                //                    BmpMatrix[y, x].Palette.Entries[0] = (x+y)%1==0?Color.Blue:Color.White;

                using (Graphics g = Graphics.FromImage(BmpMatrix[y, x]))
                {
                    g.FillRectangle(((x + y) % 2 == 0) ? solidBlueBrush : solidYellowBrush, new Rectangle(new Point(0, 0), new Size(256, 256)));
                    g.DrawString("hello worldn[" + x.ToString() + "," + y.ToString() + "]", new Font("Tahoma", 8), Brushes.Black,
                        new RectangleF(0, 0, 256, 256), strFormat);
                    g.DrawImage(BmpMatrix[y, x], Point.Empty);
                }
            }

        BackColor = Color.White;

        Size = new Size(300, 300);
        Text = "Scroll Shapes Correct";

        AutoScrollMinSize = new Size(256 * matrix_x_size, 256 * matrix_y_size);
    }   

原来,这是比较容易的部分。获得多线程异步I / O在后台做的是要困难得多acchieve。不过,我知道了在这里所描述的工作方式。为了解决这个问题,更.NET /表多线程,而不是这个话题相关的。

Turned out this was the easy part. Getting async multithreaded i/o done in the background was a lot harder to acchieve. Still, I've got it working in the way described here. The issues to resolve were more .NET/Form multithreading related than to this topic.

在伪code它的工作原理是这样的:

In pseudo code it works like this:

after onPaint (and on Tick)
   check if tiles on display need to be retrieved from disc
       if so: post them to an async io queue
       if not: check if tiles close to display area are already loaded
           if not: post them to an async io/queue
   check if bitmaps have arrived from io thread
      if so: updat them on screen, and force repaint if visible

结果:我现在有自己的自定义控制,使用大约50兆字节的速度非常快获得任意大小(瓷砖)TIFF文件

Result: I now have my own Custom control which uses roughly 50 MByte for very fast access to arbitrary size (tiled) TIFF files.

阅读全文

相关推荐

最新文章