質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.12%

Bitmap、Mat間の変換

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,621

hsgru3

score 22

前提・実現したいこと

C++/CLIのWindowsFormsアプリケーションで画像処理のプログラムを作成しています。
ファイル選択ダイアログで選択した画像を表示させ、その隣にOpenCVで画像処理したものを表示させようとしていますがファイル選択ダイアログで選択したビットマップファイルをMatへ変換及び、Matからビットマップファイルへの変換方法がわからず困っています。
Bitmap→Mat、Mat→Bitmapの変換について教えていただきたいです。

該当のソースコード

下記のコードはボタンをクリックするとファイル選択ダイアログが開かれ選択した画像をpicturebox1に表示し、画像処理したものをpicturebox2に表示させようとしています。

    private: System::Void button_Click(System::Object^  sender, System::EventArgs^  e) {
        //ファイルを開くダイアログの作成 
        OpenFileDialog^ dlg = gcnew OpenFileDialog;
        //ファイルフィルタ 
        dlg->Filter = "画像ファイル(*.bmp,*.jpg,*.png,*.tif,*.ico)|*.bmp;*.jpg;*.png;*.tif;*.ico";
        //ダイアログの表示 (Cancelボタンがクリックされた場合は何もしない)
        if (dlg->ShowDialog() == System::Windows::Forms::DialogResult::Cancel) return;
        //ビットマップファイルから、元画像Bitmapを作成 
        Bitmap^ bmp1 = gcnew Bitmap(dlg->FileName);
        //picturebox1に表示 
        pictureBox1->Image = bmp1;
        //ビットマップファイルから、処理用Bitmapを作成
        Bitmap^ bmp2 = gcnew Bitmap(dlg->FileName);
--------------------------------
ファイル選択ダイアログで選択したbmp2をMatに変換
            ↓
      OpenCVを用いて画像処理
            ↓
画像処理済みのMatをビットマップファイル(bmp3とか)に変換
--------------------------------
                //picturebox2に画像処理したものを表示
         pictureBox2->Image = bmp3;
        }

補足情報(FW/ツールのバージョンなど)

Visual studio community 2015
OpenCV 3.4.0

追記

下記のコードはBitmapをMatに変換するのではなくファイル選択で選んだパス(dlg->FileName)をSystem::String ^型からstd::stringに変換してimreadで読み込ませています。そのあとimreadで読み込んだ画像を画像処理してからpicureBox2に表示させようとしています。
ここで問題なのですがimshowで表示させた時点で上下左右反転しdrawImage関数でpictureBox2に表示させると画像が崩れてしまいます。
申し訳ございませんがヒントや参考になりそうなサイト等でも教えていただけると幸いです。

    private: System::Void button_Click(System::Object^  sender, System::EventArgs^  e) {
        //ファイルを開くダイアログの作成 
        OpenFileDialog^ dlg = gcnew OpenFileDialog;
        //ファイルフィルタ 
        dlg->Filter = "画像ファイル(*.bmp,*.jpg,*.png,*.tif,*.ico)|*.bmp;*.jpg;*.png;*.tif;*.ico";
        //ダイアログの表示 (Cancelボタンがクリックされた場合は何もしない)
        if (dlg->ShowDialog() == System::Windows::Forms::DialogResult::Cancel) return;
        //ビットマップファイルから、元画像Bitmapを作成 
        Bitmap^ bmp1 = gcnew Bitmap(dlg->FileName);
        //picturebox1に表示 
        pictureBox1->Image = bmp1;

      //ファイル選択ダイアログで選択したファイルのパス(dlg->FileName(System::String ^型))をstd::stringに変換
        string imgfl = msclr::interop::marshal_as<std::string>(dlg->FileName);
        //imreadでよみこむ
     Mat img = imread(imgfl);
     --------------------------
      OpenCVを用いて画像処理
         --------------------------
        //picturebox2に画像処理したものを表示
        drawImage(pictureBox2, img);
        }
                   //描画
    private: System::Void drawImage(PictureBox^ pic, Mat mat) {

        if ((pic->Image == nullptr) || (pic->Width != mat.cols)
            || (pic->Height != mat.rows)) {
            pic->Width = mat.cols;
            pic->Height = mat.rows;
            Bitmap^ bmpPicBox = gcnew Bitmap(pic->Width, pic->Height);
            pic->Image = bmpPicBox;
        }
        Graphics^g = Graphics::FromImage(pic->Image);
        Bitmap^ bmp = gcnew Bitmap(mat.cols, mat.rows, mat.step,
            System::Drawing::Imaging::PixelFormat::Format32bppRgb, IntPtr(mat.data));
        g->DrawImage(bmp, 0, 0, mat.cols, mat.rows);
        pic->Refresh();
        delete g;
    }


左からBitmapで読み込んでpictureBox1に出力したもの、Matで読み込んでpictureBox2に表示させたもの、Matで読み込んでimshowで表示させたものです。
まずimreadで読み込まれた際になぜか上下左右が反転してしまい、pictureBox2に出力しようとすると画像が崩れてしまいます。
![イメージ説明](f71d220f54b286edb664607c017fb12a.png)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

以下と同じですかね?


C++/CLIです。
BitmapをOpenCVのMatに変換するにはどのようにしたらよいのでしょうか。 
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12161297752


追記:

手元のVS2015でNuGetからC++/CLIのテンプレで作ったプロジェクトにOpenCvSharpを入れてみましたが、
何故か参照に追加されなかったので手動で
(プロジェクトフォルダ)\packages\OpenCvSharp-AnyCPU.2.4.10.20170306\lib\net45\*.dll
を追加しました。

あとは普通にコンパイルは通りました。
イメージ説明

OpenCVには詳しくないので適当な事を言いますが、
Bitmap型も各ピクセルにポインタ経由でアクセス出来ますので、
自分でコンバートすることもできそうかなと思いました。
フォーマットが違うとちょっと面倒くさいですが・・・。
(BitmapはGIFとか読み込むとRGBAにならなかったような気がしたので)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/11/27 15:58

    返信ありがとうございます。
    エラーに関してはOpenCV3.4.0がらみのものでした。教えていただきありがとうございます。
    おっしゃっていただいた通りOpenCvSharp::CPlusPlus::Mat^型の扱いが難しそうなので追記のようにやり方を変えてみました。
    発生した問題としてはMat型のものをBitmapに置き換えてpictureBoxに表示させるところで画像が崩れるところです。
    何かヒント等ございましたら教えていただきたいです。

    キャンセル

  • 2019/11/27 17:13

    OpenCV知らないのでなかなかドンピシャな回答だせなくてすみません。

    pepperleafさんの回答の「入出力とGUI」をみた感じでは、
    OpenCVで画像処理をしたあとに、そのままファイル出力もできるようなので、一旦PNGで書き出したあとに、Bitmapで読んだらどうでしょうか?

    これが一番ラクな気がします。

    キャンセル

  • 2019/11/27 17:52

    返信ありがとうございます。
    いろいろ試してみた結果、pictureBoxに表示するBitmap作成の時の引数を調整するとうまくいきました。
    何度も対応していただきありがとうございました。

    キャンセル

+1

OpenCVで直接、Bitmapファイルを読み込めますが、それは使えませんか?
入出力とGUI

.NETで読み込んだBitmap形式を OpenCVのMAT形式に変換するのは、ちょっと面倒でした。ただ、同様の質問もあり、Bitmapを変換する方法 は参考になるでしょうか?

読み込んだBitmap形式をMAT形式に変換した事もありますが、ちょっと面倒。
Bitmapデータのメモリ内のデータを直接、MAT形式にするのですが、.NETなので、内部データアクセスのため、メモリの直接、参照が必要。で、その後、配列データとして、MAT配列にコピー。即答できるほど中身を覚えてません。
調べるのは可能ですが、すぐに分かる人いないかな、、と。
なお、Bitmapのピクセル読み出しは、一桁以上遅くなります。ご注意を。

あと、タグに OpenCV も入れた方が回答付かないでしょうか?


既に解決済みとなっていますが、手元で、Bitmap(Format: Format24bppRgb)から、Matイメージに変換したコードです。

// Format24bppRgb イメージから、Matデータを作成
void Bmp24ToMat(Bitmap ^img, cv::Mat *matImg)
{
    Imaging::BitmapData ^bmpData = img->LockBits(
        Rectangle(0, 0, img->Width, img->Height),
        Imaging::ImageLockMode::ReadOnly, Imaging::PixelFormat::Format24bppRgb);
    try {
        *matImg = cv::Mat(img->Height, img->Width, CV_8UC3);
        uchar *bmpSrc = (uchar *)bmpData->Scan0.ToPointer();    // Bitmapデータのポインタ
        int srcLineSize = bmpData->Stride;                        // 1行あたりの byteサイズ
        int imgHeight = img->Height;
        int imgWidth = img->Width;
        for (int line = 0; line < imgHeight; line++) {
            uchar *src = (uchar *)&bmpSrc[line * srcLineSize];
            uchar *dst = matImg->ptr(line);
            for (int cols = 0; cols < imgWidth; cols++) {
                dst[0] = src[2];            // B
                dst[1] = src[1];            // G
                dst[2] = src[0];            // R
                src += 3;
                dst += 3;
            }
        }
    } finally {
        img->UnlockBits(bmpData);        // ロックの解除
    }
}


24bitフォーマット限定なのは、手元のデータがこれで十分だったためと、他の形式を調べるのが面倒だったためです。
Bitmap と、MAT形式で、RGB(Bitmap)と、BGR(MAT)で順序が違うのに注意。

参考情報として置いておきます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/11/27 15:51

    回答ありがとうございます。
    教えていただいた通りBitmapのままimreadで読み込ませるやり方でしてみました。
    BitmapのままOpenCVで読み込み画像処理後pictureBoxへの表示を試みました。
    なんとかコンパイルを通るものはできましたが画像が崩れてしまいます。
    何かヒント等ございましたら教えていただきたいです。

    キャンセル

  • 2019/11/27 17:53

    返信ありがとうございます。
    いろいろ試してみた結果、pictureBoxに表示するBitmap作成の時の引数を調整するとうまくいきました。
    何度も対応していただきありがとうございました。

    キャンセル

  • 2019/11/28 13:10

    追記ありがとうございます。
    ヒントだけでなく関数まで教えていただき助かりました。
    今後また質問させていただくと思いますで、その時はよろしくお願いいたします。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる