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.cpp
と EmployeeID.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::CharArray
と matlab::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 関数をビルドして実行します。