Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implementing NFT with threading support with emscripten #2

Open
wants to merge 24 commits into
base: fixing-nft
Choose a base branch
from

Conversation

kalwalt
Copy link
Owner

@kalwalt kalwalt commented Jul 22, 2019

In this PR i test the NFT with threading support. Basically i modified some functions in ARToolKitJS.cpp with the threading methods in trackingSub.c :

THREAD_HANDLE_T *trackingInitInit( KpmHandle *kpmHandle );
int trackingInitStart( THREAD_HANDLE_T *threadHandle, ARUint8 *imagePtrLuma );
int trackingInitGetResult( THREAD_HANDLE_T *threadHandle, float trans[3][4], int *page );
int trackingInitQuit( THREAD_HANDLE_T **threadHandle_p );

The project is not finished, they are some modifications to do... but even if it is not finished, i got 80-90 fps and 20-25 fps while detecting the NFT marker/image.
Note: not all the examples will works, i'm testing now only the nft_threejs.html example.
I'm developing for now only the minified version, i not added the Pthread support to the debug version due to this issue explained in this emscripten article:

Pthreads + memory growth (ALLOW_MEMORY_GROWTH) is especially tricky, see wasm design issue #1271. This currently causes JS accessing the wasm memory to be slow - but this will likely only be noticeable if the JS does heavy work (wasm runs at full speed, so moving work over can fix this). This also requires that your JS be aware that the HEAP* views may need to be updated - use the GROWABLE_HEAP_* helper functions which automatically handle that for you.

When it will be ready, will be merged in PR #1

to do list:

  • build the debug lib version with Pthreads support (if possible)
  • solve the asm.js issue: Invalid asm.js: Invalid member of stdlib
  • testing all the examples
  • removing not necessary code ( old code with webWorkers)
  • adding threading only to NFT
  • adding filtering to the trans Matrix
  • restoring the wasm LIb?
  • solving the issue with Firefox see implementing NFT with threading support with emscripten #2 (comment)

Note:

If someone want to try and test the code you can go to https://kalwalt.github.io/kalwalt-interactivity-AR/

But Please read carefully this before:

You need to enable the SharedArrayBuffer option in your browser. This was disabled due to Spectre issue read this article !!!

Update 16/2/2023

updated the code to Emscripten emsdk 3.1.20,

  • removed libjpeg stuff/code -> added -s USE_LIBJPEG=1
  • removed useless transferDataToHeap method
  • minor changes

Anyway, as said in this comment the code fails to load the camera parameter, and then fails to detect and track the NFT marker.

@kalwalt kalwalt added the enhancement New feature or request label Jul 22, 2019
@kalwalt kalwalt self-assigned this Jul 22, 2019
@kalwalt kalwalt mentioned this pull request Jul 22, 2019
15 tasks
@kalwalt
Copy link
Owner Author

kalwalt commented Jul 22, 2019

With the last commit i get this error:

three.min.js:359 THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0

what does it means? the matrix is not filled in the right way? look:

int trackingInitGetResult( THREAD_HANDLE_T *threadHandle, float trans[3][4], int *page );

the trans is a 3 * 4 as you can see in the code:

float trans[3][4];
float trackingTrans[3][4];
kpmResultNum = trackingInitGetResult( arc->threadHandle, trackingTrans, &pageNo);
ARLOGi("kpmResultNum is: %d\n", kpmResultNum);
for( i = 0; i < kpmResultNum; i++ ) {
//if (kpmResult[i].pageNo == markerIndex && kpmResult[i].camPoseF == 0 ) {
if (pageNo == markerIndex ) {
// if( flag == -1 || err > kpmResult[i].error ) { // Take the first or best result.
if( flag == -1 ) { // Take the first or best result.
flag = i;
err = kpmResult[i].error;
ARLOGe("error in the tracking");
}
}
}
flag = kpmResultNum;
ARLOGi("flag is: %d\n", flag);
if (flag > -1) {
for (j = 0; j < 3; j++) {
for (k = 0; k < 4; k++) {
trans[j][k] = trackingTrans[j][k];
}
}

@kalwalt
Copy link
Owner Author

kalwalt commented Jul 22, 2019

from this stackoverflow article mrdoob comment:

Matrix3.getInverse(): can't invert matrix, determinant is 0 usually happens when either the scale.x, scale.y or scale.z are 0. Make sure you're not scaling the object to 0.

@kalwalt
Copy link
Owner Author

kalwalt commented Jul 22, 2019

The NFT marker is detected, i see the scan in the console, but the sphere is not displayed. I will see this issue in the next days.
A real improvement in fps, at least on my Desktop machine!

@evaristoc
Copy link

evaristoc commented Jul 23, 2019

If it is calculating a determinant, it is looking something like a scaling factor. If I am not wrong should be applicable only to square matrices. Is trackingTrans[3][4] the target matrix for the determinant operation? (Are matrices written as M[m][n] in C++?)

@evaristoc
Copy link

@kalwalt
This number : kpmResultNum : do you think is a determinant?

@evaristoc
Copy link

evaristoc commented Jul 23, 2019

@kalwalt

I will try to check the code these days to see if I spot something. Apparently the trackingTrans matrix is the pose matrix.

I want to get and idea what the target of the threading is. At least one of the targeted functions appears to be trackingInitMain. The target (master?) data seems to be the descriptors (a struc) : trackingHandle.

If I understood correctly, I would say it makes sense to run a threading over that part.

@kalwalt
Copy link
Owner Author

kalwalt commented Jul 23, 2019

If it is calculating a determinant, it is looking something like a scaling factor. If I am not wrong should be applicable only to square matrices. Is trackingTrans[3][4] the target matrix for the determinant operation? (Are matrices written as M[m][n] in C++?)

Unfortunately I'm not very skilled in math, biìut looking in the code it should be the pose matrix?

This number : kpmResultNum : do you think is a determinant?

I don't think, it was part of the previous code, i will delete it.

I want to get and idea what the target of the threading is. At least one of the targeted functions appears to be trackingInitMain. The target (master?) data seems to be the descriptors (a struc) : trackingHandle.

i think i have implemented as in mainLoop in the nftSimple example:

https://github.com/artoolkitx/artoolkit5/blob/a8baa4b95be381776af40d49b677bd5757f780c8/examples/nftSimple/nftSimple.c#L560-L598

but the data after this routine pass trough
the markersNFT struct from ARMarkerNFT.c (see in the nftSimple example few lines after L598) the trans matrix data pass trough the arFilterTransMat function; maybe it is a necessary step?

if (flag > -1) {

//ARLOGi("flag is: %d\n", arc->detectedPage);
if (pageNo >= 0 && pageNo == arc->detectedPage) {
Copy link
Owner Author

@kalwalt kalwalt Jul 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the problem is this we do not pass any data to the EM_ASM
if i change the variable in the conditional for example:
if (pageNo >= 0) we get data but with that Threejs error, and the sphere appear and disappears. MAybe we should use another condition or what else?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't remember why i put this:
if (pageNo >= 0 && pageNo == arc->detectedPage) {

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe it should be

if (arc->detectedPage >= -1) {

//// or better

if (arc->detectedPage > -1) {

Copy link

@evaristoc evaristoc Jul 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather ask why appears and disappears. As you put it, it is a hack that might work for some but not all cases. I would prefer to understand why pageNo should be as condition.

However, this might not have sense: pageNo >= 0 && pageNo == arc->detectedPage. I can see some contradictory behaviour there.

If you leave it as arc->detectedPage > -1, does it mean that pageNo >= 0? For what I read from the code, detectedPage was a sort of flag for different states. What meant -1 status for detectedPage?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about:

if (pageNo >= 0 && arc->detectedPage SOMETHING -1) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the flagging I found for detectedPage:

int detectedPage  = -2;  // -2 Tracking not inited, -1 tracking inited OK, >= 0 tracking online on page.

@evaristoc
Copy link

evaristoc commented Jul 23, 2019

@kalwalt
pose matrix
I guess but not sure the operations with the pose (transformation) matrix are being left at minimal: the actual shape is 4x4 but the last row default to [0,0,0,1]. It is possible that is a common practice to skip that row. Something to confirm? Also the vector that multiply it has 1 as last value ([x,y,z,1]T). Check https://en.wikipedia.org/wiki/Transformation_matrix for more details.

kpmResultNum
I will check this later?

markersNFT struct
Haven't been able to read the whole code yet. Those are apparently the chosen corners (the key points that will be listed for comparison). For what I saw in the code, the operation where markersNTF struc was used suggested a rectification of the position of the markers so they can be compared. I guess this is an homographic correction.

The code apparently never bother about detecting whether there was a variation of the values of the transformation matrix : it apparently just rectify at every frame, no matter the values. So if I understand correctly that part of the script always runs.

It is likely necessary: if I am not wrong the detector algorithm needs to rectify the test image (frame) in order to compare the found points in a similar orientation, position, etc than in the training image before declaring a good matching. Once the points have been detected, the homographic correction might be used to correct the volume projection over the target area in the test image. There is something similar happening with marker-based detection, @kalwalt, but the training marker is deployed differently and the algos might be easier.

However, this is NOT a step that might require threading. A for-loop will do. I think there are other parts that will be more suitable to, to mention:

  • the method devoted to the search of the corners
  • the one that create the descriptors
  • the one that compares (the matching one)
  • the part that choose good points and reduce the number of outliers (if there is one implemented)

@evaristoc
Copy link

evaristoc commented Jul 23, 2019

@kalwalt

However now that I see it you might not have access to those methods though... hmmmm.... And they might be already optimized.

So probably the point comparison might be a good target, as well as the creation of the strucs when a painful for-loop is implemented.

Can you rather work on a simpler approach by for example making some for-loops more threaded instead? See that those for-loops are almost always there, for every frame.

Just a suggestion.

@evaristoc
Copy link

Contact you these days? Take care!

@kalwalt
Copy link
Owner Author

kalwalt commented Jul 23, 2019

@evaristoc thanks for the feedback! I have not time to answer to all the questions/topics but I want to make an observation: the kpmMatching and kpmGetResult functions (inside the threading function too) are responsable for the matching and retrieveing trans data and previously in the getNFTMarkerInfo used this two functions without threading, maybe i overcomplicated the code, But i have no time to test my idea now.... very late for me, i will try tomorrow if i will have time.

@kalwalt kalwalt force-pushed the nft-with-threads branch from 296fc2e to 218cb8f Compare July 26, 2019 22:25
@kalwalt
Copy link
Owner Author

kalwalt commented Jul 27, 2019

With the latest commits i got always the message Tracking lost. that means the ar2Tracking function receive some empty args, but it is not possible, for this reason i'm very confused....

@kalwalt
Copy link
Owner Author

kalwalt commented Jul 27, 2019

@evaristoc @nicolocarpignoli It seems that ar2Tracking was filled with wrong args:
it needs arc->videoFrame instead of arc->videoLuma , I tested with the Chrome Browser and the FPS are not so bad: 35fps while detecting the pinball image and more 50fps without.
Please test it and let me know what do you think!

But there are other refinement in the code to do, and other issues to solve...

@kalwalt
Copy link
Owner Author

kalwalt commented Jul 27, 2019

Unfortunately this not works with Firefox:

Current environment does not support SharedArrayBuffer, pthreads are not available! artoolkitNft.min.js:formatted:7495
ExitStatus: Program terminated with exit(-1)

@gpt3-bot
Copy link

gpt3-bot commented Jul 27, 2019 via email

@kalwalt
Copy link
Owner Author

kalwalt commented Sep 22, 2019

@nicolocarpignoli @evaristoc @ThorstenBux @shawmakesmusic now it works!! it was a problem of scaling the model and repositioning it !!
I will do the same for the other example.

@kalwalt
Copy link
Owner Author

kalwalt commented Sep 22, 2019

I should also test the binary version of the models, probably more efficient in loading time, and needs to test also with mobile devices...
I would know if there are some good news for the NFT marker creator @Carnaux

@nicolocarpignoli
Copy link
Collaborator

@kalwalt Great!

@Carnaux
Copy link

Carnaux commented Sep 23, 2019

@kalwalt Unfortunately I didn't have time in August and September, but in October I will have a lot more time for projects. The last thing I was doing was trying to read the jpeg image because the current implementation of the marker creator is focused to local, not web, so I can't read some properties of the jpeg file using JavaScript. Maybe @ThorstenBux can help me to understand the data inside the iset and fset files.

@kalwalt
Copy link
Owner Author

kalwalt commented Sep 23, 2019

@Carnaux I imagined you were busy, but no problem! Unfortunately i have not so much time but I will try to move forward. regarding the problem for jpeg images I will begin to look at the problem, maybe I will open a specific issue in your repository.

@Carnaux
Copy link

Carnaux commented Sep 23, 2019

@kalwalt I will open one and describe what is needed and what I was trying.

@kalwalt
Copy link
Owner Author

kalwalt commented Sep 23, 2019

@Carnaux just opened one right now!

@nicolocarpignoli
Copy link
Collaborator

nicolocarpignoli commented Sep 24, 2019

@kalwalt are you able to host a version of it on Github.io? It would be a great way to test quickly with different mobile phones too. If you don't know how to to that just ask i can help you it's simple

@kalwalt
Copy link
Owner Author

kalwalt commented Sep 24, 2019

@nicolocarpignoli I can do it. and this is a good idea. 😄

@kalwalt
Copy link
Owner Author

kalwalt commented Sep 24, 2019

@nicolocarpignoli with Github.io you can only host the master or the gh-pages or docs folder, you can not host other branch apart them. I will host on my https://github.com/kalwalt/kalwalt-interactivity-AR. I will do tomorrow as now is too late and i am very tired.

@nicolocarpignoli
Copy link
Collaborator

yes no worries host it wherever you want :)

@kalwalt
Copy link
Owner Author

kalwalt commented Sep 25, 2019

@nicolocarpignoli and everybody here... i hosted one of the examples (CesiumMan) at my page https://kalwalt.github.io/kalwalt-interactivity-AR/nft_threads_cesium.html will host also the other examples when i will have time.

@kalwalt
Copy link
Owner Author

kalwalt commented Oct 1, 2019

i added some other example to test to my https://kalwalt.github.io/kalwalt-interactivity-AR/ if someone want to try.

@kalwalt
Copy link
Owner Author

kalwalt commented Oct 7, 2019

The asm.js issue: Invalid asm.js: Invalid member of stdlib seems disappeared, don't know why i would like to know what caused maybe the last changes?

Edit: but i tested on my https://kalwalt.github.io/kalwalt-interactivity-AR/
running things locally it not happens but instead i get that error on my webpage.

@kalwalt
Copy link
Owner Author

kalwalt commented Feb 16, 2023

I adapted the code to emscripten emsdk 3.1.20, the code can be build but when i run the nft_threejs example the camera parameter can not be corrected loaded. For precision: it load the binary file but unfortunately this is not sufficient. That's very strange, maybe something related to emscripten pthread? One possible issue is the loadCamera function in the --pre-js, if we remove it from artoolkit.api.js and create the necessary code for loading outside maybe it can be solved?
I do not intend to add threading support to jsartoolkit5, but maybe in a future to jsartoolkitNFT.
I will add some useful comment in the code for future reference.

* Transfer data
*/

void transferDataToHeap(int id, ARUint8 *data) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I m not sure but it seems that is not correct, i should check and maybe i will restore it.

//FLAGS += ' -s ERROR_ON_UNDEFINED_SYMBOLS=0';
//FLAGS += ' -s NO_BROWSER=1 '; // for 20k less
FLAGS += ' --memory-init-file 0 '; // for memless file
FLAGS += ' -s BINARYEN_TRAP_MODE=clamp'
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with newer emscripten (upstream) version it's not needed anymore.

@@ -117,10 +115,10 @@ var FLAGS = '' + OPTIMIZE_FLAGS;
FLAGS += ' -Wno-warn-absolute-paths ';
FLAGS += ' -s TOTAL_MEMORY=' + MEM + ' ';
FLAGS += ' -s USE_ZLIB=1';
FLAGS += ' -s USE_LIBJPEG=1 ';
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't needed anymore to include libjpeg source code since it's embedded inside Emscripten, just adding this flag...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C/C++ coding with C and C++ language code design enhancement New feature or request javascript all about javascript code NFT nft markerless technology
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants