UrielCh/opencv4nodejs

Bindings for cv.min and cv.max

Closed this issue · 18 comments

Hello,

Is there a possibility to implement cv.min() and cv.max() that compare 2 img-arrays and return an img containing the minimum or maximum values ​​in all pixels, respectively?

We rely heavily on these functions for a specific development. If there is another alternative to using them that would be of great help as well.

Thank you for this wonderful project.

Docs:
https://docs.opencv.org/2.4/modules/core/doc/operations_on_arrays.html#min
https://docs.opencv.org/2.4/modules/core/doc/operations_on_arrays.html#max

Six thumps up in 22 minutes?

That is easy to implement, but I have to find a new job first... and deal with 2 wheelchair kids for 2 more weeks.

9 thumps up after 26 minutes...

you should also start the project 😃

Six thumps up in 22 minutes?

Its my team 😄

That is easy to implement, but I have to find a new job first... and deal with 2 wheelchair kids for 2 more weeks.

No problem, we are very patient and will help you with whatever you need.

LOL

so go shooting star on the project, and I think I can find time to add this simple mapping.

I had just add:

min(src1: Mat, src2: Mat, dst: Mat): Mat;
minAsync(src1: Mat, src2: Mat, dst: Mat): Promise<Mat>;

max(src1: Mat, src2: Mat, dst?: Mat): Mat;
maxAsync(src1: Mat, src2: Mat, dst?: Mat): Promise<Mat>;

can you provide me with a test code to test my mapping ?

for the moment dst is mandatory, I will make it optional later.

that should be good:

import { expect } from 'chai';
import cv from '@u4/opencv4nodejs';

describe('static Min/Max methods added on 2023-03-03', () => {
  const mat1 = new cv.Mat([
    [10, 20, 30],
    [40, 50, 60],
  ], cv.CV_8U);
  const mat2 = new cv.Mat([
    [1, 22, 3],
    [4, 55, 66],
  ], cv.CV_8U);

  it('max', () => {
    const dest = new cv.Mat([
      [0, 0, 0],
      [0, 0, 0],
    ], cv.CV_8U);

    const expected = new cv.Mat([
      [10, 22, 30],
      [40, 55, 66],
    ], cv.CV_8U);

    const dest2 = cv.max(mat1, mat2, dest);
    expect(dest2).to.be.deep.equal(expected);
  });

  it('min', () => {
    const dest = new cv.Mat([
      [0, 0, 0],
      [0, 0, 0],
    ], cv.CV_8U);

    const expected = new cv.Mat([
      [1, 20, 3],
      [4, 50, 60],
    ], cv.CV_8U);

    const dest2 = cv.min(mat1, mat2, dest);
    expect(dest2).to.be.deep.equal(expected);
  });
});
  static Mat methods 2023-03-03
    ✔ max
    ✔ min

is my test correct ?

that should be good:

describe('static Mat methods 2023-03-03', () => {
  it('max', () => {
    const mat1 = new cv.Mat([
      [10, 20, 30],
      [40, 50, 60],
    ], cv.CV_8U);
    const mat2 = new cv.Mat([
      [1, 22, 3],
      [4, 55, 66],
    ], cv.CV_8U);
    const dest = new cv.Mat([
      [0, 0, 0],
      [0, 0, 0],
    ], cv.CV_8U);

    const expected = new cv.Mat([
      [10, 22, 30],
      [40, 55, 66],
    ], cv.CV_8U);

    const dest2 = cv.max(mat1, mat2, dest);
    expect(dest2).to.be.deep.equal(expected);
  });
});

Your example is great.

The code I used had to create a javascript function with a loop and Mat.at() comparisons, which had a huge performance loss.

while (true) {
    tmp = marker.copy();
    marker = marker.dilate(kernel);
    marker = min(thresh, marker);

    difference = marker.sub(tmp);

    if (difference.countNonZero() <= 0) break;
}

I think of the following alternatives what works best for you.

describe('static Mat methods 2023-03-03', () => {
  it('max', () => {
    const mat1 = new cv.Mat([
      [10, 20, 30],
      [40, 50, 60],
    ], cv.CV_8U);
    const mat2 = new cv.Mat([
      [1, 22, 3],
      [4, 55, 66],
    ], cv.CV_8U);
    const dest = new cv.Mat([
      [0, 0, 0],
      [0, 0, 0],
    ], cv.CV_8U);

    const expected = new cv.Mat([
      [10, 22, 30],
      [40, 55, 66],
    ], cv.CV_8U);

    const dest2 = cv.max(mat1, mat2 /* , (dest: cv.Mat || undefined) */);
    expect(dest2).to.be.deep.equal(expected);

    cv.max(mat1, mat2, dest);
    expect(dest).to.be.deep.equal(expected);

    const dest3 = mat1.max(mat2);
    expect(dest3).to.be.deep.equal(expected);
  });
});
  static Mat methods 2023-03-03
    ✔ max
    ✔ min

is my test correct ?

Yes. It is possible in this way as well

const mat = new cv.Mat([
  [15, 222, 101],
  [27, 245, 66],
], cv.CV_8U);

const matMaxByNumber = cv.max(mat, 100);
// matMaxByNumber
[
  [100, 222, 101],
  [100, 245, 100],
]

const matMinByNumber = cv.min(mat, 100);
// matMinByNumber
[
  [15, 100, 100],
  [27, 100, 66],
]

This one will not work yet. but that the next step

I need to move to another project,

for now, I can publish a version with the following interface:

// experimental, need improvements / rewrite
export function min(src1: Mat, src2: Mat, dst: Mat): Mat;
export function minAsync(src1: Mat, src2: Mat, dst: Mat): Promise<Mat>;

export function max(src1: Mat, src2: Mat, dst: Mat): Mat;
export function maxAsync(src1: Mat, src2: Mat, dst: Mat): Promise<Mat>;

Errors are currently thrown as strings, I need to fix that too.

That would be perfect. My knowledge in C++ and Node addons is limited, otherwise I would help you with pull requests to further evolve your project. Sorry for taking up your time.

My C++ knowledge is outdated, I stop C/ C++ in 2004 ... so ... you may perform as well as I 😺

So I publish it as Version 6.5.0

Can you try and bench the 6.5.0?

In my scenario it worked like a charm.

while (true) {
  tmp = marker.copy();
  marker = marker.dilate(kernel);
  marker = cv.min(thresh, marker);

  difference = marker.sub(tmp);

  if (difference.countNonZero() <= 0) break;
}

This is the test case

describe('static Mat methods 2023-03-10', () => {
  it('(max) with optional dest', () => {
    const mat1 = new cv.Mat([
      [10, 20, 30],
      [40, 50, 60],
    ], cv.CV_8U);

    const mat2 = new cv.Mat([
      [1, 22, 3],
      [4, 55, 66],
    ], cv.CV_8U);
  
    const expectedArray = [
      [10, 22, 30],
      [40, 55, 66],
    ];
  
    const arDest2 = cv.max(mat1, mat2).getDataAsArray(); // toArray
    expect(arDest2).to.be.deep.equal(expectedArray);
  });

  it('(max) with dest', () => {
    const mat1 = new cv.Mat([
      [10, 20, 30],
      [40, 50, 60],
    ], cv.CV_8U);

    const mat2 = new cv.Mat([
      [1, 22, 3],
      [4, 55, 66],
    ], cv.CV_8U);

    const dest = new cv.Mat([
      [0, 0, 0],
      [0, 0, 0],
    ], cv.CV_8U);
  
    const expectedArray = [
      [10, 22, 30],
      [40, 55, 66],
    ];
  
    cv.max(mat1, mat2, dest);

    const arDest = dest.getDataAsArray();
    expect(arDest).to.be.deep.equal(expectedArray);
  });

  it('(min) with optional dest', () => {
    const mat1 = new cv.Mat([
      [10, 20, 30],
      [40, 50, 60],
    ], cv.CV_8U);

    const mat2 = new cv.Mat([
      [1, 22, 3],
      [4, 55, 66],
    ], cv.CV_8U);
  
    const expectedArray = [
      [1, 20, 3],
      [4, 50, 60],
    ];
  
    const arDest2 = cv.min(mat1, mat2).getDataAsArray(); // toArray
    expect(arDest2).to.be.deep.equal(expectedArray);
  });

  it('(min) with dest', () => {
    const mat1 = new cv.Mat([
      [10, 20, 30],
      [40, 50, 60],
    ], cv.CV_8U);

    const mat2 = new cv.Mat([
      [1, 22, 3],
      [4, 55, 66],
    ], cv.CV_8U);

    const dest = new cv.Mat([
      [0, 0, 0],
      [0, 0, 0],
    ], cv.CV_8U);
  
    const expectedArray = [
      [1, 20, 3],
      [4, 50, 60],
    ];
  
    cv.min(mat1, mat2, dest);

    const arDest = dest.getDataAsArray();
    expect(arDest).to.be.deep.equal(expectedArray);
  });
});

Output

static Mat methods 2023-03-10
  ✔ (max) with optional dest
  1) (max) with dest
  ✔ (min) with optional dest
  2) (min) with dest


2 passing (13ms)
2 failing

1) static Mat methods 2023-03-10
     (max) with dest:

    AssertionError: expected [ [ +0, +0, +0 ], [ +0, +0, +0 ] ] to deeply equal [ [ 10, 22, 30 ], [ 40, 55, 66 ] ]
    + expected - actual

     [
       [
    -    0
    -    0
    -    0
    +    10
    +    22
    +    30
       ]
       [
    -    0
    -    0
    -    0
    +    40
    +    55
    +    66
       ]
     ]

    at Context.<anonymous> (test.test.js:50:31)
    at processImmediate (node:internal/timers:466:21)

2) static Mat methods 2023-03-10
     (min) with dest:

    AssertionError: expected [ [ +0, +0, +0 ], [ +0, +0, +0 ] ] to deeply equal [ [ 1, 20, 3 ], [ 4, 50, 60 ] ]
    + expected - actual

     [
       [
    -    0
    -    0
    -    0
    +    1
    +    20
    +    3
       ]
       [
    -    0
    -    0
    -    0
    +    4
    +    50
    +    60
       ]
     ]

    at Context.<anonymous> (test.test.js:97:31)
    at processImmediate (node:internal/timers:466:21)

that works ?
marker = cv.min(thresh, marker);

The 3rd dest parameter is currently mandatory.
that should not work.

Use it as you can, for now, open a PR if you want some more change I used to merge them within the week, or the day.

that works ?
marker = cv.min(thresh, marker);

The 3rd dest parameter is currently mandatory.
that should not work.

Use it as you can, for now, open a PR if you want some more change I used to merge them within the week, or the day.

yes it worked and i believe that changes will not be necessary. Thanks @UrielCh

so I close the issue for now