在图片控件中显示传输的HBITMAP



我有一台相机,它有一个用C#开发的库和一个用C++6编写的客户端应用程序。我已经创建了一个C#COM包装器来将两个系统连接在一起,它运行得很好。

在C#COM包装器中,我有一个System.Drawing.Bitmap对象,它包含相机的当前帧。

在C#COM包装器中,我有一个函数public void GetFrameHandle(ref IntPtr hBitmap, [MarshalAs(UnmanagedType.SysInt)] ref int width, [MarshalAs(UnmanagedType.SysInt)] ref int height),它基本上将帧位图中的HBITMAP转换为C++

这似乎起到了一定的作用,我可以在C++中看到图像,但由于像素格式不正确,图像都被打乱了。

如何在C++中从HBITMAP确定像素格式,然后在图片控件中显示正确的图像?

我已经进行了大量的调查,似乎我需要从传输的HBITMAP中创建一个新的BITMAP,然后从正确的像素格式中创建新的HBITMAP,然后使用它来填充图片控件。

我不太确定如何开始这个过程

C#COM服务器:

/// <summary>
/// Called when an image has been grabbed and is ready to process
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void StreamGrabber_ImageGrabbed(object sender, ImageGrabbedEventArgs e)
{
// process the image
try
{
// Acquire the image from the camera. Only show the latest image. The camera may acquire images faster than the images can be displayed.
// Get the grab result.
IGrabResult grabResult = e.GrabResult;
// Check if the image can be displayed.
if (grabResult.GrabSucceeded)
{
if (grabResult.IsValid)
{
// create a new bitmap object for holding the image data from the camera
// the bits and things need to be able to be set according to the c++ program's requirements.
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(grabResult.Width, grabResult.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
// Lock the bits of the bitmap.
System.Drawing.Imaging.BitmapData bmpData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap.PixelFormat);
// Place the pointer to the buffer of the bitmap.
converter.OutputPixelFormat = PixelType.BGR8packed;
IntPtr ptrBmp = bmpData.Scan0;
converter.Convert(ptrBmp, bmpData.Stride * bitmap.Height, grabResult); //Exception handling TODO
bitmap.UnlockBits(bmpData);
// Assign a temporary variable to dispose the bitmap after assigning the new bitmap to the display control.
System.Drawing.Bitmap bitmapOld = this.currentFrame;
// Provide the display control with the new bitmap. This action automatically updates the display.
// this may require some mutex to ensure that only entire frames are retrieved
this.currentFrame = bitmap;
// if the client window is set, output bitmap to it.
if (m_clientWindow != null)
m_clientWindow.DrawImage(currentFrame, new System.Drawing.Point(0, 0));

if (bitmapOld != null)
{
// Dispose the bitmap.
bitmapOld.Dispose();
}
// notify that a frame is ready to obtain
BroadcastFrameEvent();
}
}
else
{
BroadcastErrorEvent("StreamGrabber_ImageGrabbed", String.Format("Error: {0} {1}", grabResult.ErrorCode, grabResult.ErrorDescription));
}
}
catch (Exception exception)
{
BroadcastErrorEvent("StreamGrabber_ImageGrabbed", exception.ToString());
}
finally
{
// Dispose the grab result if needed for returning it to the grab loop.
e.DisposeGrabResultIfClone();
}

}

public void GetFrameHandle(ref IntPtr hBitmap, [MarshalAs(UnmanagedType.SysInt)] ref int width, [MarshalAs(UnmanagedType.SysInt)] ref int height)
{
if (this.currentFrame != null)
{
// System.Drawing.Imaging.BitmapData bmpData = null;
try
{
hBitmap = this.currentFrame.GetHbitmap();
width = currentFrame.Width;
height = currentFrame.Height;
}
catch (Exception ex)
{
BroadcastErrorEvent("GetFrame", ex.ToString());
}
}
}

public void SaveFrame(string filename)
{
try
{
if (m_debugMode == 1)
MessageBox.Show("Filename = " + filename, "GigE COM Wrapper Debug");
if (this.currentFrame != null)
this.currentFrame.Save(filename, System.Drawing.Imaging.ImageFormat.Bmp);
}
catch (Exception ex)
{
BroadcastErrorEvent("SaveFrame", ex.ToString());
}
}

C++客户端:

// When a frame is ready to process
HRESULT CameraEventHandler::OnFrameReady()
{
HRESULT hr = S_OK;
//  if (m_debug == 1)
//      MessageBox(NULL, "Frame is ready", "COM event received", MB_OK);
// grab the frame from the COM wrapper and display it

long pOutHb;
if (pCamera != NULL)
{
BSTR bsFilename = SysAllocString(L"frame.bmp");
hr = pCamera->SaveFrame(bsFilename);
if (!SUCCEEDED(hr))
{
MessageBox(NULL, "COM Error", "Fail", MB_OK);
return hr;
}
hr = pCamera->GetFrameHandle(&pOutHb, &width, &height);
if (SUCCEEDED(hr))
{
BITMAP bm;
HBITMAP hbFrameFromCOM;
hbFrameFromCOM = (HBITMAP)pOutHb;
// get the bitmap from the HBITMAP
GetObject(hbFrameFromCOM, sizeof(BITMAP), &bm);
LONG size = bm.bmWidthBytes * bm.bmHeight;
//create the bitmap?
// copy data across?
// create a new HBITMAP (hb)
if (pDialog != NULL)
{
// post the message
// this signals the dialog to update the picture control with the HBITMAP
pDialog->SendMessage(WM_REFRESH_BITMAP);
}
}
else
if (m_debug == 1)
MessageBox(NULL, "Get bitmap handle failed", "Fail", MB_OK);
}
return hr;
}

不确定如何进行此操作。

有趣的是,我从C#代码中保存的frame.bmp也是乱码。我认为这两个问题是有关联的,但我不能把这两个点连在一起。

谢谢你的帮助。

感谢您的帮助,使它能够正常工作。

上面的代码基本上是正确的,除了相机和用作内部帧缓冲区的位图之间的C#包装中需要匹配的pixelFormats。

帧稳定后的灰度图像输出是因为我在c++客户端中将相机模式设置为灰度。我把它换成了YUV,一切都很好。

有很多地方可以设置模式!

我不需要担心更改C++客户端中的任何内容。所需要的只是将COM包装器发送的HBITMAP扔到对话框的图片控件上以显示它

干杯。

最新更新