[Artoolkit] Android Sample of nftSimple

结合:[Artoolkit] ARToolKit's SDK Structure on Android

 

重难点:aRBaseLib/, nftSimple/, libcpufeatures.a

 

 

  • aRBaseLib/

 

如果摄像头控制只能在android层操作,那么ARBaseLib中的摄像头控制部分就是重点之一。

unsw@unsw-UX303UB$ _cmd-wc-java 
   204 ./AndroidUtils.java
   395 ./NativeInterface.java
   429 ./ARToolKit.java
   242 ./camera/CaptureCameraPreview.java
   420 ./camera/CameraPreferencesActivity.java
   211 ./camera/CameraWrapper.java
    70 ./camera/CameraEventListener.java
   106 ./rendering/gles20/ARRendererGLES20.java
    85 ./rendering/gles20/LineGLES20.java
    89 ./rendering/gles20/BaseFragmentShader.java
   196 ./rendering/gles20/ShaderProgram.java
    83 ./rendering/gles20/BaseShaderProgram.java
    84 ./rendering/gles20/CubeGLES20.java
    60 ./rendering/gles20/OpenGLShader.java
    53 ./rendering/gles20/ARDrawableOpenGLES20.java
   102 ./rendering/gles20/BaseVertexShader.java
   139 ./rendering/Cube.java
    93 ./rendering/ARRenderer.java
    83 ./rendering/RenderUtils.java
   152 ./rendering/Line.java
    51 ./assets/AssetFileTransferException.java
    52 ./assets/HashComputationException.java
   191 ./assets/AssetFileTransfer.java
   154 ./assets/Hasher.java
   222 ./assets/AssetHelper.java
   122 ./FPSCounter.java
   433 ./ARActivity.java
  4521 total
unsw@unsw-UX303UB$
View Code

 4000行代码,从摄像头控制开始。(Replaced with opencv4android)

 

01. rendering.ARActivity是main(),其中:

CameraEventListener接口可替换为opencv4android提供的CameraBridgeViewBase.CvCameraViewListener2接口。

 

02. 处理每一帧

@Override
    public void cameraPreviewFrame(byte[] frame) {

        if (firstUpdate) {
            // ARToolKit has been initialised. The renderer can now add markers, etc...
            if (renderer.configureARScene()) {
                Log.i(TAG, "Scene configured successfully");
            } else { 
                // Error
                Log.e(TAG, "Error configuring scene. Cannot continue.");
                finish();
            }
            firstUpdate = false;
        }
        
        if (ARToolKit.getInstance().convertAndDetect(frame)) {
            
            // Update the renderer as the frame has changed
            if (glView != null) glView.requestRender();
            
            onFrameProcessed();
        }
        
    } 

  

03. ARToolKit处理帧,然后调用native(NDK)

    public boolean convertAndDetect(byte[] frame) {

        if (!initedNative) return false;
        if (frame == null) return false;        
        
        if (!NativeInterface.arwAcceptVideoImage(frame, frameWidth, frameHeight, cameraIndex, cameraIsFrontFacing)) return false;
        if (!NativeInterface.arwCapture()) return false;
        return NativeInterface.arwUpdateAR();
    }

 libARWrapper.so的native代码在哪里?

nftSimple没有使用Wrapper技术,而是直接调用native: "AR and Rendering Code in Native C/C++ Using Android NDK"

怎么感觉 aRBaseLib 没有大用 ?

    @Override
    public void onPreviewFrame(byte[] data, Camera cam) {
        
        nftSimpleActivity.nativeVideoFrame(data);
        cam.addCallbackBuffer(data);
    }

 

04. 一帧的处理

  1 JNIEXPORT void JNICALL JNIFUNCTION_NATIVE(nativeVideoFrame(JNIEnv* env, jobject obj, jbyteArray pinArray))
  2 {
  3     int i, j, k;
  4     jbyte* inArray;
  5         
  6     if (!videoInited) {
  7 #ifdef DEBUG
  8         LOGD("nativeVideoFrame !VIDEO\n");
  9 #endif        
 10         return; // No point in trying to track until video is inited.
 11     }
 12     if (!nftDataLoaded) {
 13         if (!nftDataLoadingThreadHandle || threadGetStatus(nftDataLoadingThreadHandle) < 1) {
 14 #ifdef DEBUG
 15             LOGD("nativeVideoFrame !NFTDATA\n");
 16 #endif        
 17             return;
 18         } else {
 19             nftDataLoaded = true;
 20             threadWaitQuit(nftDataLoadingThreadHandle);
 21             threadFree(&nftDataLoadingThreadHandle); // Clean up.
 22         }
 23     }
 24     if (!gARViewInited) {
 25         return; // Also, we won't track until the ARView has been inited.
 26 #ifdef DEBUG
 27         LOGD("nativeVideoFrame !ARVIEW\n");
 28 #endif        
 29     }
 30 #ifdef DEBUG
 31     LOGD("nativeVideoFrame\n");
 32 #endif        
 33     
 34     // Copy the incoming  YUV420 image in pinArray.
 35     env->GetByteArrayRegion(pinArray, 0, gVideoFrameSize, (jbyte *)gVideoFrame);
 36     
 37     // As of ARToolKit v5.0, NV21 format video frames are handled natively,
 38     // and no longer require colour conversion to RGBA.
 39     // If you still require RGBA format information from the video,
 40     // here is where you'd do the conversion:
 41     // color_convert_common(gVideoFrame, gVideoFrame + videoWidth*videoHeight, videoWidth, videoHeight, myRGBABuffer);
 42 
 43     videoFrameNeedsPixelBufferDataUpload = true; // Note that buffer needs uploading. (Upload must be done on OpenGL context's thread.)
 44     
 45     // Run marker detection on frame
 46     if (trackingThreadHandle) {
 47         // Perform NFT tracking.
 48         float            err;
 49         int              ret;
 50         int              pageNo;
 51         // 又到了熟悉的地方:)
 52         if( detectedPage == -2 ) {
 53             trackingInitStart( trackingThreadHandle, gVideoFrame );
 54             detectedPage = -1;
 55         }
 56         if( detectedPage == -1 ) {
 57             ret = trackingInitGetResult( trackingThreadHandle, trackingTrans, &pageNo);
 58             if( ret == 1 ) {
 59                 if (pageNo >= 0 && pageNo < surfaceSetCount) {
 60 #ifdef DEBUG
 61                     LOGE("Detected page %d.\n", pageNo);
 62 #endif
 63                     detectedPage = pageNo;
 64                     ar2SetInitTrans(surfaceSet[detectedPage], trackingTrans);
 65                 } else {
 66                     LOGE("Detected bad page %d.\n", pageNo);
 67                     detectedPage = -2;
 68                 }
 69             } else if( ret < 0 ) {
 70 #ifdef DEBUG
 71                 LOGE("No page detected.\n");
 72 #endif
 73                 detectedPage = -2;
 74             }
 75         }
 76         if( detectedPage >= 0 && detectedPage < surfaceSetCount) {
 77             if( ar2Tracking(ar2Handle, surfaceSet[detectedPage], gVideoFrame, trackingTrans, &err) < 0 ) {
 78 #ifdef DEBUG
 79                 LOGE("Tracking lost.\n");
 80 #endif
 81                 detectedPage = -2;
 82             } else {
 83 #ifdef DEBUG
 84                 LOGE("Tracked page %d (max %d).\n", detectedPage, surfaceSetCount - 1);
 85 #endif
 86             }
 87         }
 88     } else {
 89         LOGE("Error: trackingThreadHandle\n");
 90         detectedPage = -2;
 91     }
 92     
 93     // Update markers.
 94     for (i = 0; i < markersNFTCount; i++) {
 95         markersNFT[i].validPrev = markersNFT[i].valid;
 96         if (markersNFT[i].pageNo >= 0 && markersNFT[i].pageNo == detectedPage) {
 97             markersNFT[i].valid = TRUE;
 98             for (j = 0; j < 3; j++) for (k = 0; k < 4; k++) markersNFT[i].trans[j][k] = trackingTrans[j][k];
 99         }
100         else markersNFT[i].valid = FALSE;
101         if (markersNFT[i].valid) {
102             
103             // Filter the pose estimate.
104             if (markersNFT[i].ftmi) {
105                 if (arFilterTransMat(markersNFT[i].ftmi, markersNFT[i].trans, !markersNFT[i].validPrev) < 0) {
106                     LOGE("arFilterTransMat error with marker %d.\n", i);
107                 }
108             }
109             
110             if (!markersNFT[i].validPrev) {
111                 // Marker has become visible, tell any dependent objects.
112                 //ARMarkerAppearedNotification
113             }
114     
115             // We have a new pose, so set that.
116             arglCameraViewRHf(markersNFT[i].trans, markersNFT[i].pose.T, 1.0f /*VIEW_SCALEFACTOR*/);
117             // Tell any dependent objects about the update.
118             //ARMarkerUpdatedPoseNotification
119             
120         } else {
121             
122             if (markersNFT[i].validPrev) {
123                 // Marker has ceased to be visible, tell any dependent objects.
124                 //ARMarkerDisappearedNotification
125             }
126         }                    
127     }
128 }

