読者です 読者をやめる 読者になる 読者になる

C#でOpenCVの画像を表示させたくて苦労する2

ゴールデンウィークC#の文法の勉強してました。何となくわかってきましたが、.netの方が大きすぎてどこから手をつければいいのか戸惑ってます。イベントループとか.netの設計の思想とかまとめた資料はあるのかな。

前の日記でOpenCVの画像を表示させようとしましたが、謎の変換をしていて非常に気持ち悪いので、wpfは止めてフォームにしました。どうもcv::MatのアライメントがC#とは違うみたいで、p_mat_というポインタを作って何とかしています。OpenCVC#向けライブラリを使うと簡単に変換できそうな気がするので(未確認ですが)、そちらを使った方がいいと思います。

見た目はこんな感じです。ボタンを押すとファイル選択ダイアログが表示されて、選択した画像がpicutureBoxに表示されます。

using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using Wrapper;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private readonly ImageProcess _imageprocess = new ImageProcess();

        public Form1()
        {
            InitializeComponent();
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            var fd = new OpenFileDialog
            {
                Filter = @"Image Files(*.jpg)|*.jpg"
            };

            if (fd.ShowDialog() == DialogResult.OK)
            {
                this.toolStripStatusLabel1.Text = fd.FileName;

                var bitmap = await Task.Run(() => _imageprocess.Process(fd.FileName));

                this.pictureBox1.Image = bitmap;
            }
            else
            {
                this.toolStripStatusLabel1.Text = @"画像がないよ";
            }
        }

        private Task<System.Drawing.Bitmap> ProcessInNativeTaskAsync(string filename)
        {
            return Task.Run(() => _imageprocess.Process(filename));
        }
    }
}
#pragma once

#using <System.Drawing.dll>

#include <opencv2/core/core.hpp>

namespace Wrapper
{
	public ref class ImageProcess
	{
	public:
		ImageProcess();
		~ImageProcess();
		!ImageProcess();

		System::Drawing::Bitmap^ Process(System::String^ filename);
	private:
		System::Drawing::Bitmap^ GetBitmap(cv::Mat_<cv::Vec3b>& image);

		cv::Mat_<cv::Vec3b> *p_mat_;
	};
}
#include "ImageProcess.h"

#using <System.Windows.Forms.dll>

#include <msclr/marshal_cppstd.h>

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

namespace Wrapper
{
	ImageProcess::ImageProcess()
		: p_mat_(nullptr)
	{
	}

	ImageProcess::~ImageProcess()
	{
		this->!ImageProcess();
	}

	ImageProcess::!ImageProcess()
	{
		if (p_mat_ != nullptr)
			delete p_mat_;
	}

	System::Drawing::Bitmap^ ImageProcess::Process(System::String^ filename)
	{
		using namespace msclr::interop;
		cv::Mat_<cv::Vec3b> image = cv::imread(marshal_as<std::string>(filename));
		if (image.empty())
		{
			System::Windows::Forms::MessageBox::Show(filename + "はないよ");
		}

		return GetBitmap(image);
	}

	System::Drawing::Bitmap^ ImageProcess::GetBitmap(cv::Mat_<cv::Vec3b>& image)
	{
		const int alignment = 4;
		const int new_cols = cv::alignSize(image.cols, alignment);

		if (p_mat_ == nullptr)
		{
			p_mat_ = new cv::Mat_<cv::Vec3b>(image.rows, new_cols);
		}
		else if (p_mat_->cols != new_cols || p_mat_->rows != image.rows)
		{
			delete p_mat_;
			p_mat_ = new cv::Mat_<cv::Vec3b>(image.rows, new_cols);
		}
		cv::Mat_<cv::Vec3b> roi_mat(*p_mat_, cv::Rect(0, 0, image.cols, image.rows));
		image.copyTo(roi_mat);

		System::Drawing::Bitmap^ dst = gcnew System::Drawing::Bitmap(roi_mat.cols, 
			roi_mat.rows, 
			roi_mat.step, 
			System::Drawing::Imaging::PixelFormat::Format24bppRgb, 
			System::IntPtr(roi_mat.data));

		return dst;  
	}
}