mirror of
https://github.com/peterbraden/node-opencv.git
synced 2025-12-08 19:45:55 +00:00
More accurate tracking of external memory using OpenCV’s reference counts
This commit is contained in:
parent
dff99718b9
commit
f8d7dc2f06
@ -283,7 +283,7 @@ NAN_METHOD(BackgroundSubtractorWrap::ApplyMOG) {
|
||||
#endif
|
||||
}
|
||||
|
||||
Local<Object> fgMask = Matrix::CreateWrappedFromMat(_fgMask);
|
||||
Local<Object> fgMask = Matrix::CreateWrappedFromMat(_fgMask.clone());
|
||||
mat.release();
|
||||
|
||||
argv[0] = Nan::Null();
|
||||
@ -309,15 +309,15 @@ public:
|
||||
AsyncBackgroundSubtractorWorker(
|
||||
Nan::Callback *callback,
|
||||
BackgroundSubtractorWrap *bg,
|
||||
cv::Mat &img_mat):
|
||||
Matrix *matrix):
|
||||
Nan::AsyncWorker(callback),
|
||||
bg(bg),
|
||||
img_mat(img_mat) { // note: this makes a new cv::Mat, and so increments the ref count for the data without copying it
|
||||
matrix(matrix) {
|
||||
|
||||
}
|
||||
|
||||
~AsyncBackgroundSubtractorWorker() {
|
||||
// upon destroy, img_mat will reduce refcount on data by one
|
||||
|
||||
}
|
||||
|
||||
// Executed inside the worker-thread.
|
||||
@ -328,9 +328,9 @@ public:
|
||||
// wait here if already in apply - auto-release on scope exit
|
||||
BGAutoMutex(bg->applymutex);
|
||||
#if CV_MAJOR_VERSION >= 3
|
||||
bg->subtractor->apply(this->img_mat, _fgMask);
|
||||
bg->subtractor->apply(matrix->mat, _fgMask);
|
||||
#else
|
||||
bg->subtractor->operator()(this->img_mat, _fgMask);
|
||||
bg->subtractor->operator()(matrix->mat, _fgMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -340,7 +340,10 @@ public:
|
||||
void HandleOKCallback() {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
Local<Object> im_to_return = Matrix::CreateWrappedFromMat(_fgMask);
|
||||
delete matrix;
|
||||
matrix = NULL;
|
||||
|
||||
Local<Object> im_to_return = Matrix::CreateWrappedFromMat(_fgMask.clone());
|
||||
|
||||
Local<Value> argv[] = {
|
||||
Nan::Null()
|
||||
@ -356,7 +359,7 @@ public:
|
||||
|
||||
private:
|
||||
BackgroundSubtractorWrap *bg;
|
||||
cv::Mat img_mat;
|
||||
Matrix *matrix;
|
||||
cv::Mat _fgMask;
|
||||
};
|
||||
|
||||
@ -395,7 +398,7 @@ NAN_METHOD(BackgroundSubtractorWrap::Apply) {
|
||||
|
||||
Nan::Callback *callback = new Nan::Callback(cb.As<Function>());
|
||||
Matrix *_img = Nan::ObjectWrap::Unwrap<Matrix>(info[0]->ToObject());
|
||||
Nan::AsyncQueueWorker(new AsyncBackgroundSubtractorWorker( callback, self, _img->mat));
|
||||
Nan::AsyncQueueWorker(new AsyncBackgroundSubtractorWorker( callback, self, new Matrix::Matrix(_img)));
|
||||
return;
|
||||
} else { //synchronous - return the image
|
||||
|
||||
@ -426,7 +429,7 @@ NAN_METHOD(BackgroundSubtractorWrap::Apply) {
|
||||
#else
|
||||
self->subtractor->operator()(mat, _fgMask);
|
||||
#endif
|
||||
fgMask = Matrix::CreateWrappedFromMat(_fgMask);
|
||||
fgMask = Matrix::CreateWrappedFromMat(_fgMask.clone());
|
||||
}
|
||||
|
||||
mat.release();
|
||||
|
||||
221
src/Matrix.cc
221
src/Matrix.cc
@ -161,13 +161,29 @@ NAN_METHOD(Matrix::New) {
|
||||
info.GetReturnValue().Set(info.Holder());
|
||||
}
|
||||
|
||||
//convenience factory method for creating a wrapped Matrix from a cv::Mat and tracking external memory correctly
|
||||
//Convenience factory method for creating a wrapped Matrix from a cv::Mat and tracking external memory correctly.
|
||||
// Always tracks the referenced matrix as external memory.
|
||||
Local<Object> Matrix::CreateWrappedFromMat(cv::Mat mat){
|
||||
Local < Object > result =
|
||||
Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *m = Nan::ObjectWrap::Unwrap<Matrix>(result);
|
||||
m->mat = mat;
|
||||
Nan::AdjustExternalMemory(m->mat.rows * m->mat.cols * m->mat.elemSize());
|
||||
Nan::AdjustExternalMemory(m->mat.dataend - m->mat.datastart);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//Convenience factory method for creating a wrapped Matrix from a cv::Mat and tracking external memory correctly.
|
||||
// Only tracks the referenced matrix as external memory if the refcount does not exceed the base refcount.
|
||||
// Useful for creating a wrapper Matrix around a Mat that is also referenced by another wrapper Matrix
|
||||
Local<Object> Matrix::CreateWrappedFromMatIfNotReferenced(cv::Mat mat, int baseRefCount){
|
||||
Local < Object > result =
|
||||
Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *m = Nan::ObjectWrap::Unwrap<Matrix>(result);
|
||||
m->mat = mat;
|
||||
if (m->getWrappedRefCount() <= 2 + baseRefCount){ //one reference in m, one on the stack
|
||||
Nan::AdjustExternalMemory(m->mat.dataend - m->mat.datastart);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -179,24 +195,28 @@ Matrix::Matrix() :
|
||||
Matrix::Matrix(int rows, int cols) :
|
||||
node_opencv::Matrix() {
|
||||
mat = cv::Mat(rows, cols, CV_32FC3);
|
||||
Nan::AdjustExternalMemory(mat.rows * mat.cols * mat.elemSize());
|
||||
Nan::AdjustExternalMemory(mat.dataend - mat.datastart);
|
||||
}
|
||||
|
||||
Matrix::Matrix(int rows, int cols, int type) :
|
||||
node_opencv::Matrix() {
|
||||
mat = cv::Mat(rows, cols, type);
|
||||
Nan::AdjustExternalMemory(mat.rows * mat.cols * mat.elemSize());
|
||||
Nan::AdjustExternalMemory(mat.dataend - mat.datastart);
|
||||
}
|
||||
|
||||
Matrix::Matrix(Matrix *m) :
|
||||
node_opencv::Matrix() {
|
||||
mat = cv::Mat(m->mat);
|
||||
}
|
||||
|
||||
Matrix::Matrix(cv::Mat m, cv::Rect roi) :
|
||||
node_opencv::Matrix() {
|
||||
mat = cv::Mat(m, roi);
|
||||
Nan::AdjustExternalMemory(mat.rows * mat.cols * mat.elemSize());
|
||||
}
|
||||
|
||||
Matrix::Matrix(int rows, int cols, int type, Local<Object> scalarObj) {
|
||||
mat = cv::Mat(rows, cols, type);
|
||||
Nan::AdjustExternalMemory(mat.rows * mat.cols * mat.elemSize());
|
||||
Nan::AdjustExternalMemory(mat.dataend - mat.datastart);
|
||||
if (mat.channels() == 3) {
|
||||
mat.setTo(cv::Scalar(scalarObj->Get(0)->IntegerValue(),
|
||||
scalarObj->Get(1)->IntegerValue(),
|
||||
@ -212,8 +232,10 @@ Matrix::Matrix(int rows, int cols, int type, Local<Object> scalarObj) {
|
||||
}
|
||||
|
||||
Matrix::~Matrix(){
|
||||
int size = mat.rows * mat.cols * mat.elemSize();
|
||||
Nan::AdjustExternalMemory(-1 * size);
|
||||
if(getWrappedRefCount() == 1){ //if this holds the last reference to the Mat
|
||||
int size = mat.dataend - mat.datastart;
|
||||
Nan::AdjustExternalMemory(-1 * size);
|
||||
}
|
||||
}
|
||||
|
||||
NAN_METHOD(Matrix::Empty) {
|
||||
@ -584,9 +606,9 @@ NAN_METHOD(Matrix::Crop) {
|
||||
int width = info[2]->IntegerValue();
|
||||
int height = info[3]->IntegerValue();
|
||||
|
||||
cv::Rect roi(x, y, width, height);
|
||||
cv::Mat mat(self->mat, cv::Rect(x,y,width,height));
|
||||
|
||||
Local < Object > im_h = Matrix::CreateWrappedFromMat(self->mat(roi));
|
||||
Local < Object > im_h = Matrix::CreateWrappedFromMatIfNotReferenced(mat, 1);
|
||||
|
||||
info.GetReturnValue().Set(im_h);
|
||||
} else {
|
||||
@ -784,10 +806,10 @@ NAN_METHOD(Matrix::ToBuffer) {
|
||||
|
||||
class AsyncToBufferWorker: public Nan::AsyncWorker {
|
||||
public:
|
||||
AsyncToBufferWorker(Nan::Callback *callback, cv::Mat mat, std::string ext,
|
||||
AsyncToBufferWorker(Nan::Callback *callback, Matrix *matrix, std::string ext,
|
||||
std::vector<int> params) :
|
||||
Nan::AsyncWorker(callback),
|
||||
mat(mat), // dulipcate mat, adding ref, but not copying data
|
||||
matrix(matrix), // dulipcate mat, adding ref, but not copying data
|
||||
ext(ext),
|
||||
params(params) {
|
||||
}
|
||||
@ -799,13 +821,16 @@ public:
|
||||
void Execute() {
|
||||
std::vector<uchar> vec(0);
|
||||
// std::vector<int> params(0);//CV_IMWRITE_JPEG_QUALITY 90
|
||||
cv::imencode(ext, this->mat, vec, this->params);
|
||||
cv::imencode(ext, matrix->mat, vec, this->params);
|
||||
res = vec;
|
||||
}
|
||||
|
||||
void HandleOKCallback() {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
delete matrix;
|
||||
matrix = NULL;
|
||||
|
||||
Local<Object> buf = Nan::NewBuffer(res.size()).ToLocalChecked();
|
||||
uchar* data = (uchar*) Buffer::Data(buf);
|
||||
memcpy(data, &res[0], res.size());
|
||||
@ -829,7 +854,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
cv::Mat mat;
|
||||
Matrix *matrix;
|
||||
std::string ext;
|
||||
std::vector<int> params;
|
||||
std::vector<uchar> res;
|
||||
@ -869,7 +894,7 @@ NAN_METHOD(Matrix::ToBufferAsync) {
|
||||
}
|
||||
|
||||
Nan::Callback *callback = new Nan::Callback(cb.As<Function>());
|
||||
Nan::AsyncQueueWorker(new AsyncToBufferWorker(callback, self->mat, ext, params));
|
||||
Nan::AsyncQueueWorker(new AsyncToBufferWorker(callback, new Matrix(self), ext, params));
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1062,9 +1087,9 @@ NAN_METHOD(Matrix::Save) {
|
||||
// https://github.com/rvagg/nan/blob/c579ae858ae3208d7e702e8400042ba9d48fa64b/examples/async_pi_estimate/async.cc
|
||||
class AsyncSaveWorker: public Nan::AsyncWorker {
|
||||
public:
|
||||
AsyncSaveWorker(Nan::Callback *callback, cv::Mat mat, char* filename) :
|
||||
AsyncSaveWorker(Nan::Callback *callback, Matrix *matrix, char* filename) :
|
||||
Nan::AsyncWorker(callback),
|
||||
mat(mat),
|
||||
matrix(matrix),
|
||||
filename(filename) {
|
||||
}
|
||||
|
||||
@ -1076,7 +1101,7 @@ public:
|
||||
// here, so everything we need for input and output
|
||||
// should go on `this`.
|
||||
void Execute() {
|
||||
res = cv::imwrite(this->filename, this->mat);
|
||||
res = cv::imwrite(this->filename, matrix->mat);
|
||||
}
|
||||
|
||||
// Executed when the async work is complete
|
||||
@ -1085,6 +1110,9 @@ public:
|
||||
void HandleOKCallback() {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
delete matrix;
|
||||
matrix = NULL;
|
||||
|
||||
Local<Value> argv[] = {
|
||||
Nan::Null(),
|
||||
Nan::New<Number>(res)
|
||||
@ -1098,7 +1126,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
cv::Mat mat;
|
||||
Matrix *matrix;
|
||||
std::string filename;
|
||||
int res;
|
||||
};
|
||||
@ -1115,7 +1143,7 @@ NAN_METHOD(Matrix::SaveAsync) {
|
||||
REQ_FUN_ARG(1, cb);
|
||||
|
||||
Nan::Callback *callback = new Nan::Callback(cb.As<Function>());
|
||||
Nan::AsyncQueueWorker(new AsyncSaveWorker(callback, self->mat, *filename));
|
||||
Nan::AsyncQueueWorker(new AsyncSaveWorker(callback, new Matrix(self), *filename));
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1166,9 +1194,9 @@ NAN_METHOD(Matrix::ConvertGrayscale) {
|
||||
Nan::ThrowError("Image is no 3-channel");
|
||||
}
|
||||
|
||||
int oldSize = self->mat.rows * self->mat.cols * self->mat.elemSize();
|
||||
int oldSize = self->mat.dataend - self->mat.datastart;
|
||||
cv::cvtColor(self->mat, self->mat, CV_BGR2GRAY);
|
||||
int newSize = self->mat.rows * self->mat.cols * self->mat.elemSize();
|
||||
int newSize = self->mat.dataend - self->mat.datastart;
|
||||
Nan::AdjustExternalMemory(newSize - oldSize);
|
||||
|
||||
info.GetReturnValue().Set(Nan::Null());
|
||||
@ -1300,7 +1328,7 @@ NAN_METHOD(Matrix::Sobel) {
|
||||
Matrix *result = Nan::ObjectWrap::Unwrap<Matrix>(result_to_return);
|
||||
|
||||
cv::Sobel(self->mat, result->mat, ddepth, xorder, yorder, ksize, scale, delta, borderType);
|
||||
Nan::AdjustExternalMemory(result->mat.rows * result->mat.cols * result->mat.elemSize());
|
||||
Nan::AdjustExternalMemory(result->mat.dataend - result->mat.datastart);
|
||||
|
||||
info.GetReturnValue().Set(result_to_return);
|
||||
}
|
||||
@ -1314,7 +1342,7 @@ NAN_METHOD(Matrix::Copy) {
|
||||
Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(img_to_return);
|
||||
self->mat.copyTo(img->mat);
|
||||
Nan::AdjustExternalMemory(img->mat.rows * img->mat.cols * img->mat.elemSize());
|
||||
Nan::AdjustExternalMemory(img->mat.dataend - img->mat.datastart);
|
||||
|
||||
info.GetReturnValue().Set(img_to_return);
|
||||
}
|
||||
@ -1334,7 +1362,7 @@ NAN_METHOD(Matrix::Flip) {
|
||||
Local<Object> img_to_return = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(img_to_return);
|
||||
cv::flip(self->mat, img->mat, flipCode);
|
||||
Nan::AdjustExternalMemory(img->mat.rows * img->mat.cols * img->mat.elemSize());
|
||||
Nan::AdjustExternalMemory(img->mat.dataend - img->mat.datastart);
|
||||
|
||||
info.GetReturnValue().Set(img_to_return);
|
||||
}
|
||||
@ -1357,7 +1385,7 @@ NAN_METHOD(Matrix::ROI) {
|
||||
|
||||
cv::Mat roi(self->mat, cv::Rect(x,y,w,h));
|
||||
// Although it's an image to return, it is in fact a pointer to ROI of parent matrix
|
||||
Local<Object> img_to_return = Matrix::CreateWrappedFromMat(roi);
|
||||
Local<Object> img_to_return = Matrix::CreateWrappedFromMatIfNotReferenced(roi, 1);
|
||||
|
||||
info.GetReturnValue().Set(img_to_return);
|
||||
}
|
||||
@ -1397,7 +1425,7 @@ NAN_METHOD(Matrix::Dct) {
|
||||
Local<Object> out = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *m_out = Nan::ObjectWrap::Unwrap<Matrix>(out);
|
||||
m_out->mat.create(cols, rows, CV_32F);
|
||||
Nan::AdjustExternalMemory(m_out->mat.rows * m_out->mat.cols * m_out->mat.elemSize());
|
||||
Nan::AdjustExternalMemory(m_out->mat.dataend - m_out->mat.datastart);
|
||||
|
||||
cv::dct(self->mat, m_out->mat);
|
||||
|
||||
@ -1414,7 +1442,7 @@ NAN_METHOD(Matrix::Idct) {
|
||||
Local<Object> out = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *m_out = Nan::ObjectWrap::Unwrap<Matrix>(out);
|
||||
m_out->mat.create(cols, rows, CV_32F);
|
||||
Nan::AdjustExternalMemory(m_out->mat.rows * m_out->mat.cols * m_out->mat.elemSize());
|
||||
Nan::AdjustExternalMemory(m_out->mat.dataend - m_out->mat.datastart);
|
||||
|
||||
cv::idct(self->mat, m_out->mat);
|
||||
|
||||
@ -1451,19 +1479,15 @@ NAN_METHOD(Matrix::Add) {
|
||||
|
||||
Matrix *src1 = Nan::ObjectWrap::Unwrap<Matrix>(info[0]->ToObject());
|
||||
|
||||
Local<Object> out = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *m_out = Nan::ObjectWrap::Unwrap<Matrix>(out);
|
||||
m_out->mat.create(cols, rows, self->mat.type());
|
||||
Nan::AdjustExternalMemory(m_out->mat.rows * m_out->mat.cols * m_out->mat.elemSize());
|
||||
|
||||
try {
|
||||
cv::add(self->mat, src1->mat, m_out->mat);
|
||||
cv::Mat outputmat = cv::Mat(cols, rows, self->mat.type());
|
||||
cv::add(self->mat, src1->mat, outputmat);
|
||||
Local<Object> out = CreateWrappedFromMat(outputmat);
|
||||
info.GetReturnValue().Set(out);
|
||||
} catch(cv::Exception& e ) {
|
||||
const char* err_msg = e.what();
|
||||
Nan::ThrowError(err_msg);
|
||||
}
|
||||
|
||||
info.GetReturnValue().Set(out);
|
||||
}
|
||||
|
||||
NAN_METHOD(Matrix::BitwiseXor) {
|
||||
@ -1916,10 +1940,10 @@ cv::Rect* setRect(Local<Object> objRect, cv::Rect &result) {
|
||||
|
||||
class ResizeASyncWorker: public Nan::AsyncWorker {
|
||||
public:
|
||||
ResizeASyncWorker(Nan::Callback *callback, cv::Mat image, cv::Size size, double fx, double fy, int interpolation) :
|
||||
ResizeASyncWorker(Nan::Callback *callback, Matrix *image, cv::Size size, double fx, double fy, int interpolation) :
|
||||
Nan::AsyncWorker(callback),
|
||||
image(image), // here, the cv::Mat is duplicated, adding to refcount without data copy
|
||||
dest(NULL),
|
||||
image(image),
|
||||
dest(cv::Mat()),
|
||||
size(size),
|
||||
fx(fx),
|
||||
fy(fy),
|
||||
@ -1928,17 +1952,14 @@ public:
|
||||
}
|
||||
|
||||
~ResizeASyncWorker() {
|
||||
// don't leave this if it was allocated
|
||||
// could happen if NaN does not call HandleSuccess?
|
||||
delete dest;
|
||||
dest = NULL;
|
||||
// cv::Mat image will be deleted, which will reduce refcount
|
||||
// Any cleanup we needed to do could be done here.
|
||||
// Clean up of the input image Matrix and the destination cv::Mat
|
||||
// should be handled automatically by destructors.
|
||||
}
|
||||
|
||||
void Execute() {
|
||||
try {
|
||||
dest = new Matrix();
|
||||
cv::resize(image, dest->mat, size, fx, fy, interpolation);
|
||||
cv::resize(image->mat, dest, size, fx, fy, interpolation);
|
||||
success = 1;
|
||||
} catch(...){
|
||||
success = 0;
|
||||
@ -1950,9 +1971,10 @@ public:
|
||||
|
||||
if (success){
|
||||
try{
|
||||
Local<Object> im_to_return = Matrix::CreateWrappedFromMat(dest->mat);
|
||||
delete dest;
|
||||
dest = NULL;
|
||||
Local<Object> im_to_return = Matrix::CreateWrappedFromMat(dest);
|
||||
delete image;
|
||||
image = NULL;
|
||||
dest.release(); //release our refcount before handing it back to the callback
|
||||
|
||||
Local<Value> argv[] = {
|
||||
Nan::Null(), // err
|
||||
@ -1965,8 +1987,6 @@ public:
|
||||
Nan::FatalException(try_catch);
|
||||
}
|
||||
} catch (...){
|
||||
delete dest;
|
||||
dest = NULL;
|
||||
Local<Value> argv[] = {
|
||||
Nan::New("C++ exception wrapping response").ToLocalChecked(), // err
|
||||
Nan::Null() // result
|
||||
@ -1979,9 +1999,6 @@ public:
|
||||
}
|
||||
}
|
||||
} else {
|
||||
delete dest;
|
||||
dest = NULL;
|
||||
|
||||
Local<Value> argv[] = {
|
||||
Nan::New("C++ exception").ToLocalChecked(), // err
|
||||
Nan::Null() //result
|
||||
@ -1996,8 +2013,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
cv::Mat image;
|
||||
Matrix *dest;
|
||||
Matrix *image;
|
||||
cv::Mat dest;
|
||||
cv::Size size;
|
||||
double fx;
|
||||
double fy;
|
||||
@ -2062,17 +2079,17 @@ NAN_METHOD(Matrix::Resize) {
|
||||
if (isAsync){
|
||||
REQ_FUN_ARG(numargs-1, cb);
|
||||
Nan::Callback *callback = new Nan::Callback(cb.As<Function>());
|
||||
Nan::AsyncQueueWorker(new ResizeASyncWorker(callback, self->mat, size, fx, fy, interpolation));
|
||||
Nan::AsyncQueueWorker(new ResizeASyncWorker(callback, new Matrix(self), size, fx, fy, interpolation));
|
||||
info.GetReturnValue().Set(Nan::Null());
|
||||
} else {
|
||||
try{
|
||||
Matrix *self = Nan::ObjectWrap::Unwrap<Matrix>(info.This());
|
||||
int oldSize = self->mat.rows * self->mat.cols * self->mat.elemSize();
|
||||
int oldSize = (self->getWrappedRefCount() == 1) ? self->mat.dataend - self->mat.datastart : 0;
|
||||
cv::Mat res = cv::Mat(x, y, CV_32FC3);
|
||||
cv::resize(self->mat, res, cv::Size(x, y), 0, 0, interpolation);
|
||||
~self->mat;
|
||||
self->mat = res;
|
||||
int newSize = self->mat.rows * self->mat.cols * self->mat.elemSize();
|
||||
int newSize = self->mat.dataend - self->mat.datastart;
|
||||
Nan::AdjustExternalMemory(newSize - oldSize);
|
||||
} catch (...){
|
||||
return Nan::ThrowError("c++ Exception processing resize");
|
||||
@ -2302,13 +2319,12 @@ NAN_METHOD(Matrix::Threshold) {
|
||||
}
|
||||
}
|
||||
|
||||
Local < Object > img_to_return =
|
||||
Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(img_to_return);
|
||||
self->mat.copyTo(img->mat);
|
||||
cv::Mat outputmat = cv::Mat();
|
||||
self->mat.copyTo(outputmat);
|
||||
|
||||
cv::threshold(self->mat, img->mat, threshold, maxVal, typ);
|
||||
Nan::AdjustExternalMemory(img->mat.rows * img->mat.cols * img->mat.elemSize());
|
||||
cv::threshold(self->mat, outputmat, threshold, maxVal, typ);
|
||||
|
||||
Local < Object > img_to_return = CreateWrappedFromMat(outputmat);
|
||||
|
||||
info.GetReturnValue().Set(img_to_return);
|
||||
}
|
||||
@ -2322,14 +2338,13 @@ NAN_METHOD(Matrix::AdaptiveThreshold) {
|
||||
double blockSize = info[3]->NumberValue();
|
||||
double C = info[4]->NumberValue();
|
||||
|
||||
Local < Object > img_to_return =
|
||||
Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(img_to_return);
|
||||
self->mat.copyTo(img->mat);
|
||||
cv::Mat outputmat = cv::Mat();
|
||||
self->mat.copyTo(outputmat);
|
||||
|
||||
cv::adaptiveThreshold(self->mat, img->mat, maxVal, adaptiveMethod,
|
||||
cv::adaptiveThreshold(self->mat, outputmat, maxVal, adaptiveMethod,
|
||||
thresholdType, blockSize, C);
|
||||
Nan::AdjustExternalMemory(img->mat.rows * img->mat.cols * img->mat.elemSize());
|
||||
|
||||
Local < Object > img_to_return = CreateWrappedFromMat(outputmat);
|
||||
|
||||
info.GetReturnValue().Set(img_to_return);
|
||||
}
|
||||
@ -2339,18 +2354,14 @@ NAN_METHOD(Matrix::MeanStdDev) {
|
||||
|
||||
Matrix *self = Nan::ObjectWrap::Unwrap<Matrix>(info.This());
|
||||
|
||||
Local<Object> mean = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *m_mean = Nan::ObjectWrap::Unwrap<Matrix>(mean);
|
||||
Local<Object> stddev = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *m_stddev = Nan::ObjectWrap::Unwrap<Matrix>(stddev);
|
||||
cv::Mat meanMat = cv::Mat();
|
||||
cv::Mat stddevMat = cv::Mat();
|
||||
|
||||
cv::meanStdDev(self->mat, m_mean->mat, m_stddev->mat);
|
||||
Nan::AdjustExternalMemory(m_mean->mat.rows * m_mean->mat.cols * m_mean->mat.elemSize());
|
||||
Nan::AdjustExternalMemory(m_stddev->mat.rows * m_stddev->mat.cols * m_stddev->mat.elemSize());
|
||||
cv::meanStdDev(self->mat, meanMat, stddevMat);
|
||||
|
||||
Local<Object> data = Nan::New<Object>();
|
||||
data->Set(Nan::New<String>("mean").ToLocalChecked(), mean);
|
||||
data->Set(Nan::New<String>("stddev").ToLocalChecked(), stddev);
|
||||
data->Set(Nan::New<String>("mean").ToLocalChecked(), CreateWrappedFromMat(meanMat));
|
||||
data->Set(Nan::New<String>("stddev").ToLocalChecked(), CreateWrappedFromMat(stddevMat));
|
||||
|
||||
info.GetReturnValue().Set(data);
|
||||
}
|
||||
@ -2479,9 +2490,9 @@ NAN_METHOD(Matrix::CvtColor) {
|
||||
Nan::ThrowTypeError("Conversion code is unsupported");
|
||||
}
|
||||
|
||||
int oldSize = self->mat.rows * self->mat.cols * self->mat.elemSize();
|
||||
int oldSize = self->mat.dataend - self->mat.datastart;
|
||||
cv::cvtColor(self->mat, self->mat, iTransform);
|
||||
int newSize = self->mat.rows * self->mat.cols * self->mat.elemSize();
|
||||
int newSize = self->mat.dataend - self->mat.datastart;
|
||||
if(oldSize != newSize){
|
||||
Nan::AdjustExternalMemory(newSize - oldSize);
|
||||
}
|
||||
@ -2508,7 +2519,7 @@ NAN_METHOD(Matrix::Split) {
|
||||
size = channels.size();
|
||||
v8::Local<v8::Array> arrChannels = Nan::New<Array>(size);
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
Local<Object> matObject = Matrix::CreateWrappedFromMat(channels[i]);
|
||||
Local<Object> matObject = Matrix::CreateWrappedFromMatIfNotReferenced(channels[i], 1);
|
||||
arrChannels->Set(i, matObject);
|
||||
}
|
||||
|
||||
@ -2524,7 +2535,7 @@ NAN_METHOD(Matrix::Merge) {
|
||||
if (!info[0]->IsArray()) {
|
||||
Nan::ThrowTypeError("The argument must be an array");
|
||||
}
|
||||
int oldSize = self->mat.rows * self->mat.cols * self->mat.elemSize();
|
||||
int oldSize = self->mat.dataend - self->mat.datastart;
|
||||
v8::Local<v8::Array> jsChannels = v8::Local<v8::Array>::Cast(info[0]);
|
||||
|
||||
unsigned int L = jsChannels->Length();
|
||||
@ -2534,7 +2545,7 @@ NAN_METHOD(Matrix::Merge) {
|
||||
vChannels[i] = matObject->mat;
|
||||
}
|
||||
cv::merge(vChannels, self->mat);
|
||||
int newSize = self->mat.rows * self->mat.cols * self->mat.elemSize();
|
||||
int newSize = self->mat.dataend - self->mat.datastart;
|
||||
Nan::AdjustExternalMemory(newSize - oldSize);
|
||||
|
||||
return;
|
||||
@ -2694,7 +2705,7 @@ NAN_METHOD(Matrix::MatchTemplateByMatrix) {
|
||||
int cols = self->mat.cols - templ->mat.cols + 1;
|
||||
int rows = self->mat.rows - templ->mat.rows + 1;
|
||||
m_out->mat.create(cols, rows, CV_32FC1);
|
||||
Nan::AdjustExternalMemory(m_out->mat.rows * m_out->mat.cols * m_out->mat.elemSize());
|
||||
Nan::AdjustExternalMemory(m_out->mat.dataend - m_out->mat.datastart);
|
||||
|
||||
/*
|
||||
TM_SQDIFF =0
|
||||
@ -2729,7 +2740,7 @@ NAN_METHOD(Matrix::MatchTemplate) {
|
||||
int cols = self->mat.cols - templ.cols + 1;
|
||||
int rows = self->mat.rows - templ.rows + 1;
|
||||
m_out->mat.create(cols, rows, CV_32FC1);
|
||||
Nan::AdjustExternalMemory(m_out->mat.rows * m_out->mat.cols * m_out->mat.elemSize());
|
||||
Nan::AdjustExternalMemory(m_out->mat.dataend - m_out->mat.datastart);
|
||||
|
||||
/*
|
||||
TM_SQDIFF =0
|
||||
@ -3038,7 +3049,7 @@ NAN_METHOD(Matrix::Reshape) {
|
||||
JSTHROW("Invalid number of arguments");
|
||||
}
|
||||
|
||||
Local<Object> img_to_return = Matrix::CreateWrappedFromMat(self->mat.reshape(cn, rows));
|
||||
Local<Object> img_to_return = Matrix::CreateWrappedFromMatIfNotReferenced(self->mat.reshape(cn, rows),0);
|
||||
|
||||
info.GetReturnValue().Set(img_to_return);
|
||||
}
|
||||
@ -3047,9 +3058,13 @@ NAN_METHOD(Matrix::Release) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
Matrix *self = Nan::ObjectWrap::Unwrap<Matrix>(info.This());
|
||||
int size = self->mat.rows * self->mat.cols * self->mat.elemSize();
|
||||
|
||||
if(self->getWrappedRefCount() == 1){
|
||||
int size = self->mat.dataend - self->mat.datastart;
|
||||
Nan::AdjustExternalMemory(-1 * size);
|
||||
}
|
||||
|
||||
self->mat.release();
|
||||
Nan::AdjustExternalMemory(-1 * size);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -3065,25 +3080,29 @@ NAN_METHOD(Matrix::Release) {
|
||||
//}
|
||||
|
||||
|
||||
NAN_METHOD(Matrix::GetrefCount) {
|
||||
Nan::HandleScope scope;
|
||||
Matrix *self = Nan::ObjectWrap::Unwrap<Matrix>(info.This());
|
||||
|
||||
int refcount = -1;
|
||||
|
||||
int Matrix::getWrappedRefCount(){
|
||||
int refcount = -1;
|
||||
#if CV_MAJOR_VERSION >= 3
|
||||
if (self->mat.u){
|
||||
refcount = self->mat.u->refcount;
|
||||
if (mat.u){
|
||||
refcount = mat.u->refcount;
|
||||
} else {
|
||||
refcount = -1; // indicates no reference ptr
|
||||
}
|
||||
#else
|
||||
if (self->mat.refcount){
|
||||
refcount = *(self->mat.refcount);
|
||||
if (mat.refcount){
|
||||
refcount = *(mat.refcount);
|
||||
} else {
|
||||
refcount = -1; // indicates no reference ptr
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return refcount;
|
||||
}
|
||||
|
||||
NAN_METHOD(Matrix::GetrefCount) {
|
||||
Nan::HandleScope scope;
|
||||
Matrix *self = Nan::ObjectWrap::Unwrap<Matrix>(info.This());
|
||||
|
||||
int refcount = self->getWrappedRefCount();
|
||||
|
||||
info.GetReturnValue().Set(Nan::New<Number>(refcount));
|
||||
return;
|
||||
|
||||
@ -8,7 +8,10 @@ public:
|
||||
static void Init(Local<Object> target);
|
||||
static NAN_METHOD(New);
|
||||
static Local<Object> CreateWrappedFromMat(cv::Mat mat);
|
||||
static Local<Object> CreateWrappedFromMatIfNotReferenced(cv::Mat mat, int baseRefCount);
|
||||
int getWrappedRefCount();
|
||||
Matrix();
|
||||
Matrix(Matrix *other);
|
||||
Matrix(cv::Mat other, cv::Rect roi);
|
||||
Matrix(int rows, int cols);
|
||||
Matrix(int rows, int cols, int type);
|
||||
|
||||
@ -49,6 +49,7 @@ public:
|
||||
|
||||
try{
|
||||
Local<Object> im_to_return = Matrix::CreateWrappedFromMat(outputmat);
|
||||
outputmat.release();
|
||||
|
||||
Local<Value> argv[] = {
|
||||
Nan::Null(),
|
||||
@ -110,6 +111,7 @@ public:
|
||||
Nan::HandleScope scope;
|
||||
|
||||
Local<Object> im_to_return = Matrix::CreateWrappedFromMat(outputmat);
|
||||
outputmat.release();
|
||||
|
||||
Local<Value> argv[] = {
|
||||
Nan::Null(),
|
||||
@ -165,7 +167,7 @@ NAN_METHOD(OpenCV::ReadImageAsync) {
|
||||
|
||||
width = info[0]->Uint32Value();
|
||||
height = info[1]->Uint32Value();
|
||||
Local<Object> img_to_return = Matrix::CreateWrappedFromMat(*(new cv::Mat(width, height, type)));
|
||||
Local<Object> img_to_return = Matrix::CreateWrappedFromMat(cv::Mat(width, height, type));
|
||||
if (callback_arg < 0){
|
||||
info.GetReturnValue().Set(img_to_return);
|
||||
return;
|
||||
@ -287,7 +289,7 @@ NAN_METHOD(OpenCV::ReadImage) {
|
||||
}
|
||||
width = info[0]->Uint32Value();
|
||||
height = info[1]->Uint32Value();
|
||||
mat = *(new cv::Mat(width, height, type));
|
||||
mat = cv::Mat(width, height, type);
|
||||
|
||||
} else if (info[0]->IsString()) {
|
||||
std::string filename = std::string(*Nan::Utf8String(info[0]->ToString()));
|
||||
@ -318,7 +320,7 @@ NAN_METHOD(OpenCV::ReadImage) {
|
||||
}
|
||||
|
||||
img->mat = mat;
|
||||
Nan::AdjustExternalMemory(img->mat.rows * img->mat.cols * img->mat.elemSize());
|
||||
Nan::AdjustExternalMemory(img->mat.dataend - img->mat.datastart);
|
||||
} catch (cv::Exception& e) {
|
||||
argv[0] = Nan::Error(e.what());
|
||||
argv[1] = Nan::Null();
|
||||
|
||||
@ -40,7 +40,7 @@ void VideoCaptureWrap::Init(Local<Object> target) {
|
||||
Nan::SetPrototypeMethod(ctor, "getFPS", GetFPS);
|
||||
Nan::SetPrototypeMethod(ctor, "setFPS", SetFPS);
|
||||
Nan::SetPrototypeMethod(ctor, "release", Release);
|
||||
Nan::SetPrototypeMethod(ctor, "ReadSync", ReadSync);
|
||||
Nan::SetPrototypeMethod(ctor, "readSync", ReadSync);
|
||||
Nan::SetPrototypeMethod(ctor, "grab", Grab);
|
||||
Nan::SetPrototypeMethod(ctor, "retrieve", Retrieve);
|
||||
|
||||
@ -238,6 +238,7 @@ public:
|
||||
Nan::HandleScope scope;
|
||||
|
||||
Local<Object> im_to_return = Matrix::CreateWrappedFromMat(mat);
|
||||
mat.release();
|
||||
|
||||
Local<Value> argv[] = {
|
||||
Nan::Null()
|
||||
@ -274,11 +275,10 @@ NAN_METHOD(VideoCaptureWrap::ReadSync) {
|
||||
Nan::HandleScope scope;
|
||||
VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap<VideoCaptureWrap>(info.This());
|
||||
|
||||
Local<Object> im_to_return= Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||
Matrix *img = Nan::ObjectWrap::Unwrap<Matrix>(im_to_return);
|
||||
cv::Mat outputmat = cv::Mat();
|
||||
v->cap.read(outputmat);
|
||||
|
||||
v->cap.read(img->mat);
|
||||
Nan::AdjustExternalMemory(img->mat.rows * img->mat.cols * img->mat.elemSize());
|
||||
Local<Object> im_to_return = Matrix::CreateWrappedFromMat(outputmat);
|
||||
|
||||
info.GetReturnValue().Set(im_to_return);
|
||||
}
|
||||
|
||||
980
test/memory.js
Normal file
980
test/memory.js
Normal file
@ -0,0 +1,980 @@
|
||||
require("v8").setFlagsFromString('--expose_gc');
|
||||
var gc = require("vm").runInNewContext('gc');
|
||||
|
||||
var fs = require('fs')
|
||||
, path = require('path')
|
||||
, test = require('tape')
|
||||
, cv = require('../lib/opencv');
|
||||
|
||||
var IMAGE_PATH = path.resolve(__dirname, '../examples/files', 'mona.png');
|
||||
var TEMP_SAVE_PATH = path.resolve(__dirname, '../examples/tmp', 'out.jpg');
|
||||
|
||||
// These tests check that every function that creates or modifies a Matrix handles its externally tracked memory correctly.
|
||||
// Since the memory tracker uses OpenCV's reference counting to determine when to tell Node about memory changes,
|
||||
// it is important that only Matrix objects that Javascript knows about retain references to internal OpenCV Mat objects.
|
||||
// Reference counts for newly created objects should ususally therefore be 1, and releasing them should alter the
|
||||
// externally tracked memory appropriately.
|
||||
|
||||
// Note that garbage collection could run at any time, which could interfere with measurements of external memory,
|
||||
// so these tests manually run garbage collection as part of their setup to minimize this possibility.
|
||||
|
||||
//********************
|
||||
// Image Reading
|
||||
//********************
|
||||
|
||||
test("readImage", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = cv.readImage(IMAGE_PATH);
|
||||
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 1134000); //image is tracked as external memory
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("readImage creating a new 100x100 matrix", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = cv.readImage(100,100);
|
||||
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 80000); //image is tracked as external memory
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("readImage from data buffer", t=>{
|
||||
gc();
|
||||
var buffer = fs.readFileSync(IMAGE_PATH);
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = cv.readImage(buffer);
|
||||
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 1134000); //image is tracked as external memory
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("readImage (callback pattern)", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
cv.readImage(IMAGE_PATH, (err, image) => {
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 1134000); //image is tracked as external memory
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("readImage creating a new 100x100 matrix (callback pattern)", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
cv.readImage(100, 100, (err, image) => {
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 80000); //image is tracked as external memory
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("readImage from data buffer (callback pattern)", t=>{
|
||||
gc();
|
||||
var buffer = fs.readFileSync(IMAGE_PATH);
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
cv.readImage(buffer, (err, image) => {
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 1134000); //image is tracked as external memory
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("readImageAsync", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
cv.readImageAsync(IMAGE_PATH, (err, image) => {
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 1134000); //image is tracked as external memory
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("readImageAsync creating a new 100x100 matrix", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
cv.readImageAsync(100, 100, (err, image) => {
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 80000); //image is tracked as external memory
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("readImageAsync from data buffer", t=>{
|
||||
gc();
|
||||
var buffer = fs.readFileSync(IMAGE_PATH);
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
cv.readImageAsync(buffer, (err, image) => {
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 1134000); //image is tracked as external memory
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("video capture async", t=>{
|
||||
gc();
|
||||
var vid = new cv.VideoCapture(path.resolve(__dirname, '../examples/files', 'motion.mov'));
|
||||
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
vid.read( (err, im) => {
|
||||
|
||||
t.equal(im.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 545280); //image is tracked as external memory
|
||||
|
||||
im.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("video capture sync", t=>{
|
||||
gc();
|
||||
var vid = new cv.VideoCapture(path.resolve(__dirname, '../examples/files', 'motion.mov'));
|
||||
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var im = vid.readSync();
|
||||
|
||||
t.equal(im.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 545280);
|
||||
|
||||
im.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
//********************
|
||||
// Matrix Constructors
|
||||
//********************
|
||||
|
||||
// Base constructor, doesn't actually allocate any memory
|
||||
test("Matrix()", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix();
|
||||
|
||||
t.equal(image.getrefCount(), -1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 0);
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// Constructor with a size
|
||||
test("Matrix(int, int)", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(100, 100);
|
||||
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 120000); //100 * 100 * size of CV_32FC3 (12)
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// Constructor with a size and type
|
||||
test("Matrix(int, int, type)", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(100, 100, cv.Constants.CV_8UC1);
|
||||
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 10000); //100 * 100
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// Constructor with a size, type, and initial values
|
||||
test("Matrix(int, int, type, [values])", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
|
||||
// Constructor with an existing matrix and a region of interest
|
||||
test("Matrix(Matrix, x, y, w, h)", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
var image = new cv.Matrix(originalImage, 25, 25, 50, 50); //this should share memory with the original
|
||||
t.equal(image.getrefCount(), 2); //so the refcount goes up
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //but the memory usage does not
|
||||
|
||||
originalImage.release();
|
||||
t.equal(originalImage.getrefCount(), -1);
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000);
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix.Zeros", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = cv.Matrix.Zeros(100, 100);
|
||||
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 80000); //100 * 100 * size of CV_64FC1
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix.Ones", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = cv.Matrix.Ones(100, 100);
|
||||
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 80000); //100 * 100 * size of CV_64FC1
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix.Eye", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = cv.Matrix.Eye(100, 100);
|
||||
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 80000); //100 * 100 * size of CV_64FC1
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
//********************
|
||||
// Matrix Functions
|
||||
//********************
|
||||
|
||||
test("Matrix clone", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
var image = originalImage.clone();
|
||||
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 60000);
|
||||
|
||||
originalImage.release();
|
||||
t.equal(originalImage.getrefCount(), -1);
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000);
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix crop", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
t.equal(originalImage.height(), 100);
|
||||
|
||||
var image = originalImage.crop(25, 25, 50, 50); //crops share memory with the original
|
||||
t.equal(originalImage.height(), 100);
|
||||
t.equal(image.height(), 50);
|
||||
t.equal(image.getrefCount(), 2);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000);
|
||||
|
||||
originalImage.release();
|
||||
t.equal(originalImage.getrefCount(), -1);
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000);
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
//ROI in this implementation is basically the same thing as crop
|
||||
test("Matrix roi", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
t.equal(originalImage.height(), 100);
|
||||
|
||||
var image = originalImage.roi(25, 25, 50, 50); //ROIs share memory with the original
|
||||
t.equal(originalImage.height(), 100);
|
||||
t.equal(image.height(), 50);
|
||||
t.equal(image.getrefCount(), 2);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000);
|
||||
|
||||
originalImage.release();
|
||||
t.equal(originalImage.getrefCount(), -1);
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000);
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix convertGrayscale", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
originalImage.convertGrayscale();
|
||||
t.equal(process.memoryUsage().external - startingMemory, 10000); //grayscale takes less space
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
|
||||
originalImage.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix sobel", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
var resultImage = originalImage.sobel(cv.Constants.CV_16S, 1, 1);
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 90000); //our original 30k image plus our new 60k one
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
t.equal(resultImage.getrefCount(), 1);
|
||||
|
||||
originalImage.release();
|
||||
resultImage.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix copy", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
var resultImage = originalImage.copy(0);
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 60000); //our original image plus our new one
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
t.equal(resultImage.getrefCount(), 1);
|
||||
|
||||
originalImage.release();
|
||||
resultImage.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix flip", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
var resultImage = originalImage.flip(0);
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 60000); //our original image plus our new one
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
t.equal(resultImage.getrefCount(), 1);
|
||||
|
||||
originalImage.release();
|
||||
resultImage.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix dct", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_32F);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 40000); //100 * 100 * 4
|
||||
|
||||
var resultImage = originalImage.dct();
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 80000); //our original image plus our new one
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
t.equal(resultImage.getrefCount(), 1);
|
||||
|
||||
originalImage.release();
|
||||
resultImage.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix idct", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_32F);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 40000); //100 * 100 * 4
|
||||
|
||||
var resultImage = originalImage.idct();
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 80000); //our original image plus our new one
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
t.equal(resultImage.getrefCount(), 1);
|
||||
|
||||
originalImage.release();
|
||||
resultImage.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix add", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var src1 = new cv.Matrix.Ones(100, 100);
|
||||
var src2 = new cv.Matrix.Ones(100, 100);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 160000);
|
||||
|
||||
var resultMatrix = src1.add(src2);
|
||||
|
||||
t.equal(resultMatrix.get(0,0), 2); //just making sure the result is correct
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 240000);
|
||||
t.equal(src1.getrefCount(), 1);
|
||||
t.equal(src2.getrefCount(), 1);
|
||||
t.equal(resultMatrix.getrefCount(), 1);
|
||||
|
||||
src1.release();
|
||||
src2.release();
|
||||
resultMatrix.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix resize", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
image.resize(50, 50);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 7500); //50 * 50 * 3
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix resize async", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
image.resize(50, 50, (err, resizedImage)=>{
|
||||
t.equal(image.height(), 100); //we have both the original and the resized image
|
||||
t.equal(resizedImage.height(), 50);
|
||||
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(resizedImage.getrefCount(), 1);
|
||||
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 37500);
|
||||
|
||||
image.release();
|
||||
resizedImage.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("Matrix resize async edge case", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(1000, 1000, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 3000000); //100 * 100 * 3
|
||||
|
||||
image.resize(50, 50, (err, resizedImage)=>{
|
||||
t.equal(image.getrefCount(), -1); //this happens second, image should have been released already
|
||||
t.equal(resizedImage.getrefCount(), 1);
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 7500);
|
||||
|
||||
resizedImage.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
image.release(); //this happens first
|
||||
});
|
||||
|
||||
test("Matrix threshold", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_8U);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 10000); //100 * 100
|
||||
|
||||
var resultImage = originalImage.threshold(1,1);
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 20000); //our original image plus our new one
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
t.equal(resultImage.getrefCount(), 1);
|
||||
|
||||
originalImage.release();
|
||||
resultImage.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix adaptiveThreshold", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var originalImage = new cv.Matrix(100, 100, cv.Constants.CV_8U);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 10000); //100 * 100
|
||||
|
||||
var resultImage = originalImage.adaptiveThreshold(255, 0, 0, 15, 2);
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 20000); //our original image plus our new one
|
||||
t.equal(originalImage.getrefCount(), 1);
|
||||
t.equal(resultImage.getrefCount(), 1);
|
||||
|
||||
originalImage.release();
|
||||
resultImage.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix meanStdDev", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var matrix = new cv.Matrix.Ones(100, 100, cv.Constants.CV_8UC3);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000);
|
||||
|
||||
var result = matrix.meanStdDev();
|
||||
|
||||
t.equal(result.mean.getrefCount(), 1);
|
||||
t.equal(result.stddev.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30048);
|
||||
|
||||
matrix.release();
|
||||
result.mean.release();
|
||||
result.stddev.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix copyTo", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var smallImg = new cv.Matrix.Ones(25, 25, cv.Constants.CV_8UC3);
|
||||
var bigImg = cv.Matrix.Zeros(100, 100, cv.Constants.CV_8UC3);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000 + 1875);
|
||||
|
||||
smallImg.copyTo(bigImg, 0, 0);
|
||||
|
||||
t.equal(smallImg.getrefCount(), 1);
|
||||
t.equal(bigImg.getrefCount(), 1);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000 + 1875);
|
||||
|
||||
smallImg.release();
|
||||
bigImg.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix cvtColor", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
image.cvtColor("CV_BGR2GRAY");
|
||||
t.equal(process.memoryUsage().external - startingMemory, 10000); //grayscale is smaller
|
||||
|
||||
image.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix split", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
var result = image.split();
|
||||
t.equal(process.memoryUsage().external - startingMemory, 60000);
|
||||
|
||||
image.release();
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000);
|
||||
|
||||
result.forEach(m => m.release());
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix merge", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image1 = new cv.Matrix(100, 100, cv.Constants.CV_8UC1, [0]);
|
||||
var image2 = new cv.Matrix(100, 100, cv.Constants.CV_8UC1, [0]);
|
||||
var image3 = new cv.Matrix(100, 100, cv.Constants.CV_8UC1, [0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
var result = new cv.Matrix(10,10);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000 + 1200);
|
||||
|
||||
result.merge([image1, image2, image3]);
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 60000);
|
||||
|
||||
result.release();
|
||||
image1.release();
|
||||
image2.release();
|
||||
image3.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test("Matrix reshape", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(100, 100, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //100 * 100 * 3
|
||||
|
||||
var result = image.reshape(2);
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000); //reshape does not copy data, so the allocated size hasn't changed
|
||||
|
||||
image.release();
|
||||
|
||||
t.equal(process.memoryUsage().external - startingMemory, 30000);
|
||||
|
||||
result.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
//********************
|
||||
// Additional Asynchronous Matrix Functions
|
||||
//********************
|
||||
|
||||
|
||||
test("Matrix toBuffer async edge case", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(1000, 1000, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 3000000); //100 * 100 * 3
|
||||
|
||||
image.toBufferAsync((err, buffer)=>{
|
||||
t.equal(image.getrefCount(), -1); //this happens second, image should have been released already
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 33006); //the size of the buffer, which hasn't been released yet
|
||||
t.end();
|
||||
});
|
||||
image.release();
|
||||
});
|
||||
|
||||
test("Matrix save async edge case", t=>{
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(1000, 1000, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 3000000); //100 * 100 * 3
|
||||
|
||||
image.saveAsync(TEMP_SAVE_PATH, (err, buffer)=>{
|
||||
t.equal(image.getrefCount(), -1); //this happens second, image should have been released already
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
|
||||
fs.unlinkSync(TEMP_SAVE_PATH);
|
||||
t.end();
|
||||
});
|
||||
image.release();
|
||||
});
|
||||
|
||||
//********************
|
||||
// Background Subtractors
|
||||
//********************
|
||||
|
||||
function testSyncBackgroundSubtractor(t, subtractor){
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(1000, 1000, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 3000000); //100 * 100 * 3
|
||||
|
||||
var output = subtractor.apply(image);
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(output.getrefCount(), 1);
|
||||
|
||||
image.release();
|
||||
output.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
|
||||
t.end();
|
||||
}
|
||||
|
||||
function testAsyncBackgroundSubtractor(t, subtractor){
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(1000, 1000, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 3000000); //100 * 100 * 3
|
||||
|
||||
subtractor.apply(image, (err, output) => {
|
||||
t.equal(image.getrefCount(), 1);
|
||||
t.equal(output.getrefCount(), 1);
|
||||
|
||||
image.release();
|
||||
output.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
|
||||
t.end();
|
||||
});
|
||||
}
|
||||
|
||||
function testAsyncBackgroundSubtractorEarlyRelease(t, subtractor){
|
||||
gc();
|
||||
var startingMemory = process.memoryUsage().external;
|
||||
|
||||
var image = new cv.Matrix(1000, 1000, cv.Constants.CV_8UC3, [0,0,0]);
|
||||
t.equal(process.memoryUsage().external - startingMemory, 3000000); //100 * 100 * 3
|
||||
|
||||
subtractor.apply(image, (err, output) => {
|
||||
t.equal(image.getrefCount(), -1);
|
||||
t.equal(output.getrefCount(), 1);
|
||||
|
||||
output.release();
|
||||
|
||||
var endingMemory = process.memoryUsage().external;
|
||||
t.equal(endingMemory - startingMemory, 0);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
image.release();
|
||||
}
|
||||
|
||||
test("default background subtractor", t=>{
|
||||
testSyncBackgroundSubtractor(t, new cv.BackgroundSubtractor());
|
||||
});
|
||||
|
||||
test("MOG background subtractor", t=>{
|
||||
testSyncBackgroundSubtractor(t, cv.BackgroundSubtractor.createMOG());
|
||||
});
|
||||
|
||||
test("MOG2 background subtractor", t=>{
|
||||
testSyncBackgroundSubtractor(t, cv.BackgroundSubtractor.createMOG2());
|
||||
});
|
||||
|
||||
test("GMG background subtractor", t=>{
|
||||
testSyncBackgroundSubtractor(t, cv.BackgroundSubtractor.createGMG());
|
||||
});
|
||||
|
||||
test("default background subtractor async", t=>{
|
||||
testAsyncBackgroundSubtractor(t, new cv.BackgroundSubtractor());
|
||||
});
|
||||
|
||||
test("MOG background subtractor async", t=>{
|
||||
testAsyncBackgroundSubtractor(t, cv.BackgroundSubtractor.createMOG());
|
||||
});
|
||||
|
||||
test("MOG2 background subtractor async", t=>{
|
||||
testAsyncBackgroundSubtractor(t, cv.BackgroundSubtractor.createMOG2());
|
||||
});
|
||||
|
||||
test("GMG background subtractor async", t=>{
|
||||
testAsyncBackgroundSubtractor(t, cv.BackgroundSubtractor.createGMG());
|
||||
});
|
||||
|
||||
test("default background subtractor async early release", t=>{
|
||||
testAsyncBackgroundSubtractorEarlyRelease(t, new cv.BackgroundSubtractor());
|
||||
});
|
||||
|
||||
test("MOG background subtractor async early release", t=>{
|
||||
testAsyncBackgroundSubtractorEarlyRelease(t, cv.BackgroundSubtractor.createMOG());
|
||||
});
|
||||
|
||||
test("MOG2 background subtractor async early release", t=>{
|
||||
testAsyncBackgroundSubtractorEarlyRelease(t, cv.BackgroundSubtractor.createMOG2());
|
||||
});
|
||||
|
||||
test("GMG background subtractor async early release", t=>{
|
||||
testAsyncBackgroundSubtractorEarlyRelease(t, cv.BackgroundSubtractor.createGMG());
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user