Files
opencv/cxx/mat.cc
2025-03-17 15:55:43 +08:00

490 lines
17 KiB
C++

#include "mat.h"
using namespace Napi;
#define MAT_INSTANCE_METHOD(method) InstanceMethod<&CVMat::method>(#method, static_cast<napi_property_attributes>(napi_writable | napi_configurable))
#define MAT_STATIC_METHOD(method) StaticMethod<&CVMat::method>(#method, static_cast<napi_property_attributes>(napi_writable | napi_configurable))
#define NODE_FUNCTION_IMPL(name) Napi::Value CVMat::name(const Napi::CallbackInfo &info)
FunctionReference *CVMat::constructor = nullptr;
Napi::Object CVMat::Init(Napi::Env env, Napi::Object exports)
{
Function func = DefineClass(env, "Mat", {
MAT_STATIC_METHOD(ImRead),
MAT_STATIC_METHOD(ImDecode),
MAT_STATIC_METHOD(ImWrite),
MAT_STATIC_METHOD(ImEncode),
MAT_STATIC_METHOD(Crop),
MAT_STATIC_METHOD(Resize),
MAT_STATIC_METHOD(WarpAffine),
MAT_STATIC_METHOD(Blur),
MAT_STATIC_METHOD(CopyMakeBorder),
MAT_STATIC_METHOD(Flip),
MAT_STATIC_METHOD(GetRotationMatrix2D),
MAT_STATIC_METHOD(Rectangle),
MAT_STATIC_METHOD(Circle),
MAT_STATIC_METHOD(Line),
MAT_STATIC_METHOD(Ellipse),
MAT_STATIC_METHOD(Polylines),
MAT_STATIC_METHOD(FillPoly),
MAT_STATIC_METHOD(FillConvexPoly),
MAT_STATIC_METHOD(DrawMarker),
MAT_STATIC_METHOD(PutText),
MAT_INSTANCE_METHOD(IsEmpty),
MAT_INSTANCE_METHOD(GetCols),
MAT_INSTANCE_METHOD(GetRows),
MAT_INSTANCE_METHOD(GetType),
MAT_INSTANCE_METHOD(GetDepth),
MAT_INSTANCE_METHOD(GetChannels),
MAT_INSTANCE_METHOD(GetFlags),
MAT_INSTANCE_METHOD(GetDims),
MAT_INSTANCE_METHOD(GetIsContinuous),
MAT_INSTANCE_METHOD(GetIsSubmatrix),
MAT_INSTANCE_METHOD(GetElemSize),
MAT_INSTANCE_METHOD(GetElemSize1),
MAT_INSTANCE_METHOD(GetTotal),
MAT_INSTANCE_METHOD(GetTotalWithDim),
MAT_INSTANCE_METHOD(GetSize),
MAT_INSTANCE_METHOD(GetData),
MAT_INSTANCE_METHOD(Col),
MAT_INSTANCE_METHOD(ColRange),
MAT_INSTANCE_METHOD(Row),
MAT_INSTANCE_METHOD(RowRange),
MAT_INSTANCE_METHOD(Diag),
MAT_INSTANCE_METHOD(Clone),
MAT_INSTANCE_METHOD(CopyTo),
});
constructor = new FunctionReference();
*constructor = Napi::Persistent(func);
exports.Set("Mat", func);
env.SetInstanceData<FunctionReference>(constructor);
return exports;
}
CVMat::CVMat(const CallbackInfo &info)
: ObjectWrap<CVMat>(info)
{
if (info.Length() >= 2) {
auto sizesArray = info[0].As<Array>();
std::vector<int> sizes(sizesArray.Length());
for (auto i = 0; i < sizes.size(); ++i) sizes[i] = sizesArray.Get(i).As<Number>().Int32Value();
auto type = info[1].As<Number>().Int32Value();
// 使用sizes和type初始化
if (info.Length() < 3) mat_ = cv::Mat(sizes, type);
// 使用数据初始化
else if (info[2].IsTypedArray()) {
auto dataArray = info[2].As<TypedArray>();
auto data = static_cast<uint8_t *>(dataArray.ArrayBuffer().Data()) + dataArray.ByteOffset();
mat_ = cv::Mat(sizes, type, data);
}
// 其他 TODO
else mat_ = cv::Mat(sizes, type);
}
}
NODE_FUNCTION_IMPL(ImRead)
{
auto filename = info[0].As<String>().Utf8Value();
int flag = (info.Length() >= 2) ? info[1].As<Number>().Int32Value() : cv::IMREAD_COLOR_BGR;
return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = cv::imread(filename, flag); });
}
NODE_FUNCTION_IMPL(ImDecode)
{
auto arr = info[0].As<TypedArray>();
auto data = static_cast<uint8_t *>(arr.ArrayBuffer().Data()) + arr.ByteOffset();
std::vector<uint8_t> buffer(data, data + arr.ByteLength());
int flag = (info.Length() >= 2) ? info[1].As<Number>().Int32Value() : cv::IMREAD_COLOR_BGR;
return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = cv::imdecode(buffer, flag); });
}
NODE_FUNCTION_IMPL(ImWrite)
{
auto &mat = GetMat(info[0].As<Object>());
auto filename = info[1].As<String>().Utf8Value();
std::vector<int> params;
if (info[2].IsArray()) {
auto paramArray = info[2].As<Array>();
params.resize(paramArray.Length());
for (auto i = 0; i < params.size(); ++i) params[i] = paramArray.Get(i).As<Number>().Int32Value();
}
auto res = cv::imwrite(filename, mat.mat_, params);
return Boolean::New(info.Env(), res);
}
NODE_FUNCTION_IMPL(ImEncode)
{
auto &mat = GetMat(info[0].As<Object>());
auto extname = info[1].As<String>().Utf8Value();
std::vector<int> params;
if (info[2].IsArray()) {
auto paramArray = info[2].As<Array>();
params.resize(paramArray.Length());
for (auto i = 0; i < params.size(); ++i) params[i] = paramArray.Get(i).As<Number>().Int32Value();
}
std::vector<uchar> buf;
if (!cv::imencode(extname, mat.mat_, buf, params)) return info.Env().Undefined();
auto arrayBuffer = ArrayBuffer::New(info.Env(), buf.size());
auto bufferPtr = static_cast<uchar *>(arrayBuffer.Data());
for (auto ch : buf) {
*bufferPtr = ch;
bufferPtr++;
}
return arrayBuffer;
}
NODE_FUNCTION_IMPL(IsEmpty)
{
return Boolean::New(info.Env(), mat_.empty());
}
NODE_FUNCTION_IMPL(GetCols)
{
return Number::New(info.Env(), mat_.cols);
}
NODE_FUNCTION_IMPL(GetRows)
{
return Number::New(info.Env(), mat_.rows);
}
NODE_FUNCTION_IMPL(GetType)
{
return Number::New(info.Env(), mat_.type());
}
NODE_FUNCTION_IMPL(GetDepth)
{
return Number::New(info.Env(), mat_.depth());
}
NODE_FUNCTION_IMPL(GetChannels)
{
return Number::New(info.Env(), mat_.channels());
}
NODE_FUNCTION_IMPL(GetFlags)
{
return Number::New(info.Env(), mat_.flags);
}
NODE_FUNCTION_IMPL(GetDims)
{
return Number::New(info.Env(), mat_.dims);
}
NODE_FUNCTION_IMPL(GetIsContinuous)
{
return Boolean::New(info.Env(), mat_.isContinuous());
}
NODE_FUNCTION_IMPL(GetIsSubmatrix)
{
return Boolean::New(info.Env(), mat_.isSubmatrix());
}
NODE_FUNCTION_IMPL(GetElemSize)
{
return Number::New(info.Env(), static_cast<double>(mat_.elemSize()));
}
NODE_FUNCTION_IMPL(GetElemSize1)
{
return Number::New(info.Env(), static_cast<double>(mat_.elemSize1()));
}
NODE_FUNCTION_IMPL(GetTotal)
{
return Number::New(info.Env(), static_cast<double>(mat_.total()));
}
NODE_FUNCTION_IMPL(GetTotalWithDim)
{
return Number::New(info.Env(), static_cast<double>(mat_.total(info[0].As<Number>().Int32Value(), info[1].As<Number>().Int32Value())));
}
NODE_FUNCTION_IMPL(GetSize)
{
auto ret = Array::New(info.Env(), mat_.dims);
auto &size = mat_.size;
for (int i = 0; i < mat_.dims; ++i) ret.Set(i, size[i]);
return ret;
}
NODE_FUNCTION_IMPL(GetData)
{
auto ptr = mat_.ptr();
auto bytes = mat_.elemSize() * mat_.total();
return ArrayBuffer::New(info.Env(), ptr, bytes);
}
NODE_FUNCTION_IMPL(Col)
{
auto col = info[0].As<Number>().Int32Value();
return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.col(col); });
}
NODE_FUNCTION_IMPL(ColRange)
{
auto start = info[0].As<Number>().Int32Value();
auto end = info[1].As<Number>().Int32Value();
return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.colRange(start, end); });
}
NODE_FUNCTION_IMPL(Row)
{
auto row = info[0].As<Number>().Int32Value();
return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.row(row); });
}
NODE_FUNCTION_IMPL(RowRange)
{
auto start = info[0].As<Number>().Int32Value();
auto end = info[1].As<Number>().Int32Value();
return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.rowRange(start, end); });
}
NODE_FUNCTION_IMPL(Diag)
{
auto d = info[0].As<Number>().Int32Value();
return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.diag(d); });
}
NODE_FUNCTION_IMPL(Clone)
{
return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = mat_.clone(); });
}
NODE_FUNCTION_IMPL(CopyTo)
{
auto &target = GetMat(info[0].As<Object>());
mat_.copyTo(target.mat_);
return info.Env().Undefined();
}
NODE_FUNCTION_IMPL(Crop)
{
auto &src = GetMat(info[0].As<Object>());
auto &dst = GetMat(info[1].As<Object>());
auto rangeArray = info[2].As<Array>();
std::vector<cv::Range> ranges(rangeArray.Length());
for (int i = 0; i < ranges.size(); ++i) {
auto item = rangeArray.Get(i).As<Object>();
auto start = item.Get("start").As<Number>().Int32Value();
auto end = item.Get("end").As<Number>().Int32Value();
ranges[i] = cv::Range(start, end);
}
dst.mat_ = src.mat_(ranges);
return info[1];
}
NODE_FUNCTION_IMPL(Resize)
{
auto &src = GetMat(info[0].As<Object>());
auto &dst = GetMat(info[1].As<Object>());
auto width = info[2].As<Number>().Int32Value();
auto height = info[3].As<Number>().Int32Value();
auto fx = info[4].As<Number>().DoubleValue();
auto fy = info[5].As<Number>().DoubleValue();
auto interpolation = info[6].As<Number>().Int32Value();
cv::resize(src.mat_, dst.mat_, cv::Size(width, height), fx, fy, interpolation);
return info[1];
}
NODE_FUNCTION_IMPL(WarpAffine)
{
auto &src = GetMat(info[0].As<Object>());
auto &dst = GetMat(info[1].As<Object>());
auto &transformMat = GetMat(info[2].As<Object>());
auto dwidth = info[3].As<Number>().Int32Value();
auto dheight = info[4].As<Number>().Int32Value();
auto flags = info[5].As<Number>().Int32Value();
auto borderMode = info[6].As<Number>().Int32Value();
cv::warpAffine(src.mat_, dst.mat_, transformMat.mat_, cv::Size(dwidth, dheight), flags, borderMode);
return info[1];
}
NODE_FUNCTION_IMPL(Blur)
{
auto &src = GetMat(info[0].As<Object>());
auto &dst = GetMat(info[1].As<Object>());
auto kwidth = info[2].As<Number>().Int32Value();
auto kheight = info[3].As<Number>().Int32Value();
auto anchorX = info[4].As<Number>().Int32Value();
auto anchorY = info[5].As<Number>().Int32Value();
auto borderType = info[6].As<Number>().Int32Value();
cv::blur(src.mat_, dst.mat_, cv::Size(kwidth, kheight), cv::Point(anchorX, anchorY), borderType);
return info[1];
}
NODE_FUNCTION_IMPL(CopyMakeBorder)
{
auto &src = GetMat(info[0].As<Object>());
auto &dst = GetMat(info[1].As<Object>());
auto top = info[2].As<Number>().Int32Value();
auto bottom = info[3].As<Number>().Int32Value();
auto left = info[4].As<Number>().Int32Value();
auto right = info[5].As<Number>().Int32Value();
auto borderType = info[6].As<Number>().Int32Value();
cv::copyMakeBorder(src.mat_, dst.mat_, top, bottom, left, right, borderType);
return info[1];
}
NODE_FUNCTION_IMPL(Flip)
{
auto &src = GetMat(info[0].As<Object>());
auto &dst = GetMat(info[1].As<Object>());
auto flipCode = info[2].As<Number>().Int32Value();
cv::flip(src.mat_, dst.mat_, flipCode);
return info[1];
}
NODE_FUNCTION_IMPL(GetRotationMatrix2D)
{
auto centerX = info[0].As<Number>().FloatValue();
auto centerY = info[1].As<Number>().FloatValue();
auto angle = info[2].As<Number>().DoubleValue();
auto scale = info[3].As<Number>().DoubleValue();
return CreateMat(info.Env(), [&](CVMat &mat) { mat.mat_ = cv::getRotationMatrix2D(cv::Point2f(centerX, centerY), angle, scale); });
}
NODE_FUNCTION_IMPL(Rectangle)
{
auto &img = GetMat(info[0].As<Object>());
auto x1 = info[1].As<Number>().Int32Value();
auto y1 = info[2].As<Number>().Int32Value();
auto x2 = info[3].As<Number>().Int32Value();
auto y2 = info[4].As<Number>().Int32Value();
auto b = info[5].As<Number>().DoubleValue();
auto g = info[6].As<Number>().DoubleValue();
auto r = info[7].As<Number>().DoubleValue();
auto thickness = info[8].As<Number>().Int32Value();
auto lineType = info[9].As<Number>().Int32Value();
auto shift = info[10].As<Number>().Int32Value();
cv::rectangle(img.mat_, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(b, g, r), thickness, lineType, shift);
return info.Env().Undefined();
}
NODE_FUNCTION_IMPL(Circle)
{
auto &img = GetMat(info[0].As<Object>());
auto x = info[1].As<Number>().Int32Value();
auto y = info[2].As<Number>().Int32Value();
auto radius = info[3].As<Number>().Int32Value();
auto b = info[4].As<Number>().DoubleValue();
auto g = info[5].As<Number>().DoubleValue();
auto r = info[6].As<Number>().DoubleValue();
auto thickness = info[7].As<Number>().Int32Value();
auto lineType = info[8].As<Number>().Int32Value();
auto shift = info[9].As<Number>().Int32Value();
cv::circle(img.mat_, cv::Point(x, y), radius, cv::Scalar(b, g, r), thickness, lineType, shift);
return info.Env().Undefined();
}
NODE_FUNCTION_IMPL(Line)
{
auto &img = GetMat(info[0].As<Object>());
auto x1 = info[1].As<Number>().Int32Value();
auto y1 = info[2].As<Number>().Int32Value();
auto x2 = info[3].As<Number>().Int32Value();
auto y2 = info[4].As<Number>().Int32Value();
auto b = info[5].As<Number>().DoubleValue();
auto g = info[6].As<Number>().DoubleValue();
auto r = info[7].As<Number>().DoubleValue();
auto thickness = info[8].As<Number>().Int32Value();
auto lineType = info[9].As<Number>().Int32Value();
auto shift = info[10].As<Number>().Int32Value();
cv::line(img.mat_, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(b, g, r), thickness, lineType, shift);
return info.Env().Undefined();
}
NODE_FUNCTION_IMPL(Ellipse)
{
auto &img = GetMat(info[0].As<Object>());
auto x = info[1].As<Number>().Int32Value();
auto y = info[2].As<Number>().Int32Value();
auto width = info[3].As<Number>().Int32Value();
auto height = info[4].As<Number>().Int32Value();
auto angle = info[5].As<Number>().DoubleValue();
auto startAngle = info[6].As<Number>().DoubleValue();
auto endAngle = info[7].As<Number>().DoubleValue();
auto b = info[8].As<Number>().DoubleValue();
auto g = info[9].As<Number>().DoubleValue();
auto r = info[10].As<Number>().DoubleValue();
auto thickness = info[11].As<Number>().Int32Value();
auto lineType = info[12].As<Number>().Int32Value();
auto shift = info[13].As<Number>().Int32Value();
cv::ellipse(img.mat_, cv::Point(x, y), cv::Size(width, height), angle, startAngle, endAngle, cv::Scalar(b, g, r), thickness, lineType, shift);
return info.Env().Undefined();
}
NODE_FUNCTION_IMPL(Polylines)
{
auto &img = GetMat(info[0].As<Object>());
auto points_ = info[1].As<Array>();
std::vector<cv::Point> points(points_.Length());
for (uint32_t i = 0; i < points_.Length(); i++) {
auto pt = points_.Get(i).As<Array>();
points[i] = cv::Point(pt.Get(0U).As<Number>().Int32Value(), pt.Get(1U).As<Number>().Int32Value());
}
auto isClosed = info[2].As<Boolean>().Value();
auto b = info[3].As<Number>().DoubleValue();
auto g = info[4].As<Number>().DoubleValue();
auto r = info[5].As<Number>().DoubleValue();
auto thickness = info[6].As<Number>().Int32Value();
auto lineType = info[7].As<Number>().Int32Value();
auto shift = info[8].As<Number>().Int32Value();
cv::polylines(img.mat_, points, isClosed, cv::Scalar(b, g, r), thickness, lineType, shift);
return info.Env().Undefined();
}
NODE_FUNCTION_IMPL(FillPoly)
{
auto &img = GetMat(info[0].As<Object>());
auto points_ = info[1].As<Array>();
std::vector<cv::Point> points(points_.Length());
for (uint32_t i = 0; i < points_.Length(); i++) {
auto pt = points_.Get(i).As<Array>();
points[i] = cv::Point(pt.Get(0U).As<Number>().Int32Value(), pt.Get(1U).As<Number>().Int32Value());
}
auto b = info[2].As<Number>().DoubleValue();
auto g = info[3].As<Number>().DoubleValue();
auto r = info[4].As<Number>().DoubleValue();
auto lineType = info[5].As<Number>().Int32Value();
auto shift = info[6].As<Number>().Int32Value();
cv::fillPoly(img.mat_, points, cv::Scalar(b, g, r), lineType, shift);
return info.Env().Undefined();
}
NODE_FUNCTION_IMPL(FillConvexPoly)
{
auto &img = GetMat(info[0].As<Object>());
auto points_ = info[1].As<Array>();
std::vector<cv::Point> points(points_.Length());
for (uint32_t i = 0; i < points_.Length(); i++) {
auto pt = points_.Get(i).As<Array>();
points[i] = cv::Point(pt.Get(0U).As<Number>().Int32Value(), pt.Get(1U).As<Number>().Int32Value());
}
auto b = info[2].As<Number>().DoubleValue();
auto g = info[3].As<Number>().DoubleValue();
auto r = info[4].As<Number>().DoubleValue();
auto lineType = info[5].As<Number>().Int32Value();
auto shift = info[6].As<Number>().Int32Value();
cv::fillConvexPoly(img.mat_, points, cv::Scalar(b, g, r), lineType, shift);
return info.Env().Undefined();
}
NODE_FUNCTION_IMPL(DrawMarker)
{
auto &img = GetMat(info[0].As<Object>());
auto x = info[1].As<Number>().Int32Value();
auto y = info[2].As<Number>().Int32Value();
auto b = info[3].As<Number>().DoubleValue();
auto g = info[4].As<Number>().DoubleValue();
auto r = info[5].As<Number>().DoubleValue();
auto markerType = info[6].As<Number>().Int32Value();
auto markerSize = info[7].As<Number>().Int32Value();
auto lineType = info[8].As<Number>().Int32Value();
auto shift = info[9].As<Number>().Int32Value();
cv::drawMarker(img.mat_, cv::Point(x, y), cv::Scalar(b, g, r), markerType, markerSize, lineType, shift);
return info.Env().Undefined();
}
NODE_FUNCTION_IMPL(PutText)
{
auto &img = GetMat(info[0].As<Object>());
auto text = info[1].As<String>().Utf8Value();
auto x = info[2].As<Number>().Int32Value();
auto y = info[3].As<Number>().Int32Value();
auto fontFace = info[4].As<Number>().Int32Value();
auto fontScale = info[5].As<Number>().DoubleValue();
auto b = info[6].As<Number>().DoubleValue();
auto g = info[7].As<Number>().DoubleValue();
auto r = info[8].As<Number>().DoubleValue();
auto thickness = info[9].As<Number>().Int32Value();
auto lineType = info[10].As<Number>().Int32Value();
auto shift = info[11].As<Number>().Int32Value();
auto bottomLeftOrigin = info[12].As<Boolean>().Value();
cv::putText(img.mat_, text, cv::Point(x, y), fontFace, fontScale, cv::Scalar(b, g, r), thickness, lineType, bottomLeftOrigin);
return info.Env().Undefined();
}
void InitMatAPI(Napi::Env env, Napi::Object exports)
{
CVMat::Init(env, exports);
}