簡體   English   中英

構建OpenCV for Android並將其與NDK一起使用

[英]Building OpenCV for Android and using it with the NDK

背景:我目前正在Android Studio上為Moverio BT 200增強現實眼鏡開發應用程序。 我正在使用OpenCV,特別是庫的arUco模塊。 該模塊必須與NDK一起使用。 此外,它不在穩定版本上,所以我自己編譯了庫(使用本指南: https//zami0xzami.wordpress.com/2016/03/17/building-opencv-for-android-from-source/ ) 。 圖書館的建設進展順利。 之后,我做了一個android studio項目(customOCVtest)。 我在使用OpenCV與Android Studio和NDK時總是這樣做,除了這次使用自定義構建。 我檢查了庫是否正確加載:

private static final String OCVdevTAG = "OCVmainAct";

static {
    System.loadLibrary("native-lib");
    if(!OpenCVLoader.initDebug()) {
        Log.d(OCVdevTAG, "OpenCV not loaded");
    } else {
        Log.d(OCVdevTAG, "OpenCV loaded");
    }
}

我構建時確實加載了庫。

現在出現了問題:當我嘗試在我的本機代碼中實際使用arUco模塊時(這是我的native-lib.cpp):

#include <jni.h>
#include <string>
#include <opencv2/aruco.hpp>

extern "C" {
jstring
Java_com_jambonsama_customocvtest_MainActivity_stringFromJNI(
    JNIEnv *env,
    jobject /* this */) {
std::string hello = "Hello from C++";
cv::Ptr<cv::aruco::Dictionary> dict = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::Mat marker;
cv::aruco::drawMarker(dict, 25, 200, marker, 1);
return env->NewStringUTF(hello.c_str());
}
}

gradle sync工作,但我無法構建。 我收到以下錯誤:

Error:FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:externalNativeBuildDebug'.
> Build command failed.
Error while executing 'C:\Users\JambonSama\AppData\Local\Android\Sdk\cmake\3.6.3155560\bin\cmake.exe' with arguments {--build C:\Users\JambonSama\AndroidStudioProjects\customOCVtest\app\.externalNativeBuild\cmake\debug\mips64 --target native-lib}
[1/1] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\debug\obj\mips64\libnative-lib.so
FAILED: cmd.exe /C "cd . && C:\Users\JambonSama\AppData\Local\Android\sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe  -target mips64el-none-linux-android -gcc-toolchain C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64 --sysroot=C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/platforms/android-21/arch-mips64 -fPIC -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -fno-exceptions -fno-rtti -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -fno-exceptions -fno-rtti  -O0 -fno-limit-debug-info -O0 -fno-limit-debug-info  -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libnative-lib.so -o ..\..\..\..\build\intermediates\cmake\debug\obj\mips64\libnative-lib.so CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o  C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_aruco.a -llog -lm "C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/mips64/libgnustl_static.a" && cd ."
C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
  C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
  C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
  C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
  C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
  C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
  C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
  C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
  C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
  C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a: error adding symbols: File in wrong format
  clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
  ninja: build stopped: subcommand failed.


* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

特別是,此錯誤消息告訴我,我嘗試使用以下參數進行構建:

{--build C:\Users\JambonSama\AndroidStudioProjects\customOCVtest\app\.externalNativeBuild\cmake\debug\mips64 --target native-lib}

該參數由AS自動生成,我找不到傳遞它的文件。 我相信,如果我能找到它,我可以為手臂(這是我想要的)而不是mips建造。 問題是,我找不到它。 (而且我甚至不確定那確實是我正在尋找的。我只是想讓我的項目為我的眼鏡而建。)

以下是我的CMakeLists.txt:

# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             # Associated headers in the same location as their source
             # file are automatically included.
             src/main/cpp/native-lib.cpp )

include_directories(C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/jni/include)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.


target_link_libraries( # Specifies the target library.
                       native-lib
                       C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a
                       C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_aruco.a

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

這是我的app build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.1"
    defaultConfig {
        applicationId "com.jambonsama.customocvtest"
        minSdkVersion 14
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
    sourceSets { main { jni.srcDirs = ['src/main/jni', 'src/main/jniLibs/'] } }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.0.1'
    testCompile 'junit:junit:4.12'
    compile project(':openCVLibrary310dev')
}

和我的openCVLibrary310dev build.gradle

apply plugin: 'com.android.library'

android {
    compileSdkVersion 25
    buildToolsVersion "23.0.2"

    defaultConfig {
        ndk {
            abiFilter("armeabi-v7a")
        }
        minSdkVersion 14
        targetSdkVersion 25
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}

我嘗試過的,主要是復制那些幫助其他人解決類似地雷問題的東西:

#set(CMAKE_SYSTEM_NAME Android)

要么

#set(CMAKE_TOOLCHAIN_FILE "Toolchain file" CACHE FILEPATH "C:/Libs/opencv_src/opencv/platforms/android.toolchain.cmake")

要么

#set( CMAKE_CXX_COMPILER "C:/Libs/android-ndk-r13b/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/bin/arm-linux-androideabi-g++.exe" )

在CMakeLists.txt中

splits {
    abi {
        enable true
        reset()
        include 'armeabi-v7a'
        universalApk true
    }
}

要么

tasks.getByPath(":app:linkMipsDebugRemoteDesktopSharedLibrary").enabled = false

在build.gradle中(我試過這兩個因為我不知道哪一個應該擁有它)。

除了最后一點代碼(task.getByPath ...),同步工作,但我無法構建。 對於最后一個,我甚至無法同步。

我也嘗試為mips重建庫,因為架構似乎是問題,但我不知道如何做到這一點。

我在哪里可以找到以下參數所在的文件:

{--build C:\Users\JambonSama\AndroidStudioProjects\customOCVtest\app\.externalNativeBuild\cmake\debug\mips64 --target native-lib}

建築時通過? 和/或如何讓Android Studio構建我的arm架構項目?

所以mips架構問題可以通過在android塊的末尾添加以下代碼到app的gradle.build來解決:

productFlavors {
    armv7 {
        ndk {
            abiFilter "armeabi-v7a"
        }
    }
    fat
}

但隨后出現了其他問題。 值得注意的是,該庫是使用Android Studio不喜歡的胡蘿卜素選項構建的,然后,gzlib錯過了,因此Android Studio無法構建和/或運行。 經過多次試驗,我終於實現了我的目標:在Windows上交叉編譯openCV與Android的額外模塊,並使用所述內置庫構建AS項目以使其正常工作 我記錄了我的整個過程,從下載openCV源代碼直到在我的arm-architected設備上運行我的應用程序,我只是將它粘貼到這里,以便任何需要這樣做的人。 以下說明主要基於本教程 (感謝編寫它的Zamrath Nizam)。 該教程唯一的問題是它可能有點舊,所以需要改變一些選項/步驟。

來自WINDOWS的Android安裝模塊的交叉編譯OPENCV

*第一:先決條件*

  • 下載OpenCV並解壓縮(例如在'../opencv-source')
  • 下載OpenCV額外模塊並解壓縮(比如'../opencv-contrib-source')
  • 下載Android NDK(比如'../ndk-dir')
  • 下載CMake(說'../cmake-dir')和MinGW(說'../mingw-dir')
  • 安裝Android Studio

* SECOND:配置CMake *

  • 轉到'../opencv-source/platforms'並創建一個名為'build_android_arm'的文件夾
  • 在CMake中,使用以下路徑填充以下前兩個字段:
    1. 源代碼在哪里:'../ opencv-source'
    2. 在哪里構建二進制文件:'../ opencv-source / platform / build_android_arm'
  • 通過“添加條目”添加以下選項:
    1. ANDROID_NDK,輸入'path',值'../ndk-dir'
    2. ANDROID_NDK_HOST_X64,輸入'bool',值為1
    3. CMAKE_TOOLCHAIN_FILE,輸入'path',value'../opencv-source/platforms/android/android.toolchain.cmake'
  • 按'配置'
  • 選擇'MinGW Makefiles'作為編譯器
  • 選擇“指定工具鏈文件以進行交叉編譯”
  • 按'下一步',然后'完成'
    • 注1:只要你沒有錯誤信息,一切都很好。 不要擔心警告消息(比如CMake告訴你你正在做舊事)。
    • 注意2:如果您無法在該步驟進行配置,請嘗試閱讀接下來的幾點,這可能有所幫助。
  • 通過“搜索”字段更改以下附加選項:

    1. EXTRA_MODULE_PATH,輸入'path',value'../opencv-contrib-source/modules'
    2. WITH_CAROTENE,輸入'bool',值為0
    3. BUILD_ZLIB,輸入'bool',值為1
      • 注意:您必須在此步驟之前已經配置一次,因為之前創建的變量在“未分組條目”組下重新分組,而以下變量是CMake自動生成的變量,並且需要在正確的組中進行分組(不是'未分組的條目')。
  • 驗證是否正確設置了以下選項(通過“搜索”字段):

    1. ANDROID_NDK_HOST_X64,輸入'bool',值為1
    2. CMAKE_MAKE_PROGRAM,輸入'path',值'../mingw-dir/bin/mingw32-make.exe'。 這個選項,我實際上沒有在我的CMake配置中。 如果你按“配置”,它不起作用你沒有這個選項,那么你應該嘗試添加它(但我不知道如何)。 如果按“配置”時沒有任何問題,請不要擔心該變量。 此檢查來自上面鏈接的原始教程。
    3. CMAKE_TOOLCHAIN_FILE,輸入'path',value'../opencv-source/platforms/android/android.toolchain.cmake'
  • 按'配置'

  • 選擇'MinGW Makefiles'作為編譯器
  • 選擇“指定工具鏈文件以進行交叉編譯”
  • 按'下一步',然后'完成'
  • 按'生成'

*第三:用mingw *編譯

  • 轉到'../mingw-dir/msys/1.0'並運行'msys'bash文件
  • 導航到'../opencv-source/platforms/android_arm'
  • 運行'mingw32-make'命令
  • 運行'mingw32-make install'命令

*第四個:android項目*

  • 啟動Android Studio並創建一個新項目:
    1. 選擇文件 - >新建 - >新建項目...
    2. 用'cOCV'填寫'應用程序名稱'
    3. 選中“包括C ++支持”框
    4. 點擊下一步'
    5. 選擇你的最小SDK(比方說API 14:Android 4.0(IceCreamSandwich))
    6. 點擊“下一步”,“下一步”和“完成”
  • 轉到文件 - >新建 - >導入模塊...

    1. 提供'../opencv-source/platforms/android_arm/install/sdk/java'
    2. 點擊“下一步”和“完成”
  • 更改openCVLibraryXXX(導入模塊)文件夾中build.gradle文件中的目標:

    1. compileSdkVersion和targetSdkVersion應該相同,大於或等於23
    2. minSdkVersioon應與創建項目時指定的相同
  • 在openCVLibraryXXX(導入的模塊)文件夾中的build.gradle文件中:

    1. 將'apply plugin:com.android.application'替換為'apply plugin:com.android.library'
    2. 刪除行'applicationId'org.opencv“'
      • 注意:完成最后一步是為了避免出現以下錯誤:'未指定項目應用程序解析為不支持作為編譯依賴項的APK存檔'。
  • 將導入的庫作為依賴項添加到文件 - >'項目結構'中的'app'模塊

  • 在'app / src / main'中創建一個jniLibs文件夾:

    1. 右鍵單擊左側菜單中Android視圖中的“app”
    2. 單擊“新建文件夾-JNI文件夾”
    3. 檢查'更改文件夾位置'
    4. 將'Target Source Set'設置為'app / src / main / jniLibs'
  • 將OpenCV的庫從'opencv-source / platforms / android_arm / install / sdk / native / libs'復制到'AndroidStudioProjects / cOCV / app / src / main / jniLibs'文件夾中新創建的文件夾(jniLibs)中

    • 注意:例如,我的AndroidStudioProjects文件夾位於'C:\\ Users \\ JambonSama \\ AndroidStudioProjects'。
  • 在'opencv-contrib-source / modules / module_you_desperately_need / CMakeLists.txt'中,更改'ocv_define_module(module_you_desperately_need opencv opencv)以及'ocv_define_module(module_you_desperately_need opencv,其他一些模塊WRAP java)'

    • 注1:這個步驟可能是無用的,因為WRAP java可能已經寫在文件中了。
    • 注意2:如果'python'也被寫入,那就沒問題,你可以把它寫在原來的位置。
  • 在CMakeLists.txt中,添加:

    1. 'add_library'塊之后和'find_library'塊之前的以下兩行:

        include_directories(../opencv_src/opencv/platforms/build_android_armn/install/sdk/native/jni/include) link_directories(../AndroidStudioProjects/cOCVn/app/src/main/jniLibs/armeabi-v7a) 
      • 注意:這兩行非常直接地給出了include和link目錄的路徑
    2. 'find_library'塊之后和'target_link_libraries'塊之后的以下行:

        file(GLOB PARTYLIBS "../opencv_src/opencv/platforms/build_android_armn/install/sdk/native/3rdparty/libs/armeabi-v7a/*.a") file(GLOB CVLIBS "../opencv_src/opencv/platforms/build_android_armn/install/sdk/native/libs/armeabi-v7a/*.a") 
      • 注意:這些是為了更簡單的鏈接命令,請參閱下一點。
    3. 以下路徑,AS WRITTEN,在'target_link_libraries'中,在'native-lib'變量之后,在'$ {log-lib}'變量之前:

        ${CVLIBS} ${PARTYLIBS} ${CVLIBS} 
      • 注意:這是棘手的部分:由於周期性依賴,你必須再次編寫CVLIBS,PARTYLIBS和CVLIBS,否則你不會停止鏈接錯誤。 到現在為止,一切都應該聯系起來。
  • 在app的gradle.build中,添加以下代碼:

      productFlavors { armv7 { ndk { abiFilter "armeabi-v7a" } } fat } 

    在android塊的末尾

    • 注意:這可以通過指定一次和所有arm架構來防止構建時出現mips64體系結構錯誤
  • 在native-lib.cpp中:

    1. 在'stringFromJNI'函數中嘗試以下代碼(這個函數在創建項目時由AS自動生成)

        cv::Mat test; cv::VideoCapture camera; camera.open(0); cv::Ptrcv::aruco::Dictionary dict = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); cv::Mat marker; cv::aruco::drawMarker(dict, 25, 200, marker, 1); std::string hello = "Hello from C++"; return env-NewStringUTF(hello.c_str()); 
    2. 不要忘記以下內容包括:

        #include jni.h #include string #include opencv2/aruco.hpp #include opencv2/videoio.hpp 
      • 注意:因為在函數結束之前沒有生成字符串,所以,當你測試時,如果字符串確實顯示在屏幕上,那么該函數已經完成而沒有問題,並且你很好(因為上面提供的代碼使用了一些不在穩定版本上的模塊,截至2016年12月12日(12月8日,我用dd / mm / yyyy格式寫日期)。
  • 時間來測試:

    1. 同步gradle
    2. 建立
    3. 在一個手臂設備上運行

你很高興\\ o \\\\ O // o /

補充筆記 :

  • 所有gradle.build文件和CMakeLists.txt文件都可以在AS窗口左側菜單中的Android View上輕松找到。
  • 請記住,如果您在命令窗口中導航時出現錯誤,可能您的'/'應為'\\'或反之亦然。 ('cd'命令在命令窗口中導航)。
  • 我在Windows10上運行。
  • 如果你不太確定你應該在屏幕上逐步看到什么,我在答案開頭提到的教程應該會讓你知道在AS項目創建之前你應該看到什么。 然后,您可以看一下本教程該教程解釋了如何在Android Studio項目中為官方發布設置OpenCV SDK。 我提供的步驟與這些教程不同,但我把它們放在這里,因為它們可以幫助您了解屏幕/窗口應該是什么樣子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM