下载liveMedia库。解压完成可以先在linux环境下编译一遍试试,例如:

./genMakefiles macosx
make

然后,可以利用ndk-build将它交叉编译成动态库。这时候,需要新建一个Android.mk和Application.mk文件:

  • Application.mk
APP_BUILD_SCRIPT := Android.mk
APP_STL := gnustl_shared
APP_ABI := armeabi-v7a
  • Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := liblive555
LOCAL_CPPFLAGS += -fexceptions -DXLOCALE_NOT_USED=1 -DNULL=0 -DNO_SSTREAM=1 -UIP_ADD_SOURCE_MEMBERSHIP -DSOCKLEN_T=socklen_t

LOCAL_C_INCLUDES := \
    $(LOCAL_PATH) \
    $(LOCAL_PATH)/BasicUsageEnvironment/include \
    $(LOCAL_PATH)/UsageEnvironment/include \
    $(LOCAL_PATH)/groupsock/include \
    $(LOCAL_PATH)/liveMedia/include \

LOCAL_SRC_FILES := \
    BasicUsageEnvironment/BasicHashTable.cpp         \
        ...(这里把其他cpp、c文件都列到这里)

include $(BUILD_SHARED_LIBRARY)

然后执行ndk-build进行编译:

ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk

编译完成就可以得到libgnustl_shared.so liblive555.so了。

如题,本文将记录如何在安卓上调用OpenCV。

导入OpenCV动态库

首先当然是下载OpenCV for Android了,然后使用Android Studio创建一个工程并勾选C++ support。

然后,把OpenCV-android-sdk里面的native目录拷贝到工程中,例如app/opencv这个目录,需要修改以下文件:

  • app/build.gradle
android {
....
sourceSets {
        main {
            jniLibs.srcDirs = ['opencv/libs']
        }
    }
}

这样做的目的是为了打包的时候能自动将opencv/libs/{arch}/libopencv_java3.so这个文件打包到我们的apk中。

  • app/CMakeList.txt
set(opencv "${CMAKE_SOURCE_DIR}/opencv")
include_directories(${opencv}/jni/include)
add_library(libopencv_java3 SHARED IMPORTED )
set_target_properties(libopencv_java3 PROPERTIES
                      IMPORTED_LOCATION "${opencv}/libs/${ANDROID_ABI}/libopencv_java3.so")

target_link_libraries( # Specifies the target library.
                       native-lib
                       libopencv_java3
                       ${log-lib} )

这里把opencv作为动态库链接到工程中,并添加了包含目录,否则在编译cpp的时候会找不到opencv的头文件。

导入OpenCV Jaba Module

把opencv sdk下面的java目录作为一个module导入到工程中,并设置app依赖此module,这样就可以在工程中使用opencv提供的java接口了。我们来做一个相机:

public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2

这里首先实现CvCameraViewListener2接口,来实现相机的处理。

    private CameraBridgeViewBase cameraView;

    private BaseLoaderCallback loaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:
                    cameraView.enableView();
                    break;
                default:
                    super.onManagerConnected(status);
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.requestPermissions();

        this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_main);
        this.cameraView = (CameraBridgeViewBase) this.findViewById(R.id.cameraView);
        this.cameraView.setVisibility(SurfaceView.VISIBLE);
        this.cameraView.setCvCameraViewListener(this);
    }

在create的时候,我们申请权限,然后设置相机view的监听为自身。

    @Override
    public void onCameraViewStarted(int width, int height) {
    }

    @Override
    public void onCameraViewStopped() {
    }

相机启动停止我们不需要做别的操作。

    @Override
    protected void onResume() {
        super.onResume();
        if (!OpenCVLoader.initDebug())
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, this.loaderCallback);
        else
            this.loaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
    }

相机继续的时候,我们重新加载OpenCV库。

    @Override
    public void onPause() {
        super.onPause();
        if (this.cameraView != null)
            this.cameraView.disableView();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (this.cameraView != null)
            this.cameraView.disableView();
    }

暂停和销毁的时候,我们把相机禁用掉。

    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
        Mat frame = inputFrame.rgba();
        Core.rotate(frame, frame, Core.ROTATE_90_CLOCKWISE);
        return frame;
    }

这是关键的一步,处理相机的一帧。我们队图像进行了旋转,否则图像的坐标和我们的预期的是不一致的。注意在OpenCV3.2的时候,引入了便捷的rotate函数,如果用之前的方法,可能需要flip和reverse来实现了。

private void requestPermissions() {
        int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        if (permissionCheck == PackageManager.PERMISSION_GRANTED)
            return;

        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.CAMERA},
                0);

    }

最后是权限的动态申请。当然了,在AndroidManifest.xml中也需要进行设置,我们直接贴代码了:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.riguz.okapia">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />

    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
    <uses-feature android:name="android.hardware.camera.front" />
    <uses-feature android:name="android.hardware.camera.front.autofocus" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

参考:Use OpenCV to show camera on android App with correct orientation

作为一个全栈程序员,掌握多种主流语言无疑是求生的一大技能,实际上,很多语言都有很类似甚至一样的地方,因此学会一门语言再学其他语言就简单的多。然而现在编程语言已经够多了,还不断有新的语言在被发明,这么多语言学到死也学不完....关键是,估计学了也不见得会用到。

这些年学过的语言也不少了,刚开始大学学C++,然后学了点C#和Java,还有Python,Lua,然后工作基本上在用Java。这些语言我觉得都还挺好的,直到开始学Scala,语法不是一般的多,陆陆续续看了几次现在又都忘了,很多语法糖什么的,如果不是工作用我觉得很难学会...后来Javascript,也是听蛋疼的,shell更不用说了。Swift我直接放弃了,Objective-c直接看都不想看,好吧,我觉得现在我对语言一点都不感冒了,真的,想回头用C++。

然而C++也不断各种语法出来了,跟不上脚步。唯有C,貌似语法简单,这么多年也没什么变化,所以,准备开始来重新学习C吧。