2010-05-26 11 views
1

Comment puis-je obtenir un bitmap .NET et une image OpenCV pour pointer vers le même fragment de mémoire? Je sais que je peux copier de l'un à l'autre, mais je préférerais qu'ils pointent simplement vers les mêmes pixels.Comment puis-je obtenir un bitmap .NET et une image OpenCV pour pointer vers le même fragment de mémoire?

Points bonus pour une solution utilisant Emgu.

+0

Par curiosité: dans quel but? – Amy

+0

Il s'agit d'un système hérité qui utilise beaucoup GDI. Je voudrais utiliser OpenCV pour créer une image, et la mélanger avec le reste du système, qui utilise GDI pour le dessin. Pour obtenir l'image dans GDI, j'utilise un bitmap. S'il y a un moyen plus direct de passer d'OpenCV à un objet "Graphics" GDI, cela m'intéresserait aussi. – Sean

Répondre

5

Ce qui suit est juste une théorie et pourrait ne pas fonctionner, je ne suis pas très expérimenté avec OpenCV/emgucv


Les deux System.Drawing.Bitmap et Emgu.CV.Image ont des constructeurs prenant scan0 comme argument. Vous pouvez allouer de la mémoire pour l'image et passer ce pointeur à ces constructeurs. mémoire peut être alloué par var ptr = Marshal.AllocHGlobal(stride*height) (ne pas oublier de libérer) ou en allouant un tableau géré de taille suffisante et en acquérant son adresse. Adresse peut être aquired façon suivante:

var array = new byte[stride*height]; 
var gch = GCHandle.Alloc(array, GCHandleType.Pinned); 
var ptr = gch.AddrOfPinnedObject(); 

Cela a également tableau « pins », il ne peut donc être déplacé par éboueur et l'adresse ne changera pas.

Nous allons utiliser ces constructeurs:

Bitmap(int width, int height, int stride, PixelFormat format, IntPtr scan0); 
Image<Bgr, Byte>(int width, int height, int stride, IntPtr scan0); 

width et height arguments sont explicites. format pour bitmap est PixelFormat.Format24bppRgb. stride est la quantité d'octets pour une seule ligne d'image, il doit également être aligné (être un multiple de 4). Vous pouvez l'obtenir de cette façon:

var stride = (width * 3); 
var align = stride % 4; 
if(align != 0) stride += 4 - align; 

Et scan0 est un pointeur sur notre bloc de mémoire.

Donc, je suggère qu'après avoir créé System.Drawing.Bitmap et Emgu.CV.Image en utilisant ces constructeurs utilisera le même bloc de mémoire. Si ce n'est pas le cas, cela signifie que opencv ou bitmap ou les deux bloc de mémoire fourni de copie et la solution possible (s'il existe) ne vaut certainement pas la peine efforts.

+0

aussi, ne pas oublier 'unsafe' http://msdn.microsoft.com/en-us/library/chfa2zb8(VS.71).aspx – slf

+0

Je n'ai pas encore essayé cela, mais je vais aller de l'avant et accepter cette réponse avant que la prime ne soit épuisée. – Sean

0

Je ne sais pas si cela aide, mais vous pouvez obtenir le pointeur d'une image en utilisant Emgu .Ptr

par exemple IntPtr ip = img1.Ptr;

2

De la source Emgu.CV:

// Summary: 
//  The Get property provide a more efficient way to convert Image<Gray, Byte>, 
//  Image<Bgr, Byte> and Image<Bgra, Byte> into Bitmap such that the image data 
//  is shared with Bitmap. If you change the pixel value on the Bitmap, you change 
//  the pixel values on the Image object as well! For other types of image this 
//  property has the same effect as ToBitmap() Take extra caution not to use 
//  the Bitmap after the Image object is disposed The Set property convert the 
//  bitmap to this Image type. 
public Bitmap Bitmap { get; set; } 

Donc, en gros, pour des types spécifiques de l'image, vous pouvez simplement utiliser la propriété .Bitmap de l'image de CV, qui sera ensuite pointer directement vers les données d'image de CV.

Exemple:

string filename; 
// ... point filename to your file of choice ... 

Image<Bgr, byte> cvImg = new Image<Bgr, byte>(filename); 
Bitmap   netBmp = cvImg.Bitmap;