Main Content

MEX 関数の MATLAB オブジェクト

MEX 関数は、メンバー関数setPropertyおよびgetPropertyを使用して、MATLAB® オブジェクトのプロパティにアクセスできます。MEX 関数に渡されるオブジェクトは、任意の MATLAB 関数に渡されるオブジェクトと同様に動作します。

  • ハンドル オブジェクト - MEX 関数のハンドル オブジェクトに加えられた変更は、呼び出し元ワークスペースのオブジェクトに影響を与えます。

  • 値オブジェクト - MEX 関数の値オブジェクトに加えられた変更は、その MEX 関数のワークスペース内にある、オブジェクトの独立したコピーにのみ影響を与えます。

したがって、MEX 関数によって変更された値は呼び出し元に返さなければなりませんが、ハンドル オブジェクトは返す必要がありません。オブジェクトの動作の詳細については、オブジェクトの変更を参照してください。

プロパティ値の取得

プロパティ値を取得するには、オブジェクトの共有コピーを matlab::data::Array として作成します。たとえば、オブジェクトが 1 番目の入力引数だとすると、変数に次のように代入します。

matlab::data::Array object(inputs[0]);

MATLAB データ配列を、プロパティ値の正しい型で作成します。たとえば、Name というプロパティに MATLAB 文字ベクトルが格納されているとすると、新しい値は matlab::data::CharArray として定義します。matlab::data::ArrayFactory を使用して配列を作成します。

matlab::data::CharArray propName = matlabPtr->getProperty(object, u"Name");

オブジェクト配列からのプロパティ値の取得

MEX 関数への入力がオブジェクト配列の場合、プロパティ値を取得する配列のオブジェクトのインデックスを指定して getProperty を呼び出します。たとえば、次のコード スニペットは、オブジェクト配列 objectArray の 4 番目の要素に対する Name プロパティの値を返します。

matlab::data::Array objectArray(inputs[0]);
matlab::data::CharArray propName = matlabPtr->getProperty(objectArray, 3, u"Name");

プロパティ値の設定

プロパティ値を設定するには、オブジェクトの共有コピーを matlab::data::Array として作成します。たとえば、オブジェクトが 1 番目の入力引数だとすると、変数に次のように代入します。

matlab::data::Array object(inputs[0]);

MATLAB データ配列を、プロパティ値の正しい型で作成します。たとえば、Name というプロパティに MATLAB 文字ベクトルが格納されているとすると、新しい値は matlab::data::CharArray として定義します。matlab::data::ArrayFactory を使用して配列を作成します。

共有ポインター matlabPtr を指定して MATLAB エンジンの関数 setProperty を呼び出します。

matlabPtr->setProperty(object, u"Name",
    factory.createCharArray("New value for Name"));

オブジェクト配列におけるプロパティ値の設定

MEX 関数への入力がオブジェクト配列の場合、プロパティ値を設定する配列のオブジェクトのインデックスを指定して setProperty を呼び出します。たとえば、次のコード スニペットは、オブジェクト配列 objectArray の 4 番目の要素に対して Name プロパティの値を設定します。

matlab::data::Array objectArray(inputs[0]);
matlabPtr->setProperty(objectArray, 3, u"Name",   
    factory.createCharArray("New value for Name"));

オブジェクト プロパティのコピーオンライト動作

MEX 関数がオブジェクト プロパティに値を代入して変更すると、プロパティ値は呼び出し元ワークスペースのオブジェクトと共有されなくなります。プロパティのデータのうち変更されていないものは共有されたままです。つまり、コピーオンライト動作は変更されたプロパティに影響し、オブジェクト全体には影響しません。

プロパティを変更してオブジェクトを返す

この例では EmployeeID クラスを使用してオブジェクトを作成します。このクラスは、2 つのプロパティを定義します。Name プロパティは、1 行で任意の列の要素をもつ char 型配列として定義します。Picture プロパティは、1000 行 800 列の要素をもつ uint8 型の配列として定義し、従業員の写真に使用します。

classdef EmployeeID
   properties
      Name (1,:) char
      Picture (1000,800) uint8
   end
   methods
      function obj = EmployeeID(n,p)
         if nargin > 0
            obj.Name = n;
            obj.Picture = p;
         end
      end
   end
end

次の MEX 関数は、EmployeeID クラスに格納された 1 つのオブジェクトを変更し、イメージ内で最も明るい値の強度を下げます。この MEX 関数は、次の手順を実行します。

  • std::move を使用して、入力引数を matlab::data::Array に移動します。

  • getPropertyを使用して、変更するプロパティの値を取得します。

  • 変数を、プロパティ値として適切な型で定義します。MATLAB の型が uint8 なので、matlab::data::TypedArray<uint8_t> を使用します。

  • setPropertyを使用して、変更した配列をオブジェクト プロパティに再代入します。

  • 変更したオブジェクトを MEX 関数出力として返します。

#include "mex.hpp"
#include "mexAdapter.hpp"

using matlab::mex::ArgumentList;
using namespace matlab::data;

