B4A Library OpenCV 3.x

cesarcm

Member
Licensed User
JordiCP,

Probably my last question (I hope so) ...

I have to migrate these lines as well:

Mat X = Mat::zeros(13,6,CV_32FC1);
Mat mat43= Mat::eye(4,3,CV_32FC1); //this is a submatrix at position (4,4)

Mat aux = X.colRange(4,7).rowRange(4,8); // you are pointing to submatrix 4x3 at X(4,4)
mat43.copyTo(aux);


Any tip helps a lot ;)

Thanks
Regards,
Cear
 

JordiCP

Well-Known Member
Licensed User
Mat X = Mat::zeros(13,6,CV_32FC1);
Mat mat43= Mat::eye(4,3,CV_32FC1); //this is a submatrix at position (4,4)

Mat aux = X.colRange(4,7).rowRange(4,8); // you are pointing to submatrix 4x3 at X(4,4)
mat43.copyTo(aux);
Untested, but should be something similar to this :)
B4X:
    Dim mType As OCVCvType

    Dim X as OCVMat 
    X = X.zeros(13,6,mType.CV_32FC1)
    Dim mat43 As OCVMat = X.submat(4,8,4,7) 
    Dim aux As OCVMat
    aux = aux.eye(4,3, mType.CV_32FC1)
    mat43.copyTo(aux)


I'd recommend to add a code module to your project with some static helper methods. These become very useful to make the final code more readable
B4X:
Sub CreateScalar(X As Double) As OCVScalar
    Dim sc As OCVScalar
    sc.Initialize(X)
    Return sc
End Sub

Sub CreateScalar2(X As Double, Y As Double) As OCVScalar
    Dim sc As OCVScalar
    sc.Initialize2(X, Y)
    Return sc    
End Sub

Sub CreateScalar3(X As Double, Y As Double, Z As Double) As OCVScalar
    Dim sc As OCVScalar
    sc.Initialize3(X, Y, Z)
    Return sc    
End Sub

Sub CreateSize(W As Double, H As Double) As OCVSize
    Dim sz As OCVSize
    sz.Initialize2(Array As Double(W,H))
    Return sz
End Sub

Sub CreateMat(rows As Int, cols As Int, cType As Int) As OCVMat
    Dim m As OCVMat
    m.Initialize2(rows, cols, cType)
    Return m
End Sub

Sub CreateEyeMat(rows As Int, cols As Int, cType As Int) As OCVMat
    Dim m As OCVMat 
    m = m.eye(rows, cols, cType)
    Return m
End Sub

Sub CreateZeroMat(rows As Int, cols As Int, cType As Int) As OCVMat
    Dim m As OCVMat 
    m = m.zeros(rows, cols, cType)
    Return m
End Sub
 

cesarcm

Member
Licensed User
JordiCP,

Perfect!

Please, one more tip ...

// from Javascript
let means_c3 = cv.matFromArray(1, 1, cv.CV_32FC3, [mean.data64F[0], mean.data64F[1], mean.data64F[2]]);

PS: I guess that I have to use OCVMatOfDouble .. Am I right?

Thanks
Regards,
Cesar
 

JordiCP

Well-Known Member
Licensed User
Yes, but I guess that you can also work with OCVMat.
(Untested)
B4X:
Dim mm As OCVMatOfDouble
mm.Initialize3(Array As Double(  firstElement, secondElement, ...    ))

'or

Dim mm As OCVMat
mm.initialize2(1,1, mType.CV_32FC3)
mm.put(0,0, Array as Double( firsElement, secondElement, tihrdElement))
 

cesarcm

Member
Licensed User
YOU ROCK!

But how can I get mean.data64F? or is it not necessary?

let mean = new cv.Mat();
let stdDev = new cv.Mat();
let t1 = new cv.Mat();
cv.meanStdDev(signal, mean, stdDev, t1);

let means_c3 = cv.matFromArray(1, 1, cv.CV_32FC3, [mean.data64F[0], mean.data64F[1], mean.data64F[2]]);

Thanks for all.
Regards,
Cesar
 

JordiCP

