Hello justadudewhohacks!
In a program that works with the C++ version of opencv (2.4), calculates descriptors and key points, and i get only configuration of this type:
"% YAML: 1.0
descriptors: !! opencv-matrix
聽聽聽rows: intXXX
聽聽聽cols: intXXX
聽聽聽dt: f
聽聽聽data: [double_XXX, double_XXX, double_XXX, ... ... ... (many elements)]
keypoints: [double_XXX, double_XXX, double_XXX, ... ... ... (many elements)]
cols: intXXX
rows: intXXX"
I need to bring this data in a view that is suitable for opencv4nodejs to start comparing images already from NodeJs.
From the obtained key points, I learned how to create the necessary new cv.KeyPoint (in opencv4nodejs) using the constructor (found in the documentation) (https://opencv4nodejs.herokuapp.com/docs/core)
But I do not know how from essence
"rows: intXXX
cols: intXXX
dt: f
data: []"
initialize a suitable cv.Mat for opencv4nodejs to work with cv.matchFlannBased.
In the C ++ version, writing/reading data is very easy, using cv.FileStorage
"FileStorage fs (std :: string (in_lpszFP_Path), FileStorage :: READ);
fs ["descriptors"] >> descriptor_base;
read (fs ["keypoints"], keypoints_base);
fs ["cols"] >> cols_base;
fs ["rows"] >> rows_base;"
and further the readed data using in matcher:
"FlannBasedMatcher matcher;
matcher.knnMatch (descriptor_base, data-> descriptor, matches1, k);"
Is it possible to initiate data like
"rows: intXXX
cols: intXXX
dt: f
data: [double_XXX, double_XXX, double_XXX, ... ... ... (many double elements)]"
for correct work cv.matchFlannBased?
Thank you for attention.
I am not familar with the yaml representation of feature descriptors but it looks like data is simply a 1D array with all the feature vectors concatenated e.g. the number of elements in data is equal to cols*rows, right?
Well I guess you can simply recreate the Mat from the data array:
const matData = []
for(let i = 0; i < rows; i++) {
matData.push(data.slice(i * cols, cols))
}
const desc = new cv.Mat(rows, cols, cv.CV_32F, matData)
or something like this?
If I remember correctly, the descriptor Mat has "rows" number of feature vectors and each feature vector has "cols" number of entries
Hello again after a holiday! I'm sorry I did not answer for a long time.
I want to make such a matrix. The number of elements in the data array is exactly equal to the
rows * cols. Just like you wrote, I create a matrix, but have problem:
"Error: Mat::New - number of channels (1) do not match fill vector length 194"
(194 - is number of rows) As it seems to me, the problem is in CV_32F, I've tried different variants with float and another. like CV_8UC3 and the other types OpenCV, but problem still alive and i cant init cv.Mat from this data.
Welcome back,
If you want to create a Mat from an data array and type like so: new Mat(data, type) then data has to be an array of columns, where each column is also an array.
For example,
creating a 1 Channel Mat with 2 rows and 3 columns:
const matData = [
[255, 255, 255]
[255, 255, 255]
]
const mat = new cv.Mat(matData, cv.CV_8UC1)
creating a 3 Channel Mat with 2 rows and 3 columns:
const matData = [
[ [255, 0, 0], [255, 0, 0], [255, 0, 0] ]
[ [255, 0, 0], [255, 0, 0], [255, 0, 0] ]
]
const mat = new cv.Mat(matData, cv.CV_8UC3)
If the values themselves are multi channeled, then these values are also arrays.
The error message that you posted implies, that there must be something wrong with the array that you are passing to the constructor.
Thanks, I will continue the experiments!
So, I got to the bottom of the problem. As shown in the synchronous matchFeatures.js example, in the descriptor calculation step,
const descriptors2 = detector.compute (img2, keyPoints2);
I can get the data identical to my data by
const dataArr = descriptors2.getDataAsArray ();
So - we have cols and rows (by descriptors2 object), and dataArray.
How do I create Mat, identical to descriptors2 from this data by constructor?
const myDescMat = new cv.Mat(descriptors2.rows, descriptors2.cols, cv.CV_32F, dataArr);
gives an error message again (Error: Mat::New - number of channels (1) do not match fill vector length 194) Do I have to bring the dataArray into a certain kind?
P.S.
This example does not work, I get same error.
const matData = [
[ [255, 0, 0], [255, 0, 0], [255, 0, 0] ]
[ [255, 0, 0], [255, 0, 0], [255, 0, 0] ]
]
const mat = new cv.Mat(matData, cv.CV_8UC3)
Looks like i can do this with const desc = new cv.Mat(matData, cv.CV_32F);!
What, this example should work. I even have testcases for all kinds of initializations of Mats from arrays:
https://github.com/justadudewhohacks/opencv4nodejs/blob/master/test/tests/core/Mat/constructorTestsFromJsArray.js,
https://github.com/justadudewhohacks/opencv4nodejs/blob/master/test/tests/core/Mat/exampleData.js
If you have data like this:
const descriptors2 = detector.compute (img2, keyPoints2);
const dataArr = descriptors2.getDataAsArray ();
You can create a new Mat like this:
const myDescMat = new cv.Mat(dataArr, cv.CV_32F);
The number of rows and cols are known so you do not pass these to the constructor, because dataArr.length === rows and dataArr[0].length === cols.
I think the problem with your data from the yml file is, that you just have a single array of mat values, e.g. all columns are concatenated like this data: [column1 values, column2 values, ....].
Did you try to remap the data to an array of columns like I said?
const matData = []
for(let i = 0; i < rows; i++) {
matData.push(data.slice(i * cols, cols))
}
const desc = new cv.Mat(matData, cv.CV_32F)
Edit: Sorry in the upper example I wrote const desc = new cv.Mat(rows, cols, cv.CV_32F, matData), which is not a valid constructor in this case. It has to be const desc = new cv.Mat(matData, cv.CV_32F) of course.
Yes, its look great! Thank you very much for such support and detailed answers to my questions! I apologize, I have never worked with OpenCV before and do not know its mechanisms. :(
Nice. No worries, that's why I am here to help.
Most helpful comment
What, this example should work. I even have testcases for all kinds of initializations of Mats from arrays:
https://github.com/justadudewhohacks/opencv4nodejs/blob/master/test/tests/core/Mat/constructorTestsFromJsArray.js,
https://github.com/justadudewhohacks/opencv4nodejs/blob/master/test/tests/core/Mat/exampleData.js
If you have data like this:
You can create a new Mat like this:
The number of rows and cols are known so you do not pass these to the constructor, because
dataArr.length === rowsanddataArr[0].length === cols.I think the problem with your data from the yml file is, that you just have a single array of mat values, e.g. all columns are concatenated like this
data: [column1 values, column2 values, ....].Did you try to remap the data to an array of columns like I said?
Edit: Sorry in the upper example I wrote
const desc = new cv.Mat(rows, cols, cv.CV_32F, matData), which is not a valid constructor in this case. It has to beconst desc = new cv.Mat(matData, cv.CV_32F)of course.