class MexFunction : public matlab::mex::Function {
    std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
public:
    void operator()(ArgumentList outputs, ArgumentList inputs) {

        // Move object to variable
        Array obj = std::move(inputs[0]);

        // Get property value and modify
        TypedArray<uint8_t> imageData = matlabPtr->getProperty(obj, u"Picture");
        for (auto& elem : imageData) {
            if (elem > 240) {
                elem = elem - elem/100;
            }
        }

        // Set property value and assign to output
        matlabPtr->setProperty(obj, u"Picture", imageData);
        outputs[0] = obj;
    }
};

このコードをファイル (この例では reduceGlare.cpp という名前) に保存したら、関数 mex を使用してコンパイルします。EmployeeID オブジェクトを入力に使用して、この MEX 関数を MATLAB から呼び出します。

EmployeeObject = EmployeeID('My Name',randi([1 255],1000,800,'uint8'));
EmployeeObject = reduceGlare(EmployeeObject);

コピーが発生するのは変更されたプロパティのみ

この例では、EmployeeID オブジェクトと、その Name プロパティの新しい値を入力として受け入れる MEX 関数を作成します。プロパティを新しい値に設定したら、関数は変更済みオブジェクトを返します。この MEX 関数は、プログラムで便利に使えるいくつかのステップを追加で実行します。

  • 引数チェックは、入力の数が正しいことを確認し、MATLAB isa を呼び出して入力オブジェクトのクラスを判定します。

  • Name プロパティを設定する値に対して char または string 入力をサポートします。

  • 現在のプロパティ値を比較し、更新が必要かどうかを判定します。

ソース コードを表示するには、modifyObjectProperty.cppEmployeeID.m をクリックして、これらのファイルを MATLAB エディターで開きます。mex コマンドを使用して MEX 関数をビルドします。

この例を実行するには、modifyObjectProperty.cpp ファイルと EmployeeID.m クラスを、MATLAB パス上のフォルダーに追加します。mex の設定が完了したら、次のステートメントを実行します。

mex modifyObjectProperty.cpp
EmployeeObject = EmployeeID('My Name',randi([1 255],1000,800,'uint8'));
EmployeeObject = modifyObjectProperty(EmployeeObject,'New Name');

以下に、MexFunction::operator() の実装を示します。

include "mex.hpp"
#include "mexAdapter.hpp"

using matlab::mex::ArgumentList;
using namespace matlab::data;

class MexFunction : public matlab::mex::Function {
public:
    void operator()(ArgumentList outputs, ArgumentList inputs) {
        // Check for correct inputs
        checkArguments(outputs, inputs);

        // Assign the input object to a matlab::data::Array
        Array object(inputs[0]);

        // Member function to set properyt value
        assignProperty(object, inputs);

        // Return modified object
        outputs[0] = object;
    }

関数 MexFunction::checkArguments は次のチェックを実行します。

  • MEX 関数は引数を 2 つ指定して呼び出さなければなりません。

  • 最初の引数は EmployeeID クラスのオブジェクトでなければなりません。

    void checkArguments(ArgumentList out, ArgumentList in) {
        std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
        ArrayFactory factory;

        // Check number of inputs
        if (in.size() != 2) {
            matlabPtr->feval(u"error", 0,
                std::vector<Array>({ factory.createScalar("Two inputs required") }));
        }
        // Use isa function to test for correct class
        std::vector<Array> args{ in[0], factory.createCharArray("EmployeeID") };
        TypedArray<bool> result = matlabPtr->feval(u"isa", args);
        if (result[0] != true) {
            matlabPtr->feval(u"error", 0, 
               std::vector<Array>({ factory.createScalar("Input must be EmployeeID object") }));
        }     
    }

関数 MexFunction::assignProperty は、プロパティの新しい値が MATLAB char ベクトルとして渡されるか、string として渡されるかを判定し、入力をそれぞれ matlab::data::CharArraymatlab::data::StringArray として代入します。

新しい値を Name プロパティに代入する前に、この関数は現在値を比較して異なる値かどうかを判定し、異なる値でない場合は代入を避けます。

    void assignProperty(Array& obj, ArgumentList in) {
        std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
        ArrayFactory factory;
        std::string newPropertyValue;

        // Determine if input is MATLAB char or MATLAB string
        if (in[1].getType() == ArrayType::CHAR) {
            CharArray newName(in[1]);
            newPropertyValue = newName.toAscii();
        }
        else if (in[1].getType() == ArrayType::MATLAB_STRING) {
            StringArray newName(in[1]);
            newPropertyValue = (std::string)newName[0];
        }
        else {
            matlabPtr->feval(u"error", 0,
                std::vector<Array>({ factory.createScalar("Name must be char or string") }));
        }

        // If new value is different from new value, set new value
        CharArray currentName = matlabPtr->getProperty(obj, u"Name");
        if (currentName.toAscii() != newPropertyValue) {
            matlabPtr->setProperty(obj, u"Name", factory.createCharArray(newPropertyValue));
        }
    }

ハンドル オブジェクト

ハンドル オブジェクトを使用する例については、次のファイルをダウンロードし、ファイルの説明に従って MEX 関数をビルドして実行します。

mexgetproperty.cpp

参考

|

関連するトピック