在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

詳解Object Detection Demo的移植

谷歌開發者 ? 來源:Android高效開發 ? 2025-02-05 13:42 ? 次閱讀

以下文章來源于Android高效開發,作者2BAB

本文作者 /Android 谷歌開發者專家 El Zhang (2BAB)

繼上一篇移植了 Mediapipe 的 LLM Inference 后,這篇文章我們將繼續探索 Object Detection Demo 的移植。通過本文你將了解到:

移植 Mediapipe 的 Object Detection Android 官方 Demo 到 KMP,支持在 iOS 上運行。項目地址:https://github.com/2BAB/MediaPiper/tree/object-detection

Compose Multiplatform 與 iOS 原生控件的集成與交互 (Camera Preview),包括權限申請。

在 KMP 使用依賴注入 iOS 控件的小技巧 (基于 Koin)。

該 Demo 里兩種 Object Detection 算法的簡單背景知識。

b4c30d28-da36-11ef-9310-92fbcf53809c.png ? ? ?

Object Detection Android Sample

首先,我們先打開 Object Detection 的原版工程,發現其 Android 部分既有 android.view.View 版本的實現,也有 Jetpack Compose 的版本。因此我們延續上一篇的方式,基于 Jetpack Compose 的版本直接移植到 KMP 上。

接著,仔細體驗該 App 會發現其復雜度更高。LLM Inference 中的 SDK 僅僅是提供文本的推理接口,可直接在 Kotlin 層封裝對應平臺的 SDK 方便抽象 (盡管因為一些 cinterop 支持原因我們最后用了備用方案),UI 上則完全復用。但 Object Detection 是基于圖像的實時處理,演示里涉及攝像頭實時檢測、本地視頻的檢測、本地圖片的檢測三種。攝像頭預覽的需求一般都強依賴于平臺實現,播放器在渲染層面也鮮有自繪 (即使用平臺 Native 方案)。

b4e07cd2-da36-11ef-9310-92fbcf53809c.png

小結,在開始設計時我們就得考慮把 Compose Multiplatform (CMP) 難以實現的部分留出 (例如上圖中的 CameraView),抽象成獨立的 expect Composable 函數留給兩端各自實現。而為了方便學習需減少 Demo 的規模,我們也決定只實現 CameraView 的部分,把 Gallery (Video+Image) 的部分留給大家去嘗試。實際上,只要掌握了 Camera Preview 的嵌入方法,其他兩部分也可以參照實現,包括 Compose 和 UiKit 的交互、iOS 權限申請等。

b4eda164-da36-11ef-9310-92fbcf53809c.png

結合 iOS 版的 Demo 交叉比對,我們把 CameraView 有關的 UI 層整理成了四個部分,如上圖所示。其中:

Camera Preview 層一定是交由兩端各自實現。

ResultOverlay 即各種結果的方框繪制,可以考慮在 Common 層實現,但涉及到其與 Camera Preview 的圖層匹配 (因 Camera Preview 的大小根據鏡頭的不同會有不同的比例選項)、坐標轉換,較為復雜,本次 Demo 繼續交由兩端各自實現。

Scaffold 和 Inference Time Label 在 Common 層實現。

移植流程

移植主體的 UI 和數據結構

我們在上一節的基礎上繼續在 Mediapiper 工程中增加一個新文件夾 objectdetection。有了上一節的經驗,我們發現其實很多 UI 的內容都不復雜——除了這節的重點,相機預覽界面。因此,我們可以先行把除了camera和 gallery的文件都移動過來:

b4ff8f82-da36-11ef-9310-92fbcf53809c.png

此處需要的修改分為兩塊:

數據和邏輯部分:

我們采集原來的 SDK 中的 ObjectDetectionResult 屬性聲明,創建了一個 Common 版本的 data class,也包括其用到的各種附屬類型。如此一來,兩邊的 SDK 返回結果都可以通過簡單轉換直接替換成 Common 版本的,不管是要顯示推理時間、統一采樣埋點,甚至為以后把ResultOverlay 搬來 Common 做好了準備。