Well-Known Member
Licensed User
It's a bit difficult to follow without seeing the whole code.

If I understood correctly

B4X:
Dim mean, stdDev, t1 as OCVMat
Dim mCore as OCVCore
mCore.meanStdDev( signal, mean, stdDev, t1)  

Dim meanVals() as Double = means.get5(0,0)     '<-- each 'getX' suffix corresponds to a different data type and must match the OCV Type

Dim means_c3 as OCVMat    '<-- now the code needs a Mat of floats. There is a "convertTo' method that casts element, but we can extract them and build a new OCVMat. Need to test it,
means_c3.initialize2(1,1, mType.CV_32FC3)
means_c3.put1(0,0, Array as float( meanVals(0), meanVals(1), meanVals(2) ))
 

cesarcm

Member
Licensed User
JordiCP,

Thanks 🙏

Probably my last question (I hope so)..

Any idea to convert these lines? (in blue color)

For (var i = 1; i < signal.rows; i++) {
' If (lrescan == True) {
' let adjV = new cv.MatVector();

' let adjR = cv.matFromArray(signal.rows, 1, cv.CV_32FC1,
'
new Array(signal.rows).fill(0).fill(diff.data32F[(i-1)*3], i, signal.rows));

' let adjG = cv.matFromArray(signal.rows, 1, cv.CV_32FC1,
' new Array(signal.rows).fill(0).fill(diff.data32F[(i-1)*3+1], i, signal.rows));

' let adjB = cv.matFromArray(signal.rows, 1, cv.CV_32FC1,
' new Array(signal.rows).fill(0).fill(diff.data32F[(i-1)*3+2], i, signal.rows));



I guess that I have to create the array manually ... I do think that B4A has a function like Javascript for "new Array" like that :(

Thanks for all
Regards,
Cesar
 

JordiCP

Well-Known Member
Licensed User
I guess that 'signal' and 'diff' are OCVMat with depth=3 (cv_32FC3) and contains R,G,B channels

If you are accessing single channel elements from diff, you can first split it into 3 channels, it will be easier to manage. As it is done HERE

Regarding the code
B4X:
Dim channels As List
channels.Initialize
mCore.split( diff, channels)     '<-- Statically declare mCore as OCVCore 
Dim redChannel  As OCVMat = channels.Get(0)
Dim greenChannel  As OCVMat = channels.Get(1)
Dim blueChannel As OCVMat = channels.Get(2)

  Dim myReadData( signal.rows) as Float    'Only declare it once. Will be reused.

For i=1 to signal.rows()-1

  '---- Red channel ----
  Dim adjR as OCVMat
  adjR.initialize( signal.rows, 1, mType.CV_32F1)
  Dim valData(1) as Float
  redChannel.get3( i-1, 1, valData) 
  for j=0 to i-1
    myReadData(j) = 0
  Next
  For j=i to signal.rows-1
    myReadData(j) = valData(0)
  Next 
  adjR.put1(0,0, myReadData)

  '---- Green channel ----
  Dim adjG as OCVMat
  adjG.initialize( signal.rows, 1, mType.CV_32F1)
  Dim valData(1) as Float
  greenChannel.get3( i-1, 1, valData) 
  Dim myReadData( signal.rows) as Float
  for j=0 to i-1
    myReadData(j) = 0
  Next
  For j=i to signal.rows-1
    myReadData(j) = valData(0)
  Next 
  adjG.put1(0,0, myReadData)

 ' Do the same with the Blue channel

Next

Pls PM me if you have more issues
 

cesarcm

Member
Licensed User
(clap clap clap)

Simple and beauty! Congrats!
Thanks for all.
Kind regards,
Cesar

PS: I am trying to convert all source-code to B4A until next Monday since I will have an presentation
 

cesarcm

Member
Licensed User
Last question for today (I promisse it);)

C++ code:

// New values
Scalar means = mean(frameRGB, mask);

// Add new values to raw signal buffer
double values[] = {means(0), means(1), means(2)};

signal.push_back(Mat(1, 3, CV_64F, values));



Thanks.
Regards,
Cesar
 

JordiCP

Well-Known Member
Licensed User
Java OpenCV only allows to push_back Mats, so the scalar values must be converted to a single row Mat.

Test if this works (code is assuming that signal.cols equals 3), may need some fine tuning.
B4X:
Dim means as OCVScalar = mCore.mean(frameRGB, mask)
Dim values() as Double = means.val
Dim newMat As OCVMat
newMat.Initialize2(1, signal.cols, mType.CV_64FC1)
newMat.put(0, 0, values)
signal.push_back( newMat )
Good luck with the presentation, don't forget to add me to the credits 😁
 

cesarcm

Member
Licensed User
JordiCP,

Credits? of course!!! 👏👏👏

As like I have mentioned before: if everything goes right you will get an extra bonus (donation) or a monthly basis fee ;)

Thanks
Regards,
Cesar
 

cesarcm

Member
Licensed User
JordiCP,

Maybe a stupid question... (or not) ...

Should I always to "Initialize" an OCVMat object?

Exemple:

Dim myObj As OCVMat
myObj.initialize '???
myObj.zeros(10, 10, mType.mCvt.CV_32FC1)


Thanks
Regards,
Cesar
 

cesarcm

Member
Licensed User
JordiCP,

DFT function has 4 parameters:

4th param => nonZeroRows as Int

In my libraries of DFT for Javascript / C++ / Python, DFT has only 2 o3 parameters :(

And I am get confused to how to convert the code below (in red):

// Javascript
timeToFrequency(signal, magnitude) {
// Prepare planes
let planes = new cv.MatVector();
planes.push_back(signal);
planes.push_back(new cv.Mat.zeros(signal.rows, 1, cv.CV_32F))
//let powerSpectrum = new cv.Mat();
cv.merge(planes, signal);


// Fourier transform
cv.dft(signal, signal, cv.DFT_COMPLEX_OUTPUT);
if (magnitude) {
cv.split(signal, planes);
// planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
cv.magnitude(planes.get(0), planes.get(1), signal); // signal = magnitude
}

}

Thanks.
Regards,
Cesar
 

cesarcm

Member
Licensed User
JordiCP<

Same source code as last message but in C++

void timeToFrequency(InputArray _a, OutputArray _b, bool magnitude) {

// Prepare planes
Mat a = _a.getMat();
Mat planes[] = {cv::Mat_<float>(a), cv::Mat::zeros(a.size(), CV_32F)};
Mat powerSpectrum;
merge(planes, 2, powerSpectrum);

// Fourier transform
dft(powerSpectrum, powerSpectrum, DFT_COMPLEX_OUTPUT);

if (magnitude) {
split(powerSpectrum, planes);
cv::magnitude(planes[0], planes[1], planes[0]);
planes[0].copyTo(_b);
} else {
powerSpectrum.copyTo(_b);
}
}

Thanks.
Regards,
Cesar
 

JordiCP

Well-Known Member
Licensed User
Should I always to "Initialize
It depends. In this case 'zeros' is a static method that returns a OCVMat.
So the original Mat does not need to be initialized, but the call should be
B4X:
myObj = myObj.zeros(10, 10, mType.mCvt.CV_32FC1)
 

JordiCP

Well-Known Member
Licensed User
if (magnitude) {
cv.split(signal, planes);
// planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
cv.magnitude(planes.get(0), planes.get(1), signal); // signal = magnitude
}
You must declare planes as a list. Remember the code I sent yesterday with the split method.
 

cesarcm

Member
Licensed User
Mr.J,

Perfect! Thanks a lot!

Regarding DFT:

DFT function has 4 parameters:

4th param => nonZeroRows as Int


In my libraries of DFT for Javascript / C++ / Python, DFT has only 2 o3 parameters :(

I presume that you use this 4th parameter to calculate the next power of 2, right?

Regards,
Cesar
 

cesarcm

Member
Licensed User
JordiCP,

My original cvMat is NOT power2 compatible ... (signal As OCVMat)

How to copy it into a new OCVMat with next power2 allocated?

Thanks.
Regards,
Cesar
 
Top