Bitmap & Texture2D 互轉方法蒐集

最近學習emgucv,我在寫讀攝像頭的程序然後需要bitmap 轉texture2D 其實可以直接使用setdata<bytes>的方法賦值,感覺幀率不是一般的低,是無法忍受的。

也試了多種方法,基本上都是無法忍受的。可能有人會用得到,將蒐集的列下來。

這是一些方法的蒐集。

Texture2D toBitmap 的方法

 

public static Bitmap FastTextureToBitmap(Texture2D texture) 
        { 
            // Setup pointer back to bitmap 
            Bitmap newBitmap = new Bitmap(texture.Width, texture.Height); 
            // Get color data from the texture 
            Microsoft.Xna.Framework.Graphics.Color[ textureColors = GetColorDataFromTexture(texture); 
            System.Drawing.Imaging.BitmapData bmpData = newBitmap.LockBits(new System.Drawing.Rectangle(0, 0, newBitmap.Width, newBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 
            // Loop through pixels and set values 
            unsafe 
            { 
                byte* bmpPointer = (byte*)bmpData.Scan0; 
                for (int y = 0; y < texture.Height; y++) 
                { 
                    for (int x = 0; x < texture.Width; x++) 
                    { 
                        bmpPointer[0] = textureColors[x + y * texture.Width].B; 
                        bmpPointer[1] = textureColors[x + y * texture.Width].G; 
                        bmpPointer[2] = textureColors[x + y * texture.Width].R; 
                        bmpPointer[3] = textureColors[x + y * texture.Width].A; 
                        bmpPointer += 4; 
                    } 
                    bmpPointer += bmpData.Stride - (bmpData.Width * 4); 
                } 
            } 
            textureColors = null; 
            newBitmap.UnlockBits(bmpData); 
            return newBitmap; 
        } 

 

bitmap to texture2D 的方法:

  private Texture2D GetTexture(GraphicsDevice dev, System.Drawing.Bitmap bmp)
        {
            int[] imgData = new int[bmp.Width * bmp.Height];
            Texture2D texture = new Texture2D(dev, bmp.Width, bmp.Height);
            unsafe
            {
                // lock bitmap
                System.Drawing.Imaging.BitmapData origdata =
                    bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
                uint* byteData = (uint*)origdata.Scan0;
                // Switch bgra -> rgba
                for (int i = 0; i < imgData.Length; i++)
                {
                    byteData[i] = (byteData[i] & 0x000000ff) << 16 | (byteData[i] & 0x0000FF00) | (byteData[i] & 0x00FF0000) >> 16 | (byteData[i] & 0xFF000000);
                }
                // copy data
                System.Runtime.InteropServices.Marshal.Copy(origdata.Scan0, imgData, 0, bmp.Width * bmp.Height);
                byteData = null;
                // unlock bitmap
                bmp.UnlockBits(origdata);
            }
            texture.SetData(imgData);
            return texture;
        }



貌似對於賦值這一步C#的效率好像不高,幀率一般都會降的很低。我還沒有想到更好的辦法,表示無奈中。。。 


實際上還有一個方法可以直接使用

BitmapSourceExtensions.CopyTo Method (BitmapSource, Texture2D)

此方法需要使用  System.Windows.Media.Imaging 我倒還沒有嘗試過。估計應該是挺好用的。
例子可以參見http://msdn.microsoft.com/en-us/library/gg712857(v=vs.96).aspx 
這種方法試過,但是不管用,自己也是新手,搞不定了。。。就扔了,有人搞懂的話,可以回個帖。~
值得一提的是對於BITMAP的格式,要值得仔細查看一下,不要直接套用上面的方法

這個是另外一種方法,試了一下貌似幀率有所提高,但依然還是不如窗體直接用的那種性能好。都準備放棄XNA了。。。
 1publicstatic Texture2D BitmapToTexture2D( 
2 GraphicsDevice GraphicsDevice,
 3 System.Drawing.Bitmap image)
 4{
 5 // Buffer size is size of color array multiplied by 4 because
6// each pixel has four color bytes
7int bufferSize = image.Height * image.Width * 4; 
8 
9 // Create new memory stream and save image to stream so
10// we don't have to save and read file 
11 System.IO.MemoryStream memoryStream =
 12 new System.IO.MemoryStream(bufferSize);
13 image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
 14 15 // Creates a texture from IO.Stream - our memory stream
16 Texture2D texture = Texture2D.FromStream(
 17 GraphicsDevice, memoryStream);
 18 19return texture;
20} 


我依然覺得這是個性能瓶頸。。。又搜到了國外某人發的一個類
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace MrXNAHelper
{
    public class ImageToTexture
    {
        byte[] bmpBytes;
        Texture2D background;

        int width, height;
        Game game;
        public ImageToTexture(Game game, int width, int height)
        {
            this.width = width;
            this.height = height;
            this.game = game;

            GenerateBitmap(game, width, height);
        }

        public ImageToTexture(Game game)
        {
            this.game = game;
        }

        private void GenerateBitmap(Game game, int width, int height)
        {
            background = new Texture2D(game.GraphicsDevice, width, height);
        }

        public Texture2D ConvertBitmapToTexture(Bitmap b)
        {
                game.GraphicsDevice.Textures[0] = null;
                if (background == null ||
                    b.Width != background.Width ||
                    b.Height != background.Height)
                {
                    width = b.Width;
                    height = b.Height;
                    GenerateBitmap(game, width, height);
                }
                
                BitmapData bData = b.LockBits(new System.Drawing.Rectangle(new System.Drawing.Point(), b.Size),
                    ImageLockMode.ReadOnly,
                    PixelFormat.Format32bppRgb);

                // number of bytes in the bitmap
                int byteCount = bData.Stride * b.Height;
                if (bmpBytes == null ||
                    bmpBytes.Length != byteCount)
                    bmpBytes = new byte[byteCount];

                // Copy the locked bytes from memory
                Marshal.Copy(bData.Scan0, bmpBytes, 0, byteCount);

                // don't forget to unlock the bitmap!!
                b.UnlockBits(bData);

                background.SetData(bmpBytes);

            return background;
        }
    }
}
我終於會插代碼了,,,,囧

現在知道降低XNA幀率或者自己寫個定時器,總之不要使用60Hz的話,好像幀率也會有很大的提高。
byte[] bgrData = nextFrame.Bytes;
                    for (int i = 0; i < colorData.Length; i++)
                        colorData[i] = new Color(bgrData[3 * i + 2], bgrData[3 * i + 1], bgrData[3 * i]);
驚人也沒有用到什麼內存指針之類的,但是就做到了。使用2張貼圖交錯的加載方法。膜拜老外啊。


發佈了60 篇原創文章 · 獲贊 11 · 訪問量 49萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章