Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ jobs:
uses: actions/setup-node@v6
with:
node-version: '22.x'
- name: Update Ubuntu and install libjpeg-dev
- name: Update Ubuntu and install libjpeg-dev and zlib1g-dev
run: |
sudo apt-get update && sudo apt install libjpeg-dev
sudo apt-get update && sudo apt install libjpeg-dev zlib1g-dev
- name: Build and test WebARKitLib
run: |
cd tests && mkdir build && cd build && cmake -DEMSCRIPTEN_COMP=0 .. && make && ./webarkit_test
cd tests && mkdir build && cd build && cmake -DEMSCRIPTEN_COMP=0 .. && make && ./webarkit_test && ./webarkit_nft_test && ./webarkit_nft_limit_test
- name: Build WebARKitLib with Emscripten (Docker)
run: |
cd ..
Expand Down
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,33 @@ fetched automatically via CMake `FetchContent`. The "planned" part above is
webarkit-testing switching its WASM build over to this CMake config (away from
`tools/makem.js`). The same config also drives the unit tests (see below).

### NFT helpers (`WebARKit/WebARKitTrackers/WebARKitNFT`)

The web-adapted NFT helpers formerly in jsartoolkitNFT live here (#75):

| Header (`<WebARKitTrackers/WebARKitNFT/...>`) | Provides |
|---|---|
| `trackingMod.h` | `ar2TrackingMod()`, `ar2CreateHandleMod()`, `ar2DeleteHandleMod()` — single-threaded AR2 tracking |
| `markerDecompress.h` | `decompressMarkers()` — unpacks a `.zft` into `.iset`/`.fset`/`.fset3` (returns `-1` on error) |
| `trackingSub.h` | `trackingInit*()` — KPM detection on a worker thread (pthreads) |
| `NFTMarkerState.h` | per-marker tracking state (C++ only) |

They are built by the `WebARKitNFT` static library, which also compiles the
ARToolKit5 sources it needs (AR, ARICP, AR2, KPM, ARUtil) and does **not** need
OpenCV. CMake options in `WebARKit/CMakeLists.txt`:

- `WEBARKIT_BUILD_OPTICAL` (ON) — the OpenCV `WebARKitLib` target
- `WEBARKIT_BUILD_NFT` (OFF) — the `WebARKitNFT` target (needs libjpeg and zlib)
- `WEBARKIT_NFT_THREADS` (OFF) — adds `trackingSub` (pthreads)

```bash
emcmake cmake -S WebARKit -B build-nft -DWEBARKIT_BUILD_OPTICAL=OFF -DWEBARKIT_BUILD_NFT=ON -DWEBARKIT_NFT_THREADS=ON
cmake --build build-nft
```

## Tests

C++ unit tests (GoogleTest) live in [`tests/`](tests/) (`webarkit_test.cc`,
C++ unit tests (GoogleTest) live in [`tests/`](tests/) (`webarkit_test.cc`, `webarkit_nft_test.cc`,
`CMakeLists.txt`, `pinball.jpg`) and run in CI via
[`.github/workflows/test.yml`](https://github.com/webarkit/WebARKitLib/actions/workflows/test.yml).
Build them standalone with CMake:
Expand Down
11 changes: 11 additions & 0 deletions WebARKit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ if(VERSION GREATER 3.24)
cmake_policy(SET CMP0135 NEW)
endif()

option(WEBARKIT_BUILD_OPTICAL "Build the OpenCV optical tracker (WebARKitLib target)" ON)
option(WEBARKIT_BUILD_NFT "Build the NFT tracking helpers (WebARKitNFT target, no OpenCV)" OFF)

if(WEBARKIT_BUILD_NFT)
add_subdirectory(WebARKitTrackers/WebARKitNFT)
endif()

if(NOT WEBARKIT_BUILD_OPTICAL)
return()
endif()

include(FetchContent)
include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/OpenCVEm.cmake)

Expand Down
94 changes: 94 additions & 0 deletions WebARKit/WebARKitTrackers/WebARKitNFT/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# WebARKitNFT: NFT tracking helpers (trackingMod, markerDecompress, trackingSub)
# plus the ARToolKit sources they need (AR, ARICP, AR2, KPM, ARUtil).
# The source lists mirror jsartoolkitNFT/tools/makem.js. No OpenCV dependency.

option(WEBARKIT_NFT_THREADS "Build the threaded KPM worker (trackingSub); on Emscripten also enables -pthread" OFF)

get_filename_component(WEBARKITLIB_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../.. ABSOLUTE)
set(ARTK_SRC ${WEBARKITLIB_ROOT}/lib/SRC)

file(GLOB AR_SOURCES
${ARTK_SRC}/AR/*.c
${ARTK_SRC}/AR/arLabelingSub/*.c
${ARTK_SRC}/ARICP/*.c
)

set(ARUTIL_SOURCES
${ARTK_SRC}/ARUtil/log.c
${ARTK_SRC}/ARUtil/file_utils.c
# thread helpers: AR2 handle.c/tracking.c call them even without the KPM worker
${ARTK_SRC}/ARUtil/thread_sub.c
# minizip, used by file_utils.c (zip/unzip helpers)
${ARTK_SRC}/ARUtil/crypt.c
${ARTK_SRC}/ARUtil/ioapi.c
${ARTK_SRC}/ARUtil/unzip.c
${ARTK_SRC}/ARUtil/zip.c
)

set(AR2_SOURCES
handle.c imageSet.c jpeg.c marker.c featureMap.c featureSet.c
selectTemplate.c surface.c tracking.c tracking2d.c matching.c matching2.c
template.c searchPoint.c coord.c util.c
)
list(TRANSFORM AR2_SOURCES PREPEND ${ARTK_SRC}/AR2/)

set(KPM_SOURCES
kpmHandle.cpp kpmRefDataSet.cpp kpmMatching.cpp kpmResult.cpp kpmUtil.cpp kpmFopen.c
FreakMatcher/detectors/DoG_scale_invariant_detector.cpp
FreakMatcher/detectors/gaussian_scale_space_pyramid.cpp
FreakMatcher/detectors/gradients.cpp
FreakMatcher/detectors/orientation_assignment.cpp
FreakMatcher/detectors/pyramid.cpp
FreakMatcher/facade/visual_database_facade.cpp
FreakMatcher/matchers/hough_similarity_voting.cpp
FreakMatcher/matchers/freak.cpp
FreakMatcher/framework/date_time.cpp
FreakMatcher/framework/image.cpp
FreakMatcher/framework/logger.cpp
FreakMatcher/framework/timers.cpp
)
list(TRANSFORM KPM_SOURCES PREPEND ${ARTK_SRC}/KPM/)

set(NFT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/trackingMod.c
${CMAKE_CURRENT_SOURCE_DIR}/trackingMod2d.c
${CMAKE_CURRENT_SOURCE_DIR}/markerDecompress.c
)

if(WEBARKIT_NFT_THREADS)
list(APPEND NFT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/trackingSub.c)
endif()

add_library(WebARKitNFT STATIC
${AR_SOURCES} ${ARUTIL_SOURCES} ${AR2_SOURCES} ${KPM_SOURCES} ${NFT_SOURCES}
)

target_include_directories(WebARKitNFT
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${WEBARKITLIB_ROOT}/include
PRIVATE
${ARTK_SRC}/KPM/FreakMatcher
)

target_compile_definitions(WebARKitNFT PUBLIC HAVE_NFT)

if(EMSCRIPTEN)
# Emscripten has no fopen64/ftello64/fseeko64: let minizip use the plain calls.
set_source_files_properties(
${ARTK_SRC}/ARUtil/ioapi.c ${ARTK_SRC}/ARUtil/unzip.c ${ARTK_SRC}/ARUtil/zip.c
PROPERTIES COMPILE_DEFINITIONS USE_FILE32API
)
# libjpeg and zlib come from the Emscripten ports.
target_compile_options(WebARKitNFT PUBLIC -sUSE_LIBJPEG=1 -sUSE_ZLIB=1)
target_link_options(WebARKitNFT PUBLIC -sUSE_LIBJPEG=1 -sUSE_ZLIB=1)
if(WEBARKIT_NFT_THREADS)
target_compile_options(WebARKitNFT PUBLIC -pthread)
target_link_options(WebARKitNFT PUBLIC -pthread)
endif()
else()
find_package(JPEG REQUIRED)
find_package(ZLIB REQUIRED)
find_package(Threads REQUIRED)
target_link_libraries(WebARKitNFT PUBLIC JPEG::JPEG ZLIB::ZLIB Threads::Threads)
endif()
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef NFT_MARKER_STATE_H
#define NFT_MARKER_STATE_H

#include <AR/ar.h>
#include <AR/arFilterTransMat.h>

/**
* Tracking state for one NFT marker (page).
*
* The bindings keep one of these per loadable page (PAGES_MAX). It replaces the
* single `detectedPage` / `ftmi` pair that limited tracking to one marker at a
* time (#613, #611).
*/
struct NFTMarkerState {
bool tracking = false; // AR2 is locked on this page
ARdouble pose[3][4] = {}; // latest pose, filtered when filtering is on
float err = -1.0f; // AR2 tracking error for `pose`
ARFilterTransMatInfo *ftmi = nullptr; // this marker's pose filter, created on first use
bool filterNeedsReset = true; // restart the filter on (re)acquisition
};

#endif // NFT_MARKER_STATE_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef MARKER_DECOMPRESS_H
#define MARKER_DECOMPRESS_H

#include <stdio.h>

/* Largest decompressed .zft accepted by decompressMarkers(); larger archives are rejected. */
#ifndef MARKER_DECOMPRESS_MAX_SIZE
#define MARKER_DECOMPRESS_MAX_SIZE (128u * 1024u * 1024u)
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct
{
char *iset_content;
char *fset_content;
char *fset3_content;
} markerContentStruct;

char* nameConcat(const char *s1, const char *s2);
FILE *openZFT( const char *filename, const char *ext);
/*
* Unpack <src>.zft into <outTemp>.iset, <outTemp>.fset and <outTemp>.fset3.
* Returns 0 on success, -1 on a missing, malformed or oversized archive or a
* write error. On failure no output file is left behind, so <outTemp> should
* name new files: an existing marker set at that path is not preserved.
*/
int decompressMarkers(const char* src, const char* outTemp);
int extractDataAndSave(const char* str, const char* name);

#ifdef __cplusplus
}
#endif

#endif // MARKER_DECOMPRESS_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* trackingMod.h modified version of ar2Tracking()
* from AR2/tracking.c
* ARToolKit5
*
* This file is part of ARToolKit.
*
* ARToolKit is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARToolKit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with ARToolKit. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent modules, and to
* copy and distribute the resulting executable under terms of your choice,
* provided that you also meet, for each linked independent module, the terms and
* conditions of the license of that module. An independent module is a module
* which is neither derived from nor based on this library. If you modify this
* library, you may extend this exception to your version of the library, but you
* are not obligated to do so. If you do not wish to do so, delete this exception
* statement from your version.
*
* Copyright 2015 Daqri, LLC.
* Copyright 2006-2015 ARToolworks, Inc.
*
* Author(s): Hirokazu Kato, Philip Lamb
* Mod. by Walter Perdan @kalwalt
*
*/
/*!
@header tracking
@abstract ARToolKit NFT core routines.
@discussion
This header declares essential types and API for the NFT portion of the
ARToolKit SDK.

For compile-time per-machine and NFT configuration, see &lt;AR2/config.h&gt;.
@copyright 2015 Daqri, LLC.
*/

#ifndef __trackingMod_H__
#define __trackingMod_H__
#include <AR/ar.h>
#include <AR/icp.h>
#include <AR2/config.h>
#include <AR2/featureSet.h>
#include <AR2/template.h>
#include <AR2/marker.h>
#include <AR2/tracking.h>

#if AR2_CAPABLE_ADAPTIVE_TEMPLATE
# error "WebARKitNFT trackingMod does not support AR2_CAPABLE_ADAPTIVE_TEMPLATE"
#endif

#define AR2_TRACKING_6DOF 1
#define AR2_TRACKING_HOMOGRAPHY 2

#ifdef __cplusplus
extern "C" {
#endif

int ar2Tracking2dSubMod ( AR2HandleT *handle, AR2SurfaceSetT *surfaceSet, AR2TemplateCandidateT *candidate,
ARUint8 *dataPtr, ARUint8 *mfImage, AR2TemplateT **templ,
AR2Tracking2DResultT *result );

AR2HandleT *ar2CreateHandleMod( ARParamLT *cparamLT, AR_PIXEL_FORMAT pixFormat/*, int threadNum*/ );
AR2HandleT *ar2CreateHandleSubMod( int pixFormat, int xsize, int ysize/*, int threadNum*/ );

int ar2DeleteHandleMod( AR2HandleT **ar2Handle );

int ar2TrackingMod ( AR2HandleT *ar2Handle, AR2SurfaceSetT *surfaceSet,
ARUint8 *dataPtr, float trans[3][4], float *err );
int ar2SetInitTrans ( AR2SurfaceSetT *surfaceSet, float trans[3][4] );

#ifdef __cplusplus
}
#endif
#endif
Loading
Loading