# How to perform math operations with OpenCV Matrix and a point-like value in Javascript?

I want to scale a contour in OpenCV.js. I have a valid contour in cnt variable of type cv.Mat (verified it by using drawContours).

I found a function in Python that does everything I need but I have problems converting it to Javascript.

Python version:

``````def scale_contour(cnt, scale):
M = cv2.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])

cnt_norm = cnt - [cx, cy]
cnt_scaled = cnt_norm * scale
cnt_scaled = cnt_scaled + [cx, cy]
cnt_scaled = cnt_scaled.astype(np.int32)

return cnt_scaled
``````

Here’s what I started for Javascript:

``````function scaleContour(cnt, scale) {
console.log("cnt", cnt.data32S, cnt.rows, cnt.cols, cnt.type());

const M = cv.moments(cnt);
const cx = M['m10']/M['m00'];
const cy = M['m01']/M['m00'];
const offset = [Math.ceil(cx), Math.ceil(cy)];
console.log("Offset", offset);

// cannot use convenient Python arithmetics here,
// have to call functions
// although technically we have 1 row 2 cols for a point, but the cnt type is 2-channel CV_32SC2 (12)
// therefore keeping the size 1,1 and leave the second dimension as a channel to be compatible with the contour format
const pointMat = cv.matFromArray(1, 1, cnt.type(), offset);
console.log("pointMat", pointMat.data32S);

const cntNorm = new cv.Mat(cnt.rows, cnt.cols, cnt.type());
cv.subtract(cnt, pointMat, cntNorm); <-- my app crashes here with an exception that has only some random number - OpenCV seems to always do that when I'm doing something wrong or it's out of memory
console.log("ctnorm", cntNorm.data32S);

``````

Unfortunately, I cannot find a good example on Python-like matrix operations in the official OpenCV.js documentation on basic data structures. It just shows how to create matrices but does not explain how to perform simple math operations with a matrix and a point-like value.

Also, I’m not sure when I need `new cv.Mat(cnt.rows, cnt.cols, cnt.type());` and when `new cv.Mat()` is enough. The documentation has both but does not answer what is the rule of thumb to use an empty Mat and when it must be configured with row/col/type.

And the log output for `cnt` cols and rows is confusing, it prints 75 rows and 1 col, but the data is `Int32Array(150)`. I found that sometimes the second layer of values are designated by type and not cols/rows. That’s confusing. How should we know when to use rows=1,cols=2 and when rows=1,cols=2 and a type with 2 channels?

Ok, got something working. A bit ugly, not sure why I could not find a simpler way to multiply matrix with a constant. And also the fact that the point is treated as a 1,1 dimension element with 2 channels to make it match the contour format CV_32SC2 is very unintuitive.

``````function scaleContour(cnt, scale) {
const M = cv.moments(cnt);
const cx = M['m10']/M['m00'];
const cy = M['m01']/M['m00'];
const offset = [Math.ceil(cx), Math.ceil(cy)];

// cannot use convenient Python arithmetics here,
// have to call functions
// although we have 1,2 but the type is 2-channel CV_32SC2 (12)
// therefore keep the size 1,1 and leave the second dimension as channel
const pointMat = cv.matFromArray(1, 1, cnt.type(), offset);
// both matrices have to be the same size, so we repeat our point for every pair
let pointRepeat = new cv.Mat();
cv.repeat(pointMat, cnt.rows, 1, pointRepeat);

let cntNorm = new cv.Mat();
cv.subtract(cnt, pointRepeat, cntNorm);

//console.log("cntNorm", cntNorm.size(), cntNorm.data32S);

// let cntScaled = cntNorm.mulConstant(scale); // mulConstant is not a function - maybe in future version?
// awkward - to multiply with scalar, need mul with (1,1,...) and a factor
// Mat.ones does not work because
// In case of multi-channels type, only the first channel will be initialized with 1's, the others will be set to 0's.
let ones = new cv.Mat(cnt.rows, cnt.cols, cnt.type(), cv.Scalar.all(1));
let cntScaled = cntNorm.mul(ones, scale);

//console.log("cntScaled", cntScaled.size(), cntScaled.data32S);

ones.delete();

// reuse the same
cntNorm.delete();
cntNorm = new cv.Mat();