From e39ec08887d9135be7c4e6188eaf7987c0a630b5 Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Sat, 6 Jul 2024 23:07:18 +0200 Subject: [PATCH 01/12] autofixed spaces --- cc/core/Mat.cc | 16 ++++++------ typings/Mat.d.ts | 66 ++++++++++++++++++++++++------------------------ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/cc/core/Mat.cc b/cc/core/Mat.cc index 233c045ea..31f356e6f 100644 --- a/cc/core/Mat.cc +++ b/cc/core/Mat.cc @@ -327,7 +327,7 @@ NAN_MODULE_INIT(Mat::Init) { } // std::cout << "loop line " << cur[0] << "/" << sizes[1] << std::endl; -// std::cout << "loop cell " << cur[0] << "/" << sizes[0] << ", " << cur[1] << "/" << sizes[1] << std::endl; +// std::cout << "loop cell " << cur[0] << "/" << sizes[0] << ", " << cur[1] << "/" << sizes[1] << std::endl; // std::cout << "loop cell " << cur[0] << "/" << sizes[0] << ", " << cur[1] << "/" << sizes[1] << ", " << cur[2] << "/" << sizes[2]<< std::endl; // std::cout << "loop pos " << cur[0] << ", " << cur[1] << ", " << cur[2] << ", " << cur[3] << std::endl; @@ -502,9 +502,9 @@ NAN_METHOD(Mat::New) { else if (info[0]->IsNumber() && info[1]->IsNumber() && info[2]->IsInt32()) { int type = info[2]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(); if (info.Length() == 3 || info[3]->IsArray() || info[3]->IsNumber()) { - + cv::Mat mat(info[0]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(), info[1]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(), type); - + /* fill vector */ // TODO by Vec if (info[3]->IsArray()) { @@ -527,8 +527,8 @@ NAN_METHOD(Mat::New) { if(info[4]->IsNumber()){ int step = info[4]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(); cv::Mat mat( - info[0]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(), - info[1]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(), + info[0]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(), + info[1]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(), type, data, step @@ -536,8 +536,8 @@ NAN_METHOD(Mat::New) { self->setNativeObject(mat); } else { cv::Mat mat( - info[0]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(), - info[1]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(), + info[0]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(), + info[1]->ToInt32(Nan::GetCurrentContext()).ToLocalChecked()->Value(), type, data ); @@ -814,7 +814,7 @@ NAN_METHOD(Mat::GetDataAsArray) { FF::TryCatch tryCatch("Mat::GetDataAsArray"); cv::Mat mat = Mat::unwrapSelf(info); v8::Local rowArray = Nan::New(mat.size[0]); - + switch (mat.dims) { case 2: FF_MAT_APPLY_TYPED_OPERATOR(mat, rowArray, mat.type(), FF_JS_ARRAY_FROM_MAT_2D, FF::matGet); break; case 3: FF_MAT_APPLY_TYPED_OPERATOR(mat, rowArray, mat.type(), FF_JS_ARRAY_FROM_MAT_3D, FF::matGet); break; diff --git a/typings/Mat.d.ts b/typings/Mat.d.ts index bf8920330..d41f09601 100644 --- a/typings/Mat.d.ts +++ b/typings/Mat.d.ts @@ -174,7 +174,7 @@ export class Mat { /** * Create a Mat having the given size. * The constructor build n-Dimmentional Mat - * + * * added in opencv4node 6.2.0 */ constructor(sizes: number[], type: number); @@ -230,11 +230,11 @@ export class Mat { /** * Computes useful camera characteristics from the camera intrinsic matrix. - * + * * Do keep in mind that the unity measure 'mm' stands for whatever unit of measure one chooses for the chessboard pitch (it can thus be any value). - * + * * https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#ga87955f4330d5c20e392b265b7f92f691 - * + * * @param imageSize Input image size in pixels. * @param apertureWidth Physical width in mm of the sensor. * @param apertureHeight Physical height in mm of the sensor. @@ -327,11 +327,11 @@ export class Mat { // alternate signature /** * Draws contours outlines or filled contours. - * + * * The function draws contour outlines in the image if thickness≥0 or fills the area bounded by the contours if thickness<0 . The example below shows how to retrieve connected components from the binary image and label them: : - * + * * https://docs.opencv.org/4.5.4/d6/d6e/group__imgproc__draw.html#ga746c0625f1781f1ffc9056259103edbc - * + * * MatImgprocBindings.h * @param contours list of contours * @param contourIdx 0 based contour index to draw @@ -353,13 +353,13 @@ export class Mat { drawRectangle(pt0: Point2, pt1: Point2, color?: Vec3, thickness?: number, lineType?: number, shift?: number): void; // alternate signature /** - * + * * @param pt0 Vertex of the rectangle. - * @param pt1 Vertex of the rectangle opposite to pt1 . - * @param opt.color Rectangle color or brightness (grayscale image). + * @param pt1 Vertex of the rectangle opposite to pt1 . + * @param opt.color Rectangle color or brightness (grayscale image). * @param opt.thickness Thickness of lines that make up the rectangle. Negative values, like FILLED, mean that the function has to draw a filled rectangle. {@see https://docs.opencv.org/4.x/d6/d6e/group__imgproc__draw.html#ggaf076ef45de481ac96e0ab3dc2c29a777a89c5f6beef080e6df347167f85e07b9e} * @param opt.lineType Type of the line. See LineTypes {@see https://docs.opencv.org/4.x/d6/d6e/group__imgproc__draw.html#gaf076ef45de481ac96e0ab3dc2c29a777} - * @param opt.shift shift Number of fractional bits in the point coordinates. + * @param opt.shift shift Number of fractional bits in the point coordinates. */ drawRectangle(pt0: Point2, pt1: Point2, opt: { color?: Vec3, thickness?: number, lineType?: number, shift?: number }): void; drawRectangle(rect: Rect, color?: Vec3, thickness?: number, lineType?: number, shift?: number): void; @@ -369,7 +369,7 @@ export class Mat { equalizeHist(this: Mat): Mat; equalizeHistAsync(this: Mat): Promise; - + erode(kernel: Mat, anchor?: Point2, iterations?: number, borderType?: number): Mat; erodeAsync(kernel: Mat, anchor?: Point2, iterations?: number, borderType?: number): Promise; exp(): Mat; @@ -427,9 +427,9 @@ export class Mat { /** * if Mat.dims <= 2 - * + * * @see https://github.com/justadudewhohacks/opencv4nodejs/issues/329 - * + * * Note this method offer low performances, use getData instead. */ getDataAsArray(): number[][]; @@ -439,9 +439,9 @@ export class Mat { getDataAsArray(): number[][][]; /** * The function computes and returns the optimal new camera intrinsic matrix based on the free scaling parameter. By varying this parameter, you may retrieve only sensible pixels alpha=0 , keep all the original image pixels if there is valuable information in the corners alpha=1 , or get something in between. When alpha>0 , the undistorted result is likely to have some black pixels corresponding to "virtual" pixels outside of the captured distorted image. The original camera intrinsic matrix, distortion coefficients, the computed new camera intrinsic matrix, and newImageSize should be passed to initUndistortRectifyMap to produce the maps for remap. - * + * * https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#ga7a6c4e032c97f03ba747966e6ad862b1 - * + * * @param distCoeffs Input vector of distortion coefficients (k1,k2,p1,p2[,k3[,k4,k5,k6[,s1,s2,s3,s4[,τx,τy]]]]) of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. * @param imageSize Original image size. * @param alpha Free scaling parameter between 0 (when all the pixels in the undistorted image are valid) and 1 (when all the source image pixels are retained in the undistorted image). See stereoRectify for details. @@ -513,7 +513,7 @@ export class Mat { * @param template Searched template. It must be not greater than the source image and have the same data type. * @param method Parameter specifying the comparison method, can be one of TM_SQDIFF, TM_SQDIFF_NORMED, TM_CCORR, TM_CCORR_NORMED, TM_CCOEFF, TM_CCOEFF_NORMED. * @param mask Optional mask. It must have the same size as templ. It must either have the same number of channels as template or only one channel, which is then used for all template and image channels. If the data type is CV_8U, the mask is interpreted as a binary mask, meaning only elements where mask is nonzero are used and are kept unchanged independent of the actual mask value (weight equals 1). For data tpye CV_32F, the mask values are used as weights. The exact formulas are documented in TemplateMatchModes. - * + * * @return Map of comparison results. It must be single-channel 32-bit floating-point. If image is W×H and templ is w×h , then result is (W−w+1)×(H−h+1) . */ matchTemplate(template: Mat, method: number, mask?: Mat): Mat; @@ -673,9 +673,9 @@ export class Mat { sqrt(): Mat; /** * Computes rectification transforms for each head of a calibrated stereo camera. - * + * * https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#ga617b1685d4059c6040827800e72ad2b6 - * + * * @param distCoeffs1 First camera distortion parameters. * @param cameraMatrix2 Second camera intrinsic matrix. * @param distCoeffs2 Second camera distortion parameters. @@ -755,11 +755,11 @@ export class Mat { warpPerspectiveAsync(transforMationMatrix: Mat, size?: Size, flags?: number, borderMode?: number, borderValue?: Vec3): Promise; /** * Performs a marker-based image segmentation using the watershed algorithm. - * + * * The function implements one of the variants of watershed, non-parametric marker-based segmentation algorithm, described in [173] . - * + * * Before passing the image to the function, you have to roughly outline the desired regions in the image markers with positive (>0) indices. So, every region is represented as one or more connected components with the pixel values 1, 2, 3, and so on. Such markers can be retrieved from a binary mask using findContours and drawContours (see the watershed.cpp demo). The markers are "seeds" of the future image regions. All the other pixels in markers , whose relation to the outlined regions is not known and should be defined by the algorithm, should be set to 0's. In the function output, each pixel in markers is set to a value of the "seed" components or to -1 at boundaries between the regions. - * + * * Note * Any two neighbor connected components are not necessarily separated by a watershed boundary (-1's pixels); for example, they can touch each other in the initial marker image passed to the function. * https://docs.opencv.org/4.6.0/d3/d47/group__imgproc__segmentation.html#ga3267243e4d3f95165d55a618c65ac6e1 @@ -769,9 +769,9 @@ export class Mat { watershedAsync(markers: Mat): Promise; /** * Decrements the reference counter and deallocates the matrix if needed. - * + * * The method decrements the reference counter associated with the matrix data. When the reference counter reaches 0, the matrix data is deallocated and the data and the reference counter pointers are set to NULL's. If the matrix header points to an external data set (see Mat::Mat ), the reference counter is NULL, and the method has no effect in this case. - * + * * This method can be called manually to force the matrix data deallocation. But since this method is automatically called in the destructor, or by any other method that changes the data pointer, it is usually not needed. The reference counter decrement and check for 0 is an atomic operation on the platforms that support it. Thus, it is safe to operate on the same matrices asynchronously in different threads. * https://docs.opencv.org/4.6.0/d3/d63/classcv_1_1Mat.html#ae48d4913285518e2c21a3457017e716e */ @@ -793,28 +793,28 @@ export class Mat { static eye(rows: number, cols: number, type: number): Mat; /** * Returns an array of all 1's of the specified size and type. - * + * * The method returns a Matlab-style 1's array initializer, similarly to Mat::zeros. Note that using this method you can initialize an array with an arbitrary value, using the following Matlab idiom: - * + * * Mat A = Mat::ones(100, 100, CV_8U)*3; // make 100x100 matrix filled with 3. * The above operation does not form a 100x100 matrix of 1's and then multiply it by 3. Instead, it just remembers the scale factor (3 in this case) and use it when actually invoking the matrix initializer. - * + * * Note * In case of multi-channels type, only the first channel will be initialized with 1's, the others will be set to 0's. * https://docs.opencv.org/4.x/d3/d63/classcv_1_1Mat.html#a5e10227b777425407986727e2d26fcdc - * @param rows - * @param cols - * @param type + * @param rows + * @param cols + * @param type */ static ones(rows: number, cols: number, type: number): Mat; /** * Returns a zero array of the specified size and type. - * + * * The method returns a Matlab-style zero array initializer. It can be used to quickly form a constant array as a function parameter, part of a matrix expression, or as a matrix initializer: - * + * * Mat A; * A = Mat::zeros(3, 3, CV_32F); - * + * * In the example above, a new matrix is allocated only if A is not a 3x3 floating-point matrix. Otherwise, the existing matrix A is filled with zeros. * https://docs.opencv.org/4.x/d3/d63/classcv_1_1Mat.html#a56daa006391a670e9cb0cd08e3168c99 * @param rows Number of rows. From a9f8b48e1b039f299542fc7f1d4131af25fcef18 Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Sat, 6 Jul 2024 23:09:22 +0200 Subject: [PATCH 02/12] add bindings --- cc/core/Mat.cc | 128 ++++++++++++++++++++++++++++++++++++++++++++++++- cc/core/Mat.h | 3 ++ 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/cc/core/Mat.cc b/cc/core/Mat.cc index 31f356e6f..db6623b8c 100644 --- a/cc/core/Mat.cc +++ b/cc/core/Mat.cc @@ -144,6 +144,9 @@ NAN_MODULE_INIT(Mat::Init) { Nan::SetPrototypeMethod(ctor, "setData", SetData); Nan::SetPrototypeMethod(ctor, "getRegion", GetRegion); Nan::SetPrototypeMethod(ctor, "row", Row); + Nan::SetPrototypeMethod(ctor, "rowRange", RowRange); + Nan::SetPrototypeMethod(ctor, "col", Col); + Nan::SetPrototypeMethod(ctor, "colRange", ColRange); Nan::SetPrototypeMethod(ctor, "copy", Copy); Nan::SetPrototypeMethod(ctor, "copyAsync", CopyAsync); Nan::SetPrototypeMethod(ctor, "copyTo", CopyTo); @@ -897,7 +900,7 @@ NAN_METHOD(Mat::Row) { try { if (mat.type() == CV_32FC1) { for (int c = 0; c < mat.cols; c++) { - Nan::Set(row, c, Nan::New(mat.at(r, c))); + Nan::Set(row, c, Nan::New(mat.at(r, c))); } } else if (mat.type() == CV_8UC1) { for (int c = 0; c < mat.cols; c++) { @@ -908,7 +911,7 @@ NAN_METHOD(Mat::Row) { cv::Vec3b vec = mat.at(r, c); v8::Local jsVec = Nan::New(3); for (int i = 0; i < 3; i++) { - Nan::Set(jsVec, i, Nan::New(vec[i])); + Nan::Set(jsVec, i, Nan::New(vec[i])); } Nan::Set(row, c, jsVec); } @@ -923,6 +926,127 @@ NAN_METHOD(Mat::Row) { info.GetReturnValue().Set(row); } +NAN_METHOD(Mat::RowRange) { + FF::TryCatch tryCatch("Mat::RowRange"); + if (!info[0]->IsNumber() || !info[1]->IsNumber()) { + return tryCatch.throwError("usage: rowRange(int start, int end)"); + } + int start = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); + int end = (int)info[1]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); + cv::Mat mat = Mat::unwrapSelf(info); + v8::Local rows = Nan::New(end - start); + try { + for (int r = start; r < end; r++) { + v8::Local row = Nan::New(mat.cols); + if (mat.type() == CV_32FC1) { + for (int c = 0; c < mat.cols; c++) { + Nan::Set(row, c, Nan::New(mat.at(r, c))); + } + } else if (mat.type() == CV_8UC1) { + for (int c = 0; c < mat.cols; c++) { + Nan::Set(row, c, Nan::New((uint)mat.at(r, c))); + } + } else if (mat.type() == CV_8UC3) { + for (int c = 0; c < mat.cols; c++) { + cv::Vec3b vec = mat.at(r, c); + v8::Local jsVec = Nan::New(3); + for (int i = 0; i < 3; i++) { + Nan::Set(jsVec, i, Nan::New(vec[i])); + } + Nan::Set(row, c, jsVec); + } + } else { + return tryCatch.throwError("not implemented yet - mat type:" + std::to_string(mat.type())); + } + Nan::Set(rows, r - start, row); + } + } catch(std::exception &e) { + return tryCatch.throwError(e.what()); + } catch(...) { + return tryCatch.throwError("... Exception"); + } + info.GetReturnValue().Set(rows); +} + +NAN_METHOD(Mat::Col) { + FF::TryCatch tryCatch("Mat::Col"); + if (!info[0]->IsNumber()) { + return tryCatch.throwError("usage: col(int c)"); + } + int c = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); + cv::Mat mat = Mat::unwrapSelf(info); + v8::Local col = Nan::New(mat.rows); + try { + if (mat.type() == CV_32FC1) { + for (int r = 0; r < mat.rows; r++) { + Nan::Set(r, col, Nan::New(mat.at(r, c))); + } + } else if (mat.type() == CV_8UC1) { + for (int r = 0; r < mat.rows; r++) { + Nan::Set(r, col, Nan::New((uint)mat.at(r, c))); + } + } else if (mat.type() == CV_8UC3) { + for (int r = 0; r < mat.rows; r++) { + cv::Vec3b vec = mat.at(r, c); + v8::Local jsVec = Nan::New(3); + for (int i = 0; i < 3; i++) { + Nan::Set(jsVec, i, Nan::New(vec[i])); + } + Nan::Set(r, col, jsVec); + } + } else { + return tryCatch.throwError("not implemented yet - mat type:" + std::to_string(mat.type())); + } + } catch(std::exception &e) { + return tryCatch.throwError(e.what()); + } catch(...) { + return tryCatch.throwError("... Exception"); + } + info.GetReturnValue().Set(col); +} + +NAN_METHOD(Mat::ColRange) { + FF::TryCatch tryCatch("Mat::ColRange"); + if (!info[0]->IsNumber() || !info[1]->IsNumber()) { + return tryCatch.throwError("usage: colRange(int start, int end)"); + } + int start = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); + int end = (int)info[1]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); + cv::Mat mat = Mat::unwrapSelf(info); + v8::Local cols = Nan::New(end - start); + try { + for (int c = start; c < end; c++) { + v8::Local col = Nan::New(mat.rows); + if (mat.type() == CV_32FC1) { + for (int r = 0; r < mat.rows; r++) { + Nan::Set(r, col, Nan::New(mat.at(r, c))); + } + } else if (mat.type() == CV_8UC1) { + for (int r = 0; r < mat.rows; r++) { + Nan::Set(r, col, Nan::New((uint)mat.at(r, c))); + } + } else if (mat.type() == CV_8UC3) { + for (int r = 0; r < mat.rows; r++) { + cv::Vec3b vec = mat.at(r, c); + v8::Local jsVec = Nan::New(3); + for (int i = 0; i < 3; i++) { + Nan::Set(jsVec, i, Nan::New(vec[i])); + } + Nan::Set(r, col, jsVec); + } + } else { + return tryCatch.throwError("not implemented yet - mat type:" + std::to_string(mat.type())); + } + Nan::Set(cols, c - start, col); + } + } catch(std::exception &e) { + return tryCatch.throwError(e.what()); + } catch(...) { + return tryCatch.throwError("... Exception"); + } + info.GetReturnValue().Set(cols); +} + NAN_METHOD(Mat::Release) { // must get pointer to the original; else we are just getting a COPY and then releasing that! Mat::unwrapThis(info)->self.release(); diff --git a/cc/core/Mat.h b/cc/core/Mat.h index 82491c6ba..60e5ad286 100644 --- a/cc/core/Mat.h +++ b/cc/core/Mat.h @@ -65,6 +65,9 @@ class Mat : public FF::ObjectWrap { static NAN_METHOD(GetRegion); static NAN_METHOD(Norm); static NAN_METHOD(Row); + static NAN_METHOD(RowRange); + static NAN_METHOD(Col); + static NAN_METHOD(ColRange); static NAN_METHOD(Release); static NAN_METHOD(PushBack); static NAN_METHOD(PushBackAsync); From 4f3d0556af11eb65ae2672dffcdfac7db375ed80 Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Sat, 6 Jul 2024 23:10:23 +0200 Subject: [PATCH 03/12] add typings --- typings/Mat.d.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/typings/Mat.d.ts b/typings/Mat.d.ts index d41f09601..51461573d 100644 --- a/typings/Mat.d.ts +++ b/typings/Mat.d.ts @@ -244,6 +244,9 @@ export class Mat { canny(threshold1: number, threshold2: number, apertureSize?: number, L2gradient?: boolean): Mat; cannyAsync(threshold1: number, threshold2: number, apertureSize?: number, L2gradient?: boolean): Promise; + col(c: number): Mat; + colRange(startCol: number, endCol: number): Mat; + compareHist(H2: Mat, method: number): number; compareHistAsync(H2: Mat, method: number): Promise; @@ -616,6 +619,10 @@ export class Mat { rodriguesAsync(): Promise<{ dst: Mat, jacobian: Mat }>; rotate(rotateCode: number): Mat; rotateAsync(rotateCode: number): Promise; + + row(r: number): Mat; + rowRange(startRow: number, endRow: number): Mat; + rqDecomp3x3(): RqDecomp3x3Ret; rqDecomp3x3Async(): Promise; scharr(ddepth: number, dx: number, dy: number, scale?: number, delta?: number, borderType?: number): Mat; From 2e42efcc7622c82f90009026be1e15214582775f Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Sat, 6 Jul 2024 23:18:48 +0200 Subject: [PATCH 04/12] add tests --- test/tests/core/Mat/Mat.test.ts | 96 +++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/test/tests/core/Mat/Mat.test.ts b/test/tests/core/Mat/Mat.test.ts index 8f8bb8720..a77d3baff 100644 --- a/test/tests/core/Mat/Mat.test.ts +++ b/test/tests/core/Mat/Mat.test.ts @@ -571,4 +571,100 @@ if (toTest.core) { ); }); }); + + describe('row', () => { + const getDut = () => new cv.Mat([ + [1, 2, 3], + [4, 5, 6], + ], cv.CV_8U); + + const expectOutput = (res: Mat) => { + expect(res).to.be.instanceOf(cv.Mat); + assertMetaData(res)(1, 3, cv.CV_8U); + assertDataDeepEquals([[4, 5, 6]], res.getDataAsArray()); + }; + + generateAPITests({ + getDut, + methodName: 'row', + methodNameSpace: 'Mat', + getRequiredArgs: () => [1], + expectOutput, + }); + }) + + describe('rowRange', () => { + const getDut = () => new cv.Mat([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], cv.CV_8U); + + const expectOutput = (res: Mat) => { + expect(res).to.be.instanceOf(cv.Mat); + assertMetaData(res)(2, 3, cv.CV_8U); + assertDataDeepEquals([ + [4, 5, 6], + [7, 8, 9], + ], res.getDataAsArray()); + }; + + generateAPITests({ + getDut, + methodName: 'rowRange', + methodNameSpace: 'Mat', + getRequiredArgs: () => [1, 3], + expectOutput, + }); + }); + + describe('col', () => { + const getDut = () => new cv.Mat([ + [1, 2, 3], + [4, 5, 6], + ], cv.CV_8U); + + const expectOutput = (res: Mat) => { + expect(res).to.be.instanceOf(cv.Mat); + assertMetaData(res)(2, 1, cv.CV_8U); + assertDataDeepEquals([ + [2], + [5], + ], res.getDataAsArray()); + }; + + generateAPITests({ + getDut, + methodName: 'col', + methodNameSpace: 'Mat', + getRequiredArgs: () => [1], + expectOutput, + }); + }); + + describe('colRange', () => { + const getDut = () => new cv.Mat([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], cv.CV_8U); + + const expectOutput = (res: Mat) => { + expect(res).to.be.instanceOf(cv.Mat); + assertMetaData(res)(3, 2, cv.CV_8U); + assertDataDeepEquals([ + [2, 3], + [5, 6], + [8, 9], + ], res.getDataAsArray()); + }; + + generateAPITests({ + getDut, + methodName: 'colRange', + methodNameSpace: 'Mat', + getRequiredArgs: () => [1, 3], + expectOutput, + }); + }); } From 2c81dad82062c4a59ba1ad7c7c0bd5981ea1a0f2 Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Sat, 6 Jul 2024 23:51:59 +0200 Subject: [PATCH 05/12] fix column methods --- cc/core/Mat.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cc/core/Mat.cc b/cc/core/Mat.cc index db6623b8c..5ab334f22 100644 --- a/cc/core/Mat.cc +++ b/cc/core/Mat.cc @@ -979,11 +979,11 @@ NAN_METHOD(Mat::Col) { try { if (mat.type() == CV_32FC1) { for (int r = 0; r < mat.rows; r++) { - Nan::Set(r, col, Nan::New(mat.at(r, c))); + Nan::Set(col, r, Nan::New(mat.at(r, c))); } } else if (mat.type() == CV_8UC1) { for (int r = 0; r < mat.rows; r++) { - Nan::Set(r, col, Nan::New((uint)mat.at(r, c))); + Nan::Set(col, r, Nan::New((uint)mat.at(r, c))); } } else if (mat.type() == CV_8UC3) { for (int r = 0; r < mat.rows; r++) { @@ -992,7 +992,7 @@ NAN_METHOD(Mat::Col) { for (int i = 0; i < 3; i++) { Nan::Set(jsVec, i, Nan::New(vec[i])); } - Nan::Set(r, col, jsVec); + Nan::Set(col, r, jsVec); } } else { return tryCatch.throwError("not implemented yet - mat type:" + std::to_string(mat.type())); @@ -1019,11 +1019,11 @@ NAN_METHOD(Mat::ColRange) { v8::Local col = Nan::New(mat.rows); if (mat.type() == CV_32FC1) { for (int r = 0; r < mat.rows; r++) { - Nan::Set(r, col, Nan::New(mat.at(r, c))); + Nan::Set(col, r, Nan::New(mat.at(r, c))); } } else if (mat.type() == CV_8UC1) { for (int r = 0; r < mat.rows; r++) { - Nan::Set(r, col, Nan::New((uint)mat.at(r, c))); + Nan::Set(col, r, Nan::New((uint)mat.at(r, c))); } } else if (mat.type() == CV_8UC3) { for (int r = 0; r < mat.rows; r++) { @@ -1032,7 +1032,7 @@ NAN_METHOD(Mat::ColRange) { for (int i = 0; i < 3; i++) { Nan::Set(jsVec, i, Nan::New(vec[i])); } - Nan::Set(r, col, jsVec); + Nan::Set(col, r, jsVec); } } else { return tryCatch.throwError("not implemented yet - mat type:" + std::to_string(mat.type())); From 9e5e466ae693e5d9a9cad7720cc8b9c2d48d6e0e Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Sun, 7 Jul 2024 01:17:29 +0200 Subject: [PATCH 06/12] Change error messages in Mat.cc --- cc/core/Mat.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cc/core/Mat.cc b/cc/core/Mat.cc index 5ab334f22..2b13fd4d4 100644 --- a/cc/core/Mat.cc +++ b/cc/core/Mat.cc @@ -892,7 +892,7 @@ NAN_METHOD(Mat::Norm) { NAN_METHOD(Mat::Row) { FF::TryCatch tryCatch("Mat::Row"); if (!info[0]->IsNumber()) { - return tryCatch.throwError("usage: row(int r)"); + return tryCatch.throwError("Mat::Row - Error: Expected argument 0 to be a number"); } int r = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); cv::Mat mat = Mat::unwrapSelf(info); @@ -929,7 +929,7 @@ NAN_METHOD(Mat::Row) { NAN_METHOD(Mat::RowRange) { FF::TryCatch tryCatch("Mat::RowRange"); if (!info[0]->IsNumber() || !info[1]->IsNumber()) { - return tryCatch.throwError("usage: rowRange(int start, int end)"); + return tryCatch.throwError("Mat::RowRange - Error: Expected argument 0 and 1 to be numbers"); } int start = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); int end = (int)info[1]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); @@ -971,7 +971,7 @@ NAN_METHOD(Mat::RowRange) { NAN_METHOD(Mat::Col) { FF::TryCatch tryCatch("Mat::Col"); if (!info[0]->IsNumber()) { - return tryCatch.throwError("usage: col(int c)"); + return tryCatch.throwError("Mat::Col - Error: Expected argument 0 to be a number"); } int c = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); cv::Mat mat = Mat::unwrapSelf(info); @@ -1008,7 +1008,7 @@ NAN_METHOD(Mat::Col) { NAN_METHOD(Mat::ColRange) { FF::TryCatch tryCatch("Mat::ColRange"); if (!info[0]->IsNumber() || !info[1]->IsNumber()) { - return tryCatch.throwError("usage: colRange(int start, int end)"); + return tryCatch.throwError("Mat::ColRange - Error: Expected argument 0 and 1 to be numbers"); } int start = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); int end = (int)info[1]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); From 36b60f5d741778a02de438c8ef1eef204514fccc Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Sun, 7 Jul 2024 01:24:18 +0200 Subject: [PATCH 07/12] change case for expected --- cc/core/Mat.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cc/core/Mat.cc b/cc/core/Mat.cc index 2b13fd4d4..e86909248 100644 --- a/cc/core/Mat.cc +++ b/cc/core/Mat.cc @@ -892,7 +892,7 @@ NAN_METHOD(Mat::Norm) { NAN_METHOD(Mat::Row) { FF::TryCatch tryCatch("Mat::Row"); if (!info[0]->IsNumber()) { - return tryCatch.throwError("Mat::Row - Error: Expected argument 0 to be a number"); + return tryCatch.throwError("Mat::Row - Error: expected argument 0 to be a number"); } int r = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); cv::Mat mat = Mat::unwrapSelf(info); @@ -929,7 +929,7 @@ NAN_METHOD(Mat::Row) { NAN_METHOD(Mat::RowRange) { FF::TryCatch tryCatch("Mat::RowRange"); if (!info[0]->IsNumber() || !info[1]->IsNumber()) { - return tryCatch.throwError("Mat::RowRange - Error: Expected argument 0 and 1 to be numbers"); + return tryCatch.throwError("Mat::RowRange - Error: expected argument 0 and 1 to be numbers"); } int start = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); int end = (int)info[1]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); @@ -971,7 +971,7 @@ NAN_METHOD(Mat::RowRange) { NAN_METHOD(Mat::Col) { FF::TryCatch tryCatch("Mat::Col"); if (!info[0]->IsNumber()) { - return tryCatch.throwError("Mat::Col - Error: Expected argument 0 to be a number"); + return tryCatch.throwError("Mat::Col - Error: expected argument 0 to be a number"); } int c = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); cv::Mat mat = Mat::unwrapSelf(info); @@ -1008,7 +1008,7 @@ NAN_METHOD(Mat::Col) { NAN_METHOD(Mat::ColRange) { FF::TryCatch tryCatch("Mat::ColRange"); if (!info[0]->IsNumber() || !info[1]->IsNumber()) { - return tryCatch.throwError("Mat::ColRange - Error: Expected argument 0 and 1 to be numbers"); + return tryCatch.throwError("Mat::ColRange - Error: expected argument 0 and 1 to be numbers"); } int start = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); int end = (int)info[1]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); From 1e2a6f1c23d52390d6f21bc4450d7131bd4d8a4e Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Sun, 7 Jul 2024 01:44:00 +0200 Subject: [PATCH 08/12] Update Mat.cc --- cc/core/Mat.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cc/core/Mat.cc b/cc/core/Mat.cc index e86909248..9bb871fc5 100644 --- a/cc/core/Mat.cc +++ b/cc/core/Mat.cc @@ -892,7 +892,7 @@ NAN_METHOD(Mat::Norm) { NAN_METHOD(Mat::Row) { FF::TryCatch tryCatch("Mat::Row"); if (!info[0]->IsNumber()) { - return tryCatch.throwError("Mat::Row - Error: expected argument 0 to be a number"); + return tryCatch.throwError("expected argument 0 to be a number"); } int r = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); cv::Mat mat = Mat::unwrapSelf(info); @@ -929,7 +929,7 @@ NAN_METHOD(Mat::Row) { NAN_METHOD(Mat::RowRange) { FF::TryCatch tryCatch("Mat::RowRange"); if (!info[0]->IsNumber() || !info[1]->IsNumber()) { - return tryCatch.throwError("Mat::RowRange - Error: expected argument 0 and 1 to be numbers"); + return tryCatch.throwError("expected argument 0 and 1 to be numbers"); } int start = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); int end = (int)info[1]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); @@ -971,7 +971,7 @@ NAN_METHOD(Mat::RowRange) { NAN_METHOD(Mat::Col) { FF::TryCatch tryCatch("Mat::Col"); if (!info[0]->IsNumber()) { - return tryCatch.throwError("Mat::Col - Error: expected argument 0 to be a number"); + return tryCatch.throwError("expected argument 0 to be a number"); } int c = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); cv::Mat mat = Mat::unwrapSelf(info); @@ -1008,7 +1008,7 @@ NAN_METHOD(Mat::Col) { NAN_METHOD(Mat::ColRange) { FF::TryCatch tryCatch("Mat::ColRange"); if (!info[0]->IsNumber() || !info[1]->IsNumber()) { - return tryCatch.throwError("Mat::ColRange - Error: expected argument 0 and 1 to be numbers"); + return tryCatch.throwError("expected argument 0 and 1 to be numbers"); } int start = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); int end = (int)info[1]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); From 70b5a371de9467fae3d785184ea221a27ac3e86d Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Mon, 8 Jul 2024 22:39:43 +0200 Subject: [PATCH 09/12] rewrite methods to work as they should by the docs --- cc/core/Mat.cc | 174 +++++++++---------------------------------------- 1 file changed, 31 insertions(+), 143 deletions(-) diff --git a/cc/core/Mat.cc b/cc/core/Mat.cc index 9bb871fc5..9d6ced05d 100644 --- a/cc/core/Mat.cc +++ b/cc/core/Mat.cc @@ -889,162 +889,50 @@ NAN_METHOD(Mat::Norm) { info.GetReturnValue().Set(norm); } +// The method makes a new header for the specified matrix row and returns it. This is an O(1) +// operation, regardless of the matrix size. The underlying data of the new matrix is shared with the +// original matrix. NAN_METHOD(Mat::Row) { - FF::TryCatch tryCatch("Mat::Row"); - if (!info[0]->IsNumber()) { - return tryCatch.throwError("expected argument 0 to be a number"); + FF::TryCatch tryCatch("Mat::Row"); + int row; + if (FF::IntConverter::arg(0, &row, info)) { + return tryCatch.reThrow(); } - int r = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); - cv::Mat mat = Mat::unwrapSelf(info); - v8::Local row = Nan::New(mat.cols); - try { - if (mat.type() == CV_32FC1) { - for (int c = 0; c < mat.cols; c++) { - Nan::Set(row, c, Nan::New(mat.at(r, c))); - } - } else if (mat.type() == CV_8UC1) { - for (int c = 0; c < mat.cols; c++) { - Nan::Set(row, c, Nan::New((uint)mat.at(r, c))); - } - } else if (mat.type() == CV_8UC3) { - for (int c = 0; c < mat.cols; c++) { - cv::Vec3b vec = mat.at(r, c); - v8::Local jsVec = Nan::New(3); - for (int i = 0; i < 3; i++) { - Nan::Set(jsVec, i, Nan::New(vec[i])); - } - Nan::Set(row, c, jsVec); - } - } else { - return tryCatch.throwError("not implemented yet - mat type:" + std::to_string(mat.type())); - } - } catch(std::exception &e) { - return tryCatch.throwError(e.what()); - } catch(...) { - return tryCatch.throwError("... Exception"); - } - info.GetReturnValue().Set(row); + info.GetReturnValue().Set(Mat::Converter::wrap(Mat::unwrapSelf(info).row(row))); } -NAN_METHOD(Mat::RowRange) { - FF::TryCatch tryCatch("Mat::RowRange"); - if (!info[0]->IsNumber() || !info[1]->IsNumber()) { - return tryCatch.throwError("expected argument 0 and 1 to be numbers"); - } - int start = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); - int end = (int)info[1]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); - cv::Mat mat = Mat::unwrapSelf(info); - v8::Local rows = Nan::New(end - start); - try { - for (int r = start; r < end; r++) { - v8::Local row = Nan::New(mat.cols); - if (mat.type() == CV_32FC1) { - for (int c = 0; c < mat.cols; c++) { - Nan::Set(row, c, Nan::New(mat.at(r, c))); - } - } else if (mat.type() == CV_8UC1) { - for (int c = 0; c < mat.cols; c++) { - Nan::Set(row, c, Nan::New((uint)mat.at(r, c))); - } - } else if (mat.type() == CV_8UC3) { - for (int c = 0; c < mat.cols; c++) { - cv::Vec3b vec = mat.at(r, c); - v8::Local jsVec = Nan::New(3); - for (int i = 0; i < 3; i++) { - Nan::Set(jsVec, i, Nan::New(vec[i])); - } - Nan::Set(row, c, jsVec); - } - } else { - return tryCatch.throwError("not implemented yet - mat type:" + std::to_string(mat.type())); - } - Nan::Set(rows, r - start, row); - } - } catch(std::exception &e) { - return tryCatch.throwError(e.what()); - } catch(...) { - return tryCatch.throwError("... Exception"); +// The method makes a new header for the specified matrix column and returns it. This is an O(1) +// operation, regardless of the matrix size. The underlying data of the new matrix is shared with the +// original matrix. See also the Mat::row description. +NAN_METHOD(Mat::Col) { + FF::TryCatch tryCatch("Mat::Col"); + int col; + if (FF::IntConverter::arg(0, &col, info)) { + return tryCatch.reThrow(); } - info.GetReturnValue().Set(rows); + info.GetReturnValue().Set(Mat::Converter::wrap(Mat::unwrapSelf(info).col(col))); } -NAN_METHOD(Mat::Col) { - FF::TryCatch tryCatch("Mat::Col"); - if (!info[0]->IsNumber()) { - return tryCatch.throwError("expected argument 0 to be a number"); - } - int c = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); - cv::Mat mat = Mat::unwrapSelf(info); - v8::Local col = Nan::New(mat.rows); - try { - if (mat.type() == CV_32FC1) { - for (int r = 0; r < mat.rows; r++) { - Nan::Set(col, r, Nan::New(mat.at(r, c))); - } - } else if (mat.type() == CV_8UC1) { - for (int r = 0; r < mat.rows; r++) { - Nan::Set(col, r, Nan::New((uint)mat.at(r, c))); - } - } else if (mat.type() == CV_8UC3) { - for (int r = 0; r < mat.rows; r++) { - cv::Vec3b vec = mat.at(r, c); - v8::Local jsVec = Nan::New(3); - for (int i = 0; i < 3; i++) { - Nan::Set(jsVec, i, Nan::New(vec[i])); - } - Nan::Set(col, r, jsVec); - } - } else { - return tryCatch.throwError("not implemented yet - mat type:" + std::to_string(mat.type())); - } - } catch(std::exception &e) { - return tryCatch.throwError(e.what()); - } catch(...) { - return tryCatch.throwError("... Exception"); +// The method makes a new header for the specified row span of the matrix. Similarly to Mat::row and +// Mat::col , this is an O(1) operation. +NAN_METHOD(Mat::RowRange) { + FF::TryCatch tryCatch("Mat::RowRange"); + int start, end; + if (FF::IntConverter::arg(0, &start, info) || FF::IntConverter::arg(1, &end, info)) { + return tryCatch.reThrow(); } - info.GetReturnValue().Set(col); + info.GetReturnValue().Set(Mat::Converter::wrap(Mat::unwrapSelf(info).rowRange(start, end))); } +// The method makes a new header for the specified column span of the matrix. Similarly to Mat::row and +// Mat::col , this is an O(1) operation. NAN_METHOD(Mat::ColRange) { FF::TryCatch tryCatch("Mat::ColRange"); - if (!info[0]->IsNumber() || !info[1]->IsNumber()) { - return tryCatch.throwError("expected argument 0 and 1 to be numbers"); - } - int start = (int)info[0]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); - int end = (int)info[1]->ToNumber(Nan::GetCurrentContext()).ToLocalChecked()->Value(); - cv::Mat mat = Mat::unwrapSelf(info); - v8::Local cols = Nan::New(end - start); - try { - for (int c = start; c < end; c++) { - v8::Local col = Nan::New(mat.rows); - if (mat.type() == CV_32FC1) { - for (int r = 0; r < mat.rows; r++) { - Nan::Set(col, r, Nan::New(mat.at(r, c))); - } - } else if (mat.type() == CV_8UC1) { - for (int r = 0; r < mat.rows; r++) { - Nan::Set(col, r, Nan::New((uint)mat.at(r, c))); - } - } else if (mat.type() == CV_8UC3) { - for (int r = 0; r < mat.rows; r++) { - cv::Vec3b vec = mat.at(r, c); - v8::Local jsVec = Nan::New(3); - for (int i = 0; i < 3; i++) { - Nan::Set(jsVec, i, Nan::New(vec[i])); - } - Nan::Set(col, r, jsVec); - } - } else { - return tryCatch.throwError("not implemented yet - mat type:" + std::to_string(mat.type())); - } - Nan::Set(cols, c - start, col); - } - } catch(std::exception &e) { - return tryCatch.throwError(e.what()); - } catch(...) { - return tryCatch.throwError("... Exception"); + int start, end; + if (FF::IntConverter::arg(0, &start, info) || FF::IntConverter::arg(1, &end, info)) { + return tryCatch.reThrow(); } - info.GetReturnValue().Set(cols); + info.GetReturnValue().Set(Mat::Converter::wrap(Mat::unwrapSelf(info).colRange(start, end))); } NAN_METHOD(Mat::Release) { From 35a16f60d3d9c4852e8aa0b2294041e9b7b7d73a Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Mon, 8 Jul 2024 22:40:53 +0200 Subject: [PATCH 10/12] remove tests from Mat.test --- test/tests/core/Mat/Mat.test.ts | 96 --------------------------------- 1 file changed, 96 deletions(-) diff --git a/test/tests/core/Mat/Mat.test.ts b/test/tests/core/Mat/Mat.test.ts index a77d3baff..8f8bb8720 100644 --- a/test/tests/core/Mat/Mat.test.ts +++ b/test/tests/core/Mat/Mat.test.ts @@ -571,100 +571,4 @@ if (toTest.core) { ); }); }); - - describe('row', () => { - const getDut = () => new cv.Mat([ - [1, 2, 3], - [4, 5, 6], - ], cv.CV_8U); - - const expectOutput = (res: Mat) => { - expect(res).to.be.instanceOf(cv.Mat); - assertMetaData(res)(1, 3, cv.CV_8U); - assertDataDeepEquals([[4, 5, 6]], res.getDataAsArray()); - }; - - generateAPITests({ - getDut, - methodName: 'row', - methodNameSpace: 'Mat', - getRequiredArgs: () => [1], - expectOutput, - }); - }) - - describe('rowRange', () => { - const getDut = () => new cv.Mat([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ], cv.CV_8U); - - const expectOutput = (res: Mat) => { - expect(res).to.be.instanceOf(cv.Mat); - assertMetaData(res)(2, 3, cv.CV_8U); - assertDataDeepEquals([ - [4, 5, 6], - [7, 8, 9], - ], res.getDataAsArray()); - }; - - generateAPITests({ - getDut, - methodName: 'rowRange', - methodNameSpace: 'Mat', - getRequiredArgs: () => [1, 3], - expectOutput, - }); - }); - - describe('col', () => { - const getDut = () => new cv.Mat([ - [1, 2, 3], - [4, 5, 6], - ], cv.CV_8U); - - const expectOutput = (res: Mat) => { - expect(res).to.be.instanceOf(cv.Mat); - assertMetaData(res)(2, 1, cv.CV_8U); - assertDataDeepEquals([ - [2], - [5], - ], res.getDataAsArray()); - }; - - generateAPITests({ - getDut, - methodName: 'col', - methodNameSpace: 'Mat', - getRequiredArgs: () => [1], - expectOutput, - }); - }); - - describe('colRange', () => { - const getDut = () => new cv.Mat([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ], cv.CV_8U); - - const expectOutput = (res: Mat) => { - expect(res).to.be.instanceOf(cv.Mat); - assertMetaData(res)(3, 2, cv.CV_8U); - assertDataDeepEquals([ - [2, 3], - [5, 6], - [8, 9], - ], res.getDataAsArray()); - }; - - generateAPITests({ - getDut, - methodName: 'colRange', - methodNameSpace: 'Mat', - getRequiredArgs: () => [1, 3], - expectOutput, - }); - }); } From ab5cffe49c02d69b105630fe075a1b479ba9a536 Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Mon, 8 Jul 2024 22:41:34 +0200 Subject: [PATCH 11/12] Rewrite tests in accessor.test.ts --- test/tests/core/Mat/accessor.test.ts | 65 ++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/tests/core/Mat/accessor.test.ts b/test/tests/core/Mat/accessor.test.ts index ff769680c..f62137fa5 100644 --- a/test/tests/core/Mat/accessor.test.ts +++ b/test/tests/core/Mat/accessor.test.ts @@ -88,6 +88,71 @@ if (toTest.core) { generateIts('should return correct values at each pixel position', createAndAssertAtReturnsCorrectValues); }); + describe("row", () => { + it("should return a new Mat with the correct row", () => { + const type = cv.CV_8U; + const mat = new cv.Mat( + [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + type + ); + const row = mat.row(1); + assertDataDeepEquals([[4, 5, 6]], row.getDataAsArray()); + }); + }); + + describe("col", () => { + it("should return a new Mat with the correct col", () => { + const type = cv.CV_8U; + const mat = new cv.Mat( + [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + type + ); + const col = mat.col(1); + assertDataDeepEquals([[2], [5], [8]], col.getDataAsArray()); + }); + }); + + describe("rowRange", () => { + it("should return a new Mat with the correct row range", () => { + const type = cv.CV_8U; + const mat = new cv.Mat( + [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + [10, 11, 12], + ], + type + ); + const rowRange = mat.rowRange(1, 3); + assertDataDeepEquals([[4, 5, 6], [7, 8, 9]], rowRange.getDataAsArray()); + }); + }); + + describe("colRange", () => { + it("should return a new Mat with the correct col range", () => { + const type = cv.CV_8U; + const mat = new cv.Mat( + [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + ], + type + ); + const colRange = mat.colRange(1, 3); + assertDataDeepEquals([[2, 3], [6, 7], [10, 11]], colRange.getDataAsArray()); + }); + }); + describe.skip('atRaw', () => { it('atRaw', () => { expect(true).to.be.false; From bc087f0bb853744bed52b74b4bbe0d321b523814 Mon Sep 17 00:00:00 2001 From: Adam Toth Date: Mon, 8 Jul 2024 22:50:56 +0200 Subject: [PATCH 12/12] add jsdoc to the typings --- typings/Mat.d.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/typings/Mat.d.ts b/typings/Mat.d.ts index 51461573d..d8af54575 100644 --- a/typings/Mat.d.ts +++ b/typings/Mat.d.ts @@ -244,7 +244,21 @@ export class Mat { canny(threshold1: number, threshold2: number, apertureSize?: number, L2gradient?: boolean): Mat; cannyAsync(threshold1: number, threshold2: number, apertureSize?: number, L2gradient?: boolean): Promise; + /** + * The method makes a new header for the specified matrix column and returns it. This is an O(1) + * operation, regardless of the matrix size. The underlying data of the new matrix is shared with the + * original matrix. See also the Mat::row description. + * @param c the zero-based index of the column to extract. + */ col(c: number): Mat; + /** + * The method makes a new header for the specified column span of the matrix. Similarly to Mat::row and + * Mat::col , this is an O(1) operation. + * + * Pay attention to the fact that the endCol argument is `not zero-based`. + * @param startRow the zero-based start index of the col span to extract + * @param endRow the 1-based ending index of the col span to extract + */ colRange(startCol: number, endCol: number): Mat; compareHist(H2: Mat, method: number): number; @@ -620,7 +634,21 @@ export class Mat { rotate(rotateCode: number): Mat; rotateAsync(rotateCode: number): Promise; + /** + * The method makes a new header for the specified matrix row and returns it. This is an O(1) + * operation, regardless of the matrix size. The underlying data of the new matrix is shared with the + * original matrix. + * @param r the 0-based index of the row to extract + */ row(r: number): Mat; + /** + * The method makes a new header for the specified row span of the matrix. Similarly to Mat::row and + * Mat::col , this is an O(1) operation. + * + * Pay attention to the fact that the endRow argument is `not zero-based`. + * @param startRow the zero-based start index of the row span to extract + * @param endRow the 1-based ending index of the row span to extract + */ rowRange(startRow: number, endRow: number): Mat; rqDecomp3x3(): RqDecomp3x3Ret;