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#中時,如果后續使用可能就會因被自動釋放掉而報錯。目前沒有什么好的解決辦法,我只能一律使用深拷貝方式,速度上肯定比這個慢,若是有好的主意,可以留言評論。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM