ExcelからOpenCVで画像を開く
はじめに
Excelにはプログラミングのできる環境としてVBAが用意されています。ただあまり使いやすいとはいえないので、別の方法があるか調べてみました。
COMというインターフェースを使うとVisual Studioで作成したDLLを呼べるみたいなので試してみます。
実装
ここではC++/CLIのOpenCVで取得したカメラ画像をExcelで表示するプログラムを作ってみます。VBAから見えてほしいインターフェースは、画像の座標を入れるとRGBの値が返ってくるものです。これを実装すると以下のようになります。
参考
Extend your VBA code with C#, VB.Net or C++/CLI | Pragmateek
#pragma once using namespace System::Runtime::InteropServices; #include <opencv2/highgui/highgui.hpp> [Guid("FCB93926-3C39-447E-81D5-A1FB109A6EF3")] public interface class ICamera { array<int>^ GetPixelColor(int r, int c); }; [Guid("A1AFD711-99A3-42C2-B6CD-1A2B2B1B3CB8")] [ClassInterface(ClassInterfaceType::None)] public ref class Camera : ICamera { public: Camera(); ~Camera(); virtual array<int>^ GetPixelColor(int r, int c); private: cv::VideoCapture *capture_; cv::Mat_<cv::Vec3b> *image_; };
VBAから呼びたい関数はインターフェースクラスで宣言します。ここだと座標rとcを入れると輝度値の配列が返ってきます。
GUIDは他とかぶらない値でVisual Studioの ツール->GUIDの作成 からコピペできます。cv::VideoCaptureとcv::Matをポインタにしているのは、C++/CLIがアンマネージドはポインタじゃないと動かないからです。これ結構つらい制約なんですよね。
#include "Camera.h" #include <iostream> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> Camera::Camera() { capture_ = new cv::VideoCapture(CV_CAP_DSHOW); image_ = new cv::Mat_<cv::Vec3b>(); *capture_ >> *image_; // 小さめにしてドット絵ぽく cv::resize(*image_, *image_, cv::Size(640 / 10, 480 / 10), 0, 0, cv::INTER_NEAREST); } Camera::~Camera() { delete capture_; delete image_; } array<int>^ Camera::GetPixelColor(int r, int c) { array<int>^ pixel = gcnew array<int>(3); pixel[0] = (*image_)(r, c)[0]; pixel[1] = (*image_)(r, c)[1]; pixel[2] = (*image_)(r, c)[2]; return pixel; }
作ったDLLはregasm.exeで登録してVBAから見えるようにします。Visual StudioのTool Commandから管理者権限で
RegAsm /codebase /tlb path-to-dll
を実行します。そうするとVBAのツール->参照設定から登録したDLLが見えます。
Option Explicit Sub Display() Dim camera As ExcelCamera2.camera Set camera = New ExcelCamera2.camera Dim dataSheet As Worksheet Set dataSheet = Sheets("Sheet1") Dim r As Long Dim c As Long For r = 1 To 480 / 10 For c = 1 To 640 / 10 Dim pixel As Variant pixel = camera.GetPixelColor(r - 1, c - 1) dataSheet.Cells(r, c).Interior.Color = RGB(pixel(2), pixel(1), pixel(0)) Next Next End Sub
F5キー押して実行するとこんな感じになります。めでたし。
(続き書きました:パワポのスライド上でプログラムを動かす - wildpieの日記)