c# - sistemas - sistema de recomendacion tesis
Pasar bitmap de c#a c++ (4)
Depende del alcance Si puede garantizar que el mapa de bits no se utiliza en ningún otro lugar, puede bloquear el almacenamiento intermedio de imágenes, y luego pasar el puntero al código C ++ y desbloquearlo después.
El comando LockBits devuelve una clase BitmapData que tiene un puntero al buffer de imagen en su propiedad Scan0 :
BitmapData bmpData = bitmapFrame.LockBits(new Rectangle(0, 0, bitmapFrame.Width, bitmapFrame.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
ativeFunctions.FaceTracker(bmpData.Scan0 , bitmapFrame.Width, bitmapFrame.Height);
bitmapFrame.UnlockBits(bmpData); //Remember to unlock!!!
Tengo una función de procesamiento de imágenes escrita en C ++ basada en opencv. En mi aplicación wpf, he utilizado la biblioteca AForge para acceder a una cámara web y actualizarla en la interfaz de usuario. Esta es la función para manejar newframes.
void UI_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
System.Drawing.Bitmap bitmapFrame = (Bitmap)eventArgs.Frame.Clone();
MemoryStream ms = new MemoryStream();
bitmapFrame.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
BitmapImage bitmapImageFrame = new BitmapImage();
bitmapImageFrame.BeginInit();
bitmapImageFrame.StreamSource = ms;
bitmapImageFrame.EndInit();
bitmapImageFrame.Freeze();
CurrentFrame = bitmapImageFrame;
}
catch (Exception ex)
{
Debug.WriteLine("fatal::" + ex.Message);
}
}
Este es mi código c ++:
void FaceTracker(unsigned char* imageBuffer, int width, int height){
Mat frame(Size(width, height), CV_8UC4, imageBuffer, Mat::AUTO_STEP);
Mat gray;
cvtColor(frame, gray, COLOR_BGR2GRAY);
//do more operations
}
Tengo dos opciones. Ya encontré un código para copiar datos de BitmapImage
a un buffer CopyPixels
usando CopyPixels
. Lo probé y funciona bien. Pero también leí que simplemente puedo pasar un control al mapa de bits usando GetHBitmap
. Sin embargo, esto no funciona para mí. Leí esto ¿Cómo puedo pasar un mapa de bits .NET a una DLL nativa? pero no entiendo la parte sobre GetDIBits
. También traté de bloquear píxeles de mapa de bits y pasar así:
bitmapFrame.LockBits(new Rectangle(0, 0, bitmapFrame.Width, bitmapFrame.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
NativeFunctions.FaceTracker(bitmapFrame.GetHbitmap(), bitmapFrame.Width, bitmapFrame.Height);
y simplemente pasando HBitMap, ninguno de los dos funciona. Siempre recibo una excepción que indica violación de acceso a la memoria.
Puedo sugerirle que use EmguCV. Es envoltorio para openCV en C #. No tiene que preocuparse por dll, lib, etc. Puedo ver que desea rastrear una cara desde la cámara web. EmguCV te da la posibilidad de capturar la imagen de la cámara web y luego hacer un seguimiento de la cara de una manera muy fácil: http://www.emgu.com/wiki/index.php/Face_detection Este enlace también te puede ayudar. Disfrutar.
Un HBITMAP
es un identificador opaco de un mapa de bits. No es un buffer de pixel. Entonces sus dos piezas de código no coinciden.
Si pasa un HBITMAP
al código nativo, entonces necesita el código nativo para usar las funciones GDI para obtener el búfer de píxeles y operarlo. Alternativamente, puede obtener un búfer de píxeles en su código administrado y pasarlo al código nativo. Cualquiera que sea el camino que tome, debe hacer coincidir los dos lados de la interoperabilidad.
Puede usar el método Bitmap.Save()
para convertirlo a una secuencia de memoria y luego enviarlo a C++ dll
.
public Image ConvertImage(Image image)
{
MemoryStream convertedImageMemoryStream;
using (MemoryStream sourceImageStream = new MemoryStream())
{
image.Save(sourceImageStream, System.Drawing.Imaging.ImageFormat.Png);
byte[] sourceImageData = sourceImageStream.ToArray();
// Send it to dll and get the IntPtr byte array from dll
byte[] imageData = new byte[imInfo.size];
Marshal.Copy(imInfo.data, imageData, 0, imInfo.size);
if (imInfo.data != IntPtr.Zero)
AlgorithmCpp.ReleaseMemoryFromC(imInfo.data);
convertedImageMemoryStream = new MemoryStream(imageData);
}
Image processed = new Bitmap(convertedImageMemoryStream);
return processed;
}
Luego, en C++ dll
use decodificación como el método cv::imdecode()
para obtener la imagen.
DllExport void convertToGray(unsigned char* data, int dataLen)
{
vector<unsigned char> inputImageBytes(data, data + dataLen);
Mat image = imdecode(inputImageBytes, CV_LOAD_IMAGE_COLOR);
Mat processed;
cvtColor(image, processed, CV_BGR2GRAY);
vector<unsigned char> bytes;
imencode(".png", processed, bytes);
// ....
Hay algunos pros de esta manera, tales como: 1. fewer data to transfer 2. minimum implementation effort from both C# and C++ end. 3. Does not depend on the source image type eg. color or grayscale or any other color palate type. So it''s very safe to use.
1. fewer data to transfer 2. minimum implementation effort from both C# and C++ end. 3. Does not depend on the source image type eg. color or grayscale or any other color palate type. So it''s very safe to use.
El único problema es que es intensivo en la CPU ya que hay una codificación y una decodificación.
Los detalles estan aqui