一些工具類和默認值枚舉也被一并移至 Common 層,并且基本不需要修改,只要把推理結果的類置換成上述 Common 版本的。

UI 部分:

一些統一的修改和上一節完全相同,R引用改 Res,主題換成上一節統一的,一些簡單的 Import 包修改。

而特別的部分在于該 Demo 沒有使用 CMP 版本的 Navigation,所以在 Home 和 Option 頁面切換只是在頂層做了一個簡單的 if...else...。

至此已經可以運行一個不含相機功能的應用了,下圖演示了這些 CMP 代碼在 iOS 上運行時的兩個頁面。

b519b132-da36-11ef-9310-92fbcf53809c.jpg

集成 CameraView 功能

如上文分析我們需要拆除 CameraView 的部分用 Native 實現,因此在 Common 的 CameraView里我們使用了兩個 expect的 Composable 函數 CameraPermissionControl 和CameraPreview:

@Composable
fun CameraView(
   threshold: Float,
   maxResults: Int,
   delegate: Int,
   mlModel: Int,
   setInferenceTime: (newInferenceTime: Int) -> Unit,
) {
   CameraPermissionControl {
       CameraPreview(
           threshold,
           maxResults,
           delegate,
           mlModel,
           setInferenceTime,
           onDetectionResultUpdate = { detectionResults ->
              ...
           })
   }
}


@Composable
expect fun CameraPermissionControl(PermissionGrantedContent:  @Composable @UiComposable () -> Unit)
```kotlin
@Composable
expect fun CameraPreview(
   threshold: Float,
   maxResults: Int,
   delegate: Int,
   mlModel: Int,
   setInferenceTime: (newInferenceTime: Int) -> Unit,
   onDetectionResultUpdate: (result: ObjectDetectionResult) -> Unit
)

Android 側的 CameraView 實現

Android 端的實現十分簡單,直接將原有的 Jetpack Compose 代碼拷貝過來:

// Android implementation
@OptIn(ExperimentalPermissionsApi::class)
@Composable
actual fun CameraPermissionControl(
  PermissionGrantedContent:  @Composable @UiComposable () -> Unit) {   
   val storagePermissionState: PermissionState =
       rememberPermissionState(Manifest.permission.CAMERA)
   LaunchedEffect(key1 = Unit) {
       if (!storagePermissionState.hasPermission) {
           storagePermissionState.launchPermissionRequest()
       }
   }


   if (!storagePermissionState.hasPermission) {
       Text(text = "No Storage Permission!")
   } else {
       PermissionGrantedContent()
   }
}


@Composable
actual fun CameraPreview(...) {
   ... // Some properties' definition


   DisposableEffect(Unit) {
       onDispose {
           active = false;
           cameraProviderFuture.get().unbindAll()
       }
   }


   // Next we describe the UI of this camera view.
   BoxWithConstraints(..) {       
       val cameraPreviewSize = getFittedBoxSize(
           containerSize = Size(
               width = this.maxWidth.value,
               height = this.maxHeight.value,
           ),
           boxSize = Size(
               width = frameWidth.toFloat(),
               height = frameHeight.toFloat()
           )
       )


       Box(
           Modifier
               .width(cameraPreviewSize.width.dp)
               .height(cameraPreviewSize.height.dp),
       ) {
           // We're using CameraX to use the phone's camera, and since it doesn't have a prebuilt
           // composable in Jetpack Compose, we use AndroidView to implement it
           AndroidView(
               factory = { ctx ->                   
                   val previewView = PreviewView(ctx)
                   val executor = ContextCompat.getMainExecutor(ctx)
                   cameraProviderFuture.addListener({
                       val cameraProvider = cameraProviderFuture.get()
                       val preview = Preview.Builder().build().also {
                           it.setSurfaceProvider(previewView.surfaceProvider)
                       }


                       val cameraSelector = CameraSelector.Builder()
                           .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                           .build()


                       // We instantiate an image analyser to apply some transformations on the
                       // input frame before feeding it to the object detector
                       val imageAnalyzer =
                           ImageAnalysis.Builder()
                               .setTargetAspectRatio(AspectRatio.RATIO_4_3)
                               .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                               .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
                               .build()


                       // Now we're ready to apply object detection. For a better performance, we
                       // execute the object detection process in a new thread.
                       val backgroundExecutor = Executors.newSingleThreadExecutor()


                       backgroundExecutor.execute {


                           // To apply object detection, we use our ObjectDetectorHelper class,
                           // which abstracts away the specifics of using MediaPipe  for object
                           // detection from the UI elements of the app
                           val objectDetectorHelper =
                               AndroidObjectDetector(
                                   context = ctx,
                                   threshold = threshold,
                                   currentDelegate = delegate,
                                   currentModel = mlModel,
                                   maxResults = maxResults,                               
                                   objectDetectorListener = ObjectDetectorListener(
                                       onErrorCallback = { _, _ -> },
                                       onResultsCallback = {
                                           // On receiving results, we now have the exact camera
                                           // frame dimensions, so we set them here
                                           frameHeight = it.inputImageHeight
                                           frameWidth = it.inputImageWidth


                                           // Then we check if the camera view is still active,
                                           // if so, we set the state of the results and
                                           // inference time.
                                           if (active) {
                                               results = it.results.first()
                                               setInferenceTime(it.inferenceTime.toInt())
                                           }
                                       }
                                   ),
                                   runningMode = RunningMode.LIVE_STREAM
                               )


                           // Now that we have our ObjectDetectorHelper instance, we set is as an
                           // analyzer and start detecting objects from the camera live stream
                           imageAnalyzer.setAnalyzer(
                               backgroundExecutor,
                               objectDetectorHelper::detectLivestreamFrame
                           )
                       }


                       // We close any currently open camera just in case, then open up
                       // our own to be display the live camera feed
                       cameraProvider.unbindAll()
                       cameraProvider.bindToLifecycle(
                           lifecycleOwner,
                           cameraSelector,
                           imageAnalyzer,
                           preview
                       )
                   }, executor)
                   // We return our preview view from the AndroidView factory to display it
                   previewView
               },
               modifier = Modifier.fillMaxSize(),
           )


           // Finally, we check for current results, if there's any, we display the results overlay
           results?.let {
               ResultsOverlay(
                   results = it,
                   frameWidth = frameWidth,
                   frameHeight = frameHeight
               )
           }
       }
   }
}
iOS 側的 CameraView 實現

iOS 則稍微需要一些精力。對于相機權限控制,我們直接在這個 Composable 函數中調用 iOS 的 platform.AVFoundation相關 API,異步發起請求然后根據結果顯示加載中、失敗、或成功時直接顯示相機預覽。可以看到我們做的 iOS 實現已十分完善,考慮到了三個不同場景 :D

...
import platform.AVFoundation.AVAuthorizationStatusAuthorized
import platform.AVFoundation.AVAuthorizationStatusDenied
import platform.AVFoundation.AVAuthorizationStatusNotDetermined
import platform.AVFoundation.AVAuthorizationStatusRestricted
import platform.AVFoundation.AVCaptureDevice
import platform.AVFoundation.AVMediaTypeVideo
import platform.AVFoundation.authorizationStatusForMediaType
import platform.AVFoundation.requestAccessForMediaType
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine


@Composable
actual fun CameraPermissionControl(PermissionGrantedContent:  @Composable @UiComposable () -> Unit) {
   var hasCameraPermission by remember { mutableStateOf(null) }


   LaunchedEffect(Unit) {
       hasCameraPermission = requestCameraAccess()
   }


   when (hasCameraPermission) {
       true -> {
           PermissionGrantedContent()
       }
       false -> {
           Text("Camera permission denied. Please grant access from settings.")
       }
       null -> {
           Text("Requesting camera permission...")
       }
   }
}




private suspend fun requestCameraAccess(): Boolean = suspendCoroutine { continuation ->
   val authorizationStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)


   when (authorizationStatus) {
       AVAuthorizationStatusNotDetermined -> {
           AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo) { granted ->
               continuation.resume(granted)
           }
       }
       AVAuthorizationStatusRestricted, AVAuthorizationStatusDenied -> {
           continuation.resume(false)
       }
       AVAuthorizationStatusAuthorized -> {
           continuation.resume(true)
       }
       else -> {
           continuation.resume(false)
       }
   }
}

然后來到核心的相機預覽功能。從 CMP 的文檔中我們知道,使用 UIKitView 即可在 Composable 函數中嵌入一個 iOS 的 View。

// Example 1
UIKitView(
   factory = { MKMapView() },
   modifier = Modifier.size(300.dp),
)


// Example 2
@OptIn(ExperimentalForeignApi::class)
@Composable
fun UseUITextField(modifier: Modifier = Modifier) {
   var message by remember { mutableStateOf("Hello, World!") }
   UIKitView(
       factory = {
           val textField = object : UITextField(CGRectMake(0.0, 0.0, 0.0, 0.0)) {
               @ObjCAction
               fun editingChanged() {
                   message = text ?: ""
               }
           }
           textField.addTarget(
               target = textField,
               action = NSSelectorFromString(textField::editingChanged.name),
               forControlEvents = UIControlEventEditingChanged
           )
           textField
       },
       modifier = modifier.fillMaxWidth().height(30.dp),
       update = { textField ->
           textField.text = message
       }
   )
}

文檔 https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-uikit-integration.html

仔細觀察這兩個示例會發現其使用的都是默認 UIKit 控件,而非工程自定義的;對應的引用則是 JetBrains 提前轉換了相關的代碼接口到 Kotlin,例如 platform.UIKit.UITextField 默認可以導入到 KMP 工程的 iOS target。但對于我們的工程情況不太相同,我們想要復用的是一個帶有識別功能的自定義 CameraPreview 視圖。

b52c8b2c-da36-11ef-9310-92fbcf53809c.png

換個角度看,KMP 產出的 app.framework 是一個基礎共享層,iOS 原生代碼依賴于這個庫。從依賴關系上,我們無法直接調用 iOS App 源碼中的CamerePreview。解決方法也不難,一般分兩種:

把相關代碼打包成一個獨立模塊,產出 cameraview.freamework,讓app 依賴它。

iOS App 在初始化 app.framework 時,傳入一個 lambda 到app 用來初始化并返回一個UIView。

此處我們采用第二種方案,定義 IOSCameraPreviewCreator 作為兩側交互的協議。

// 定義
typealias IOSCameraPreviewCreator = (
   threshold: Float,
   maxResults: Int,
   delegate: Int,
   mlModel: Int,
   setInferenceTime: (newInferenceTime: Int) -> Unit,
   callback: IOSCameraPreviewCallback
) -> UIView


typealias IOSCameraPreviewCallback = (result: ObjectDetectionResult) -> Unit


// 在啟動時從 iOS 端傳入相關實現,并加入到 Koin 的 Definition
fun onStartup(iosCameraPreviewCreator: IOSCameraPreviewCreator) {
   Startup.run { koinApp ->
       koinApp.apply {
           modules(module {
               single { LLMOperatorFactory() }
               single { iosCameraPreviewCreator }
           })
       }
   }
}


// 回到 CameraPreview 的實現,我們只要執行注入,
// 并 invoke 這個函數獲得 UIView 實例。
...
import androidx.compose.ui.viewinterop.UIKitView
import platform.UIKit.UIView


@Composable
actual fun CameraPreview(
   threshold: Float,
   maxResults: Int,
   delegate: Int,
   mlModel: Int,
   setInferenceTime: (newInferenceTime: Int) -> Unit,
   onDetectionResultUpdate: (result: ObjectDetectionResult) -> Unit,
) {
   val iOSCameraPreviewCreator = koinInject()
   // 和 Android 端集成原生 Camera View 的方式有幾分相似
   UIKitView(
       factory = {
           val iosCameraPreview: UIView = iOSCameraPreviewCreator(
               threshold,
               maxResults,
               delegate,
               mlModel,
               setInferenceTime,
               onDetectionResultUpdate)
           iosCameraPreview
       },
       modifier = Modifier.fillMaxSize(),
       update = { _ -> }
   )
}

上述代碼使用 Koin 管理依賴簡化了流程。至此 CMP 的部分已經完成,我們順延啟動參數的注入去探究 iOS 的部分。

MainKt.onStartup(iosCameraPreviewCreator: { threshold, maxResults, delegate, mlModel, onInferenceTimeUpdate, resultCallback in
   return IOSCameraView.init(
       frame: CGRectMake(0, 0, 0, 0),
       modelName: Int(truncating: mlModel) == 0 ? "EfficientDet-Lite0" : "EfficientDet-Lite2",
       maxResults: Int(truncating: maxResults),
       scoreThreshold: Float(truncating: threshold),
       onInferenceTimeUpdate: onInferenceTimeUpdate,
       resultCallback: resultCallback
   )
})
該IOSCameraView 實際上即原 iOS Demo 中的 CameraViewController,我們僅修改一些初始化和生命周期的內容,并簡化掉了參數變化監聽的部分以突出核心遷移內容:

生命周期處理:ViewController 使用 viewDidLoad 等生命周期方法,UIView 則用 didMoveToWindow 處理視圖添加或移除時的邏輯。ViewController 通過生命周期管理初始化,而 UIView 提供自定義初始化方法來傳遞模型和檢測參數。

子視圖設置:ViewController 使用@IBOutlet 和 Interface Builder,而UIView 通過 setupView 方法直接創建并添加子視圖,手動使用 AutoLayout 設置約束以及手動設置點擊事件。

回調和委托:ViewController 使用委托,而 UIView 增加了回調閉包 onInferenceTimeUpdate 和resultCallback,初始化時傳入這些參數并設置好類型轉換,方便后面回調到 KMP 層。

b53f5356-da36-11ef-9310-92fbcf53809c.jpg

我們同時保留了OverlayView CameraFeedService ObjectDetectorService 和部分DefaultConstants,此處不對他們的代碼進行修改。其中ObjectDetectorService 即是對 Object Detection SDK 的封裝,如果觀察它的 API 調用,會發現其和 iOS 的 Camera API 緊密耦合 (CMSampleBuffer 等),說明了其難以在 Common 抽象,呼應了文初對 Camera 相關服務的分析。

b559f47c-da36-11ef-9310-92fbcf53809c.png

至此,我們就可以把 iOS 端的相機預覽加 Object Detection 也跑起來。

簡單測試

上方的動圖展示了 EfficientDet-Lite0 加 CPU 模式在 iPhone 13mini 執行的效果。官方使用 Pixel 6 CPU/GPU 的測試中,轉去 GPU 執行還能再小幅提高一些性能。不難看出,其實時性已足夠滿足生產環境的需求,同時在準確率方面表現尚可。

隨 Demo 工程搭載的可選模型有兩個:

EfficientDet-Lite0 模型使用 320x320 輸入,平衡了延遲和準確性,適合輕量級應用。Demo 中默認搭載了其 float 32 版本的模型。

EfficientDet-Lite2 模型使用 448x448 輸入,準確性更高,但速度較慢,適合對準確性要求更高的場景。Demo 中默認搭載了其 float 32 版本的模型。

這兩種模型均使用包含 150 萬個實例和 80 種物體標簽的訓練集進行訓練。

b5a39b4a-da36-11ef-9310-92fbcf53809c.png

總結

一些傳統的 ML 模型在移動設備上的應用已經相對成熟,可以應對不少單一和專途的場景。而本文的兩個模型亦只有 13~25MB,相比 LLM 的模型動輒 1GB 以上,這類模型完全沒有落地的負擔。

使用 Compose Multiplatform 內嵌 UiKit 的 View 可以解決很多高性能、需要原生 API 和硬件的情況。

為了盡可能還原 Demo 的效果同時減少遷移成本,ResultOverlay 在本次遷移中雖然已經放到 Common 層,且 iOS 側也已設置結果回調到 KMP,但 iOS 上依舊使用了原生 View 實現?,F實場景中,我們可進一步擴展思考:

倘若業務場景簡單,例如也是方框識別且全屏展示 camera preview,則可以在 Compose 層簡單復用ResultOverlay。

倘若業務場景復雜,例如視頻聊天時的人臉識別加貼圖選擇和渲染,因業務部分的高復雜度使得復用同一個 StickerOverlay 的價值非常高,這個情況下 Camera Preview 無論大小如何,適配成本反倒都可以接受。另外對于 StickerOverlay 的位置計算,理論上也存在優化的空間,例如采樣計算然后中間用插值動畫移動。

一些依賴管理的復雜場景包括 UI 視圖的注入,借助類似 Koin 依賴注入框架可大幅簡化。

這次遷移的部分還有相冊選擇、照片與視頻解析等等未實現,感興趣的朋友可以自行添加測試,像讀取權限申請、播放器 View 的嵌入和本文的遷移過程會非常類似。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Android
    +關注

    關注

    12

    文章

    3945

    瀏覽量

    128005
  • 攝像頭
    +關注

    關注

    60

    文章

    4871

    瀏覽量

    96392
  • 移植
    +關注

    關注

    1

    文章

    383

    瀏覽量

    28198
  • LLM
    LLM
    +關注

    關注

    0

    文章

    301

    瀏覽量

    411

原文標題:【GDE 分享】移植 Mediapipe Demo 到 Kotlin Multiplatform (2)

文章出處:【微信號:Google_Developers,微信公眾號:谷歌開發者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    【米爾百度大腦EdgeBoard邊緣AI計算盒試用連載】III. 板載深度學習DEMO-detection測試-上(ZMJ)

    參考README.md進行操作即可。進入build文件夾,攝像頭運行YOLOV3-DEMO指令:./video_detection ../configs/yolov3/screw.json
    發表于 04-02 19:56

    【米爾百度大腦EdgeBoard邊緣AI計算盒試用連載】III. 板載深度學習DEMO-detection測試-下(ZMJ)

    本帖最后由 卿小小_9e6 于 2021-4-11 16:16 編輯 【米爾百度大腦EdgeBoard邊緣AI計算盒試用連載】III. 板載深度學習DEMO-detection測試-下(ZMJ
    發表于 04-11 16:17

    STM32程序的移植詳解步驟

    一,概括程序的移植包括以下幾步1.觀察待移植程序調用了哪些文件,將這些文件放入移植的工程當中2.在keil當中添加這些文件,并且添加.h文件的路徑3.處理頭文件及軟件版本匹配的問題二,詳解
    發表于 08-23 07:27

    如何執行object_detection_demo.py以使用攝像頭作為對象檢測Python演示的輸入?

    執行命令: python3 object_detection_demo.py -m person-vehicle-bike-detection-2001.xml -at ssd -d MYRIAD
    發表于 08-15 06:28

    Java Object Serialization Spec

    Java Object Serialization SpecificationObject serialization in the Java™system is the process
    發表于 10-14 17:39 ?7次下載

    Object-Oriented Programming in

    This chapter applies a different programming paradigm to G: Object-Oriented Programming(OOP). New
    發表于 03-02 14:18 ?28次下載

    RTAI分析及在s3c4510上的移植詳解

    RTAI分析及在s3c4510上的移植詳解
    發表于 03-28 09:52 ?24次下載

    uCOSII在LPC2210上的移植詳解

    uCOSII在LPC2210上的移植詳解:嵌入式實時操作系統在目標處理器平臺上的移植是嵌入式軟件開發的基礎和前提。論文實現了源碼公開的嵌入式實時操作系統μC/OS- II 在ARM7 微控制器LPC2
    發表于 12-31 15:11 ?144次下載

    什么是CORBA (Common Object Reques

    什么是CORBA (Common Object Request Broker Architecture)  英文縮寫: CORBA (Common Object Request Broker Architecture) 中文譯名: 通用對象請求
    發表于 02-22 11:48 ?995次閱讀

    嵌入式Linux內核移植詳解(頂嵌)

    嵌入式內核移植步驟詳解 含配置含義及內容等方面
    發表于 11-20 16:00 ?19次下載

    《Linux設備驅動開發詳解》第23章、Linux設備驅動的移植

    《Linux設備驅動開發詳解》第23章、Linux設備驅動的移植
    發表于 10-27 10:58 ?9次下載
    《Linux設備驅動開發<b class='flag-5'>詳解</b>》第23章、Linux設備驅動的<b class='flag-5'>移植</b>

    Uboot移植步驟詳解

    Uboot移植步驟詳解
    發表于 10-30 08:46 ?21次下載
    Uboot<b class='flag-5'>移植</b>步驟<b class='flag-5'>詳解</b>

    uCOS_ARM移植要點詳解

    uCOS_ARM移植要點詳解
    發表于 10-31 11:25 ?11次下載
    uCOS_ARM<b class='flag-5'>移植</b>要點<b class='flag-5'>詳解</b>

    AM64x/AM243x多協議Demo搭建與詳解

    AM64x/AM243x多協議Demo搭建與詳解
    發表于 10-28 11:59 ?2次下載
    AM64x/AM243x多協議<b class='flag-5'>Demo</b>搭建與<b class='flag-5'>詳解</b>

    Object類中的所有方法

    Object 類屬于 java.lang 包,此包下的所有類在使用時無需手動導入,系統會在程序編譯期間自動導入。Object 類是所有類的基類,當一個類沒有直接繼承某個類時,默認繼承Object
    的頭像 發表于 10-13 11:50 ?598次閱讀
    <b class='flag-5'>Object</b>類中的所有方法
    主站蜘蛛池模板: 韩国三级hd | 毛片黄色 | 国产视频一二区 | 综合色亚洲 | 播放欧亚一级特黄录像 | 在线免费看视频 | 男人操女人视频在线观看 | 久色乳综合思思在线视频 | 黄色综合 | 天天久久综合 | 日本一区二区免费在线观看 | 爱爱免费| 亚洲一区二区三区精品视频 | 国产中日韩一区二区三区 | 94在线| 男男之h啪肉np文 | 可以免费看黄色的网站 | 欧美福利视频网 | 1024你懂的国产精品 | 久久九九色| 国产精品午夜久久久久久99热 | 色吧综合 | 天天射夜夜骑 | 久久青草精品一区二区三区 | 91视频免费观看 | 黄 色 录像成 人播放免费99网 | www.色涩涩.com| 日本三级最新中文字幕电影 | 久久精品久 | 视频网站黄 | 国产aaaaaa| 亚洲福利一区 | 中文天堂最新版www官网在线 | 亚洲人成人77777网站 | 成人在线精品 | 亚洲美女激情视频 | 天天插天天射天天操 | 色天使色婷婷在线影院亚洲 | 在线观看视频网站 | 亚洲乱淫 | 四虎影视免费 |