C++/CLR中Opencv的Mat与C#中的Bitmap互转

一、Bimtap转Mat

cv::Mat BitmapToCvMat(System::Drawing::Bitmap^ image)
{
    cv::Mat dst;

    if (image == nullptr)
    {
        return dst;
    }

    int imgH = image->Height;
    int imgW = image->Width;

    int channel = 3;
    int imgtype = 0;

    if (image->PixelFormat == System::Drawing::Imaging::PixelFormat::Format8bppIndexed)
    {
        channel = 1;
        imgtype = CV_8UC1;
    }
    else if (image->PixelFormat == System::Drawing::Imaging::PixelFormat::Format24bppRgb)
    {
        channel = 3;
        imgtype = CV_8UC3;
    }
    else if (image->PixelFormat == System::Drawing::Imaging::PixelFormat::Format32bppArgb)
    {
        channel = 4;
        imgtype = CV_8UC4;
    }
    else
    {
        return dst;
    }

    System::Drawing::Imaging::BitmapData^ bitmapData = image->LockBits(System::Drawing::Rectangle(0, 0, imgW, imgH), System::Drawing::Imaging::ImageLockMode::ReadWrite, image->PixelFormat);
    int actualwidth = imgW*channel;
    int offset = bitmapData->Stride - actualwidth;

    int posScan = 0, posReal = 0;

    if (0 != offset)
    {
        int step = ((imgW * channel * 8 + 31) / 32) * 4;
        dst = cv::Mat(imgH, imgW, imgtype, (void*)(bitmapData->Scan0), step);
    }
    else
    {
        dst = cv::Mat(imgH, imgW, imgtype, (void*)(bitmapData->Scan0));
    }

    image->UnlockBits(bitmapData);

    return dst;
}

二、Mat转Bitmap

System::Drawing::Bitmap^ CvMatToBitmap(cv::Mat cvimg)
{
    if (cvimg.empty()) return nullptr;

    if (cvimg.depth() != CV_8U) return nullptr;

    int imgW = cvimg.cols;
    int imgH = cvimg.rows;
    int step = cvimg.step;
    int channel = cvimg.channels();
    System::Drawing::Imaging::PixelFormat pixelFormat;

    if (channel == 1)
    {
        pixelFormat = System::Drawing::Imaging::PixelFormat::Format8bppIndexed;
    }
    else if (channel == 3)
    {
        pixelFormat = System::Drawing::Imaging::PixelFormat::Format24bppRgb;
    }
    else if (channel == 4)
    {
        pixelFormat = System::Drawing::Imaging::PixelFormat::Format32bppArgb;
    }
    else
    {
        return nullptr;
    }

    System::Drawing::Bitmap^ resultimage = nullptr;
    resultimage = gcnew System::Drawing::Bitmap(imgW, imgH, pixelFormat);
    System::Drawing::Imaging::BitmapData^ resultimageData = resultimage->LockBits(System::Drawing::Rectangle(0, 0, imgW, imgH), System::Drawing::Imaging::ImageLockMode::ReadWrite, resultimage->PixelFormat);

    int actualWidth = imgW*channel;
    int offset = resultimageData->Stride - actualWidth;
    uchar* outputData_b = (uchar*)(void*)resultimageData->Scan0;
    uchar* img = cvimg.data;

    int posreal = 0, posscan = 0;
    for (int r = 0; r < imgH; r++)
    {
       for (int c = 0; c < actualWidth; c++)
       {
           /**outputData_b = *img;

          utputData_b++;
          img++;*/
          outputData_b[posscan++] = img[posreal++];
       }

       //outputData_b += offset;
      posscan += offset;
    }

    resultimage->UnlockBits(resultimageData);

    return resultimage;
}

以上是通过深拷贝方式实现,实际上,当图片宽为4的倍数时,有更简单的方式:

if (imgW % 4 == 0)
    {
        if (cvimg.isContinuous())
        {
            resultimage = gcnew System::Drawing::Bitmap(imgW, imgH, step, pixelFormat, System::IntPtr(cvimg.data));
        }
        else
        {
            cv::Mat cvtemp = cvimg.clone();
            resultimage = gcnew System::Drawing::Bitmap(imgW, imgH, step, pixelFormat, System::IntPtr(cvtemp.data));
        }return resultimage;
    }

但是传到C#中时,如果后续使用可能就会因被自动释放掉而报错。目前没有什么好的解决办法,我只能一律使用深拷贝方式,速度上肯定比这个慢,若是有好的主意,可以留言评论。

Original: https://www.cnblogs.com/Clark-Zhang/p/14442522.html
Author: 朔月の流光
Title: C++/CLR中Opencv的Mat与C#中的Bitmap互转

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/712707/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球