Отображение переданного HBITMAP в элементе управления изображением - PullRequest
0 голосов
/ 08 января 2019

У меня есть камера с библиотекой, разработанной на 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 ++, но оно искажено из-за неправильного формата пикселя.

Как определить формат пикселя из HBITMAP в C ++, а затем отобразить правильное изображение в элементе управления изображением?

Я провел много исследований, и мне кажется, что мне нужно создать новый BITMAP из переданного HBITMAP, а затем создать новый 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;
    }

Не знаете, как поступить с этим.

Интересно, что frame.bmp, который я сохраняю из кода C #, также искажен. Я думаю, что эти две проблемы связаны, но я не могу объединить точки здесь.

Спасибо за любую помощь с этим.

1 Ответ

0 голосов
/ 09 января 2019

Спасибо за помощь, я смог заставить его работать.

Приведенный выше код был в значительной степени корректным, за исключением пиксельных форматов, необходимых для соответствия в C # COM-оболочке между камерой и растровым изображением, используемым в качестве внутреннего буфера кадров.

Вывод изображения в градациях серого после стабилизации кадра был вызван тем, что я настраивал режим камеры в градациях серого в клиенте c ++. Я изменил его на YUV, и все было хорошо.

Есть много мест, где можно установить режимы!

Мне не нужно было беспокоиться об изменении чего-либо в клиенте C ++. Все, что требуется, это выбросить HBITMAP, отправленный оболочкой COM, в элемент управления изображением диалогового окна, чтобы отобразить его.

Приветствие.

...