由原来的 mainloop 变为了android preview 一帧来调用,其他native部分都相同。

 

 

  • libcpufeatures.a

Link: https://developer.android.com/ndk/guides/cpu-features.html

Android 官方提供的读取cpu信息的一个库。我们这里主要对应于线程相关的部分。

 


Android Studio 2.2.3直接加载Android example出现的问题:

 

@PN1019, this is a tough nut. Let me try summarize and hopefully that'll help you.
Why Android is problematic to target is because every Android product provider's product looks different, has different features, is using different Android OS versions and are built with different tool versions. And the Android SDK, tools, platform build tools, and build tools change frequently and radically. Then on top of all this, every app uses a different combination of compileSdkVersion, buildToolsVersion, minSdkVersion, and targetSdkVersion and requires a valid combination of Android plugin for Gradle version and Gradle product version for building. Ouch. Finally, Android implements it own Java runtime which affects the Java compiler used. So you have to stick with the "most" mainstream development environment the Android SDK developers target.
2) You have to tell me what OS your developing your Android product on, Linux, Mac OS X (12/11) or Windows 10. If you're not using one of the three, then please start using one. Furthermore, update to the latest version of one of these development platforms and keep it up-to-date.
3) For the IDE, please use Android Studio and make sure you're using the latest and greatest version of Android Studio.
4) Regarding the Java JRE an JDK. Always install the latest and greatest JRE and JDK on your development system (devbox). Understand the difference between the two: the JRE is for executing apps compiled from Java code and the JDK is for compiling Java code to classes that make up executable Java app. There is no need to keep old versions of either on your devbox. To see which version you have on your devbox, from your devbox's command line, do this:
For the Oracle Corp JDK version: javac -version
For the Oracle Corp JRE version: java -version
Gradle source in Android Studio uses the Oracle Corp JRE even though the Gradle language doesn't look like Java source. Also, Gradle uses the Oracle Corp JDK when it compiles the Android Java code to run as an app on an Android device. But Android implements it's own JRE to run its special rendition of compiled Java classes on Android devices. This means the version of Oracle Corp JDK used by Gradle when compiling Java for Android devices will lag behind Oracle's latest JDK release. Therefore, you can't use the latest and greatest Java language features when developing an Android app because Android is using an old version of javac, i.e. an old Oracle Corp JDK version.

So there's two ways to get around this.

Use the JDK that is embedded with Android Studio 2.2.+. Or, tell Android Studio to use the Oracle Corp JDK installed on your devbox but have it run in such a way to regress in compiling an older version of the Java language creating an older version of runtime Java classes. I recommend the former, please see my entry above now labeled with "Recommended JDK to use:".

 

and Android Studio 2.1.1 is better.

 

unsw@unsw-UX303UB$ sudo update-alternatives --config javac
There are 3 choices for the alternative javac (providing /usr/bin/javac).

  Selection    Path                                         Priority   Status
------------------------------------------------------------
  0            /usr/lib/jvm/java-7-oracle/bin/javac          1082      auto mode
* 1            /usr/lib/jvm/java-7-oracle/bin/javac          1082      manual mode
  2            /usr/lib/jvm/java-8-openjdk-amd64/bin/javac   1081      manual mode
  3            /usr/lib/jvm/java-8-oracle/bin/javac          1081      manual mode

Press enter to keep the current choice[*], or type selection number: 1

unsw@unsw-UX303UB$ sudo update-alternatives --config java
There are 4 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                            Priority   Status
------------------------------------------------------------
  0            /usr/lib/jvm/java-7-oracle/jre/bin/java          1082      auto mode
* 1            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1071      manual mode
  2            /usr/lib/jvm/java-7-oracle/jre/bin/java          1082      manual mode
  3            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      manual mode
  4            /usr/lib/jvm/java-8-oracle/jre/bin/java          1081      manual mode

Press enter to keep the current choice[*], or type selection number: 1


unsw@unsw-UX303UB$ javac -version
javac 1.7.0_80

unsw@unsw-UX303UB$ java -version
java version "1.7.0_121"
OpenJDK Runtime Environment (IcedTea 2.6.8) (7u121-2.6.8-1ubuntu0.14.04.3)
OpenJDK 64-Bit Server VM (build 24.121-b00, mixed mode)
ubuntu14.14, jdk 1.7.x

 

Next: how to implement multi-nft,start with linux verison.

posted @ 2017-02-22 13:57  郝壹贰叁  阅读(1563)  评论(0编辑  收藏  举报