{"id":43689,"date":"2023-09-06T07:07:50","date_gmt":"2023-09-06T05:07:50","guid":{"rendered":"https:\/\/www.inovex.de\/?p=43689"},"modified":"2023-09-06T10:54:09","modified_gmt":"2023-09-06T08:54:09","slug":"android-snapdragon-integration-tensor-interpretation-with-kotlin","status":"publish","type":"post","link":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/","title":{"rendered":"Android Snapdragon Integration &#038; Tensor Interpretation with Kotlin"},"content":{"rendered":"<p>During a recent tech spike, we had the opportunity to evaluate the integration of the Qualcomm <a href=\"https:\/\/developer.qualcomm.com\/qualcomm-robotics-rb5-kit\/software-reference-manual\/machine-learning\/snpe\" target=\"_blank\" rel=\"noopener\">Snapdragon SDK<\/a>\u00a0(SNPE) in an Android\/Kotlin environment. The spike was divided into two segments where we first integrated \u2013 and second, used the Snapdragon SDK for object detection on images. This article helps to understand the complexity of Snapdragon SDK and learn how to convert an output tensor to drawable bounding boxes with Kotlin.<!--more--><\/p>\n<p>The following image shows the Snapdragon\u00a0training pipeline for providing the required .dlc files (see [1]). This .dlc file contains the trained model based on the <a href=\"https:\/\/paperswithcode.com\/dataset\/pascal-voc\" target=\"_blank\" rel=\"noopener\">Pascal data set<\/a>\u00a0and needs to be added to the Android project.<\/p>\n<p><figure style=\"width: 1000px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-1-2-1024x523.png\" alt=\"depiction of a training pipeline\" width=\"1000\" height=\"511\" \/><figcaption class=\"wp-caption-text\">Image [1]: Training pipeline<\/figcaption><\/figure>The underlying story of the tech spike has been:<\/p>\n<p>\u201cAs a user, I want to detect a cat on an image with an Android app, in order to classify the cat\u201c.<\/p>\n<p>We did start with a simple Android test app, which loaded a data test set of images and integrated the Snapdragon SDK. The test app should simply get images and detect a cat on it (see [2]).<\/p>\n<p><figure style=\"width: 1000px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-app.png\" alt=\"pictures of different animals and a smartphone that detects one of the pictures as a cat picture\" width=\"1000\" height=\"376\" \/><figcaption class=\"wp-caption-text\">Image [2]: Use Case<\/figcaption><\/figure>Therefore we began with a simple app with an instrumented test that loads an image and a trained model. As the spike demands we are supposed to use the Snapdragon SDK. The Snapdragon provides a neural network, which can be fed with an input tensor. In our case, this input tensor is a converted image. Afterward, we can interpret the neural network output tensor, as soon as the neural network responded.<\/p>\n<p>From here on we are able to integrate the conversion algorithm. Before we go deeper into the algorithm it is recommended to take a moment and refresh some terminology.\u00a0Since the manual conversion of a neural network output tensor requires a specific knowledge of the used terminology, it is recommended to read through the following short glossary:<\/p>\n<h2>Definitions<\/h2>\n<p>model:<\/p>\n<ul>\n<li>In the context of this article, a model refers to a single-stage real-time object detection model, provided by a .dlc file. (<a href=\"https:\/\/paperswithcode.com\/method\/yolov2\" target=\"_blank\" rel=\"noopener\">source<\/a>)<\/li>\n<\/ul>\n<p>config:<\/p>\n<ul>\n<li>A config refers to a data class to collect all meta-data that are required by the algorithm.<\/li>\n<\/ul>\n<p>tensor:<\/p>\n<ul>\n<li>A tensor is a (n) dimensional array of values. (<a href=\"https:\/\/mathworld.wolfram.com\/Tensor.html\" target=\"_blank\" rel=\"noopener\">source<\/a>)<\/li>\n<\/ul>\n<p>logit:<\/p>\n<ul>\n<li>The vector of raw (non-normalized) predictions that a classification model generates, is ordinarily then passed to a normalization function.\u00a0(<a href=\"https:\/\/developers.google.com\/machine-learning\/glossary?hl=de#logits\" target=\"_blank\" rel=\"noopener\">source<\/a>)<\/li>\n<\/ul>\n<p><strong>Functions<\/strong><\/p>\n<p>sigmoid:<\/p>\n<ul>\n<li>Is a logistic s-shaped curve, with its limits between 0 \u2192 1. (<a href=\"https:\/\/deepai.org\/machine-learning-glossary-and-terms\/sigmoid-function\" target=\"_blank\" rel=\"noopener\">source<\/a>)<\/li>\n<\/ul>\n<p>soft-max:<\/p>\n<ul>\n<li>Is a function that turns an array with values into an array with values that sums to one.\u00a0(<a href=\"https:\/\/deepai.org\/machine-learning-glossary-and-terms\/softmax-layer\" target=\"_blank\" rel=\"noopener\">source<\/a>)<\/li>\n<\/ul>\n<p>non-max-suppression:<\/p>\n<ul>\n<li>Non-Max-Suppression is a computer vision method that selects a single entity out of many overlapping entities. (<a href=\"https:\/\/paperswithcode.com\/method\/non-maximum-suppression\" target=\"_blank\" rel=\"noopener\">source<\/a>)<\/li>\n<\/ul>\n<h2>Integration of the\u00a0Snapdragon SDK<\/h2>\n<p>Now we can start with the integration of the Snapdragon SDK into the Android app, in order to use the neural network for object detection. See below links to the Snapdragon SDK and a helpful tutorial provided by Qualcomm.<\/p>\n<p>Download\u00a0 <a href=\"https:\/\/developer.qualcomm.com\/qualcomm-robotics-rb5-kit\/software-reference-manual\/machine-learning\/snpe\" target=\"_blank\" rel=\"noopener\">SNPE Release<\/a><\/p>\n<p>Follow \u00a0\u00a0 \u00a0\u00a0 <a href=\"https:\/\/developer.qualcomm.com\/sites\/default\/files\/docs\/snpe\/android_tutorial.html\" target=\"_blank\" rel=\"noopener\">SNPE Android Tutorial<\/a><\/p>\n<h3>Setup<\/h3>\n<ul>\n<li>Add root level lib\/ directory.<\/li>\n<li>Update lib\/ with .aar SNPE Release.<\/li>\n<li>Update lib\/ with .aar Platform-Validator.<\/li>\n<li>Update src\/res\/raw with a trained model file (.dlc).<\/li>\n<li>Update AndroidManifest.xml<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-manifest-1.png\" alt=\"\" width=\"752\" height=\"53\" \/><\/p>\n<ul>\n<li>App packagingOptions in build.gradle<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-gradle.png\" alt=\"\" width=\"747\" height=\"451\" \/><\/p>\n<h3>Build the neural network<\/h3>\n<p>Load a model (.dlc) from the Android resource directory (res\/) and build the neural network as shown in below code fragment:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-build-neural-network.png\" alt=\"\" width=\"1000\" height=\"333\" \/><\/p>\n<h2>Interpretation of a\u00a0Snapdragon tensor<\/h2>\n<p>In order to use the SNPE neural network, we have to prepare the environment by loading a model and defining its parameters. Later we will use this config to set the necessary parameters for the algorithm which converts the Snapdragon output tensor. It is crucial that the type of the loaded model (for example<strong>\u00a0yoloV2.dlc<\/strong>) is mapped to the model configuration. Otherwise, the conversion will fail, since parameters like <strong>gridSize<\/strong> or <strong>cellSize<\/strong> have a major impact on the conversion algorithm.<\/p>\n<h3>Model configuration<\/h3>\n<p>The below example wraps all the parameters in a configuration file, which is used for the algorithm.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-yolo-config-1.png\" alt=\"\" width=\"1000\" height=\"791\" \/><\/p>\n<p>A typical YoloV2 configuration would use the following setup:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-yolo-config-2.png\" alt=\"\" width=\"1000\" height=\"411\" \/><\/p>\n<h3>Snapdragon input tensor setup<\/h3>\n<p>Since the main goal is to draw a list of boxes on an image that contains a cat object, we need to abstract this functionality. Starting at step one of the following code snippets we implemented this abstraction within a single function.<\/p>\n<p>1.<strong> Execute the neural network and return a list of boxes<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-43859\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-bet-boxes.png\" alt=\"\" width=\"1000\" height=\"482\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-bet-boxes.png 751w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-bet-boxes-300x145.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-bet-boxes-400x193.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-bet-boxes-360x174.png 360w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/p>\n<p>2. <strong>Transform the given image to a float array of normalized RGB values in order to create the input tensor:\u00a0<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-43862\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-get-rgb.png\" alt=\"\" width=\"1000\" height=\"232\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-get-rgb.png 755w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-get-rgb-300x70.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-get-rgb-400x93.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-get-rgb-360x83.png 360w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/p>\n<p>3. <strong>Get the grid and convert the output tensor to a list of boxes<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-43958\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-cinfig-grid.png\" alt=\"\" width=\"1000\" height=\"159\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-cinfig-grid.png 1000w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-cinfig-grid-300x48.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-cinfig-grid-768x122.png 768w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-cinfig-grid-400x64.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-cinfig-grid-360x57.png 360w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/p>\n<p>From here on all interfaces are defined. In order to keep things simple, we implemented several extensions for transforming arrays or converting a tensor. Follow along with the next chapter to get the idea of converting the output tensor to a list of boxes.<\/p>\n<h3>Output tensor conversion<\/h3>\n<p>Before we dive into the code base for converting a <a href=\"https:\/\/developer.qualcomm.com\/sites\/default\/files\/docs\/snpe\/overview.html\" target=\"_blank\" rel=\"noopener\">SNPE Neural Network<\/a> output tensor you should recap the underlying model. For this example we used <strong>YoloV2<\/strong>. A basic introduction can be found <a href=\"https:\/\/github.com\/zzxvictor\/YOLO_Explained\" target=\"_blank\" rel=\"noopener\">here<\/a> or in the original paper <a href=\"https:\/\/arxiv.org\/pdf\/1506.02640.pdf\" target=\"_blank\" rel=\"noopener\">here<\/a>. The conversion of the neural network output tensor, which is based on a YoloV2 model, is divided into four main steps (see [3]).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-3.png\" alt=\"\" width=\"1000\" height=\"98\" \/><\/p>\n<p>Image [3[: General steps to convert an output-tensor<\/p>\n<p>The following code snippets should inspire future implementations for tensor conversions in Kotlin. At the time we published this article, the conversion outputs from <strong>YoloV2<\/strong> and <strong>YoloV5<\/strong> models were implemented and tested.<\/p>\n<p>1. <strong>Create boxes from grid and config:<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-43871\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes.png\" alt=\"\" width=\"1000\" height=\"627\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes.png 831w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes-300x188.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes-768x482.png 768w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes-400x251.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes-360x226.png 360w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/p>\n<p>2.1<strong> Create a box from an anchor box:<\/strong><\/p>\n<p>In order not to blow up this article we excluded some of the simple function implementations like scaling coordinates, soft-max, or non-max-suppression.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-43873\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes-from-anchor.png\" alt=\"\" width=\"1000\" height=\"579\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes-from-anchor.png 889w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes-from-anchor-300x174.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes-from-anchor-768x445.png 768w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes-from-anchor-400x232.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-boxes-from-anchor-360x209.png 360w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/p>\n<p>2.2<strong> Create a box Instance from a filtered anchor box:<\/strong><\/p>\n<p>The given starting index, here 5, points to a defined object class. This object class or namely \u201clogit\u201c is defined by the loaded model. In our case, the logit class name is <em>cat<\/em>, since we are only interested in cat objects. But there could be more logits, depending on the use case.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-box.png\" alt=\"\" width=\"1000\" height=\"162\" \/><\/p>\n<p>2.3 <strong>Extract a logit from the given anchor box starting at the given index:\u00a0<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-logit-1.png\" alt=\"\" width=\"1000\" height=\"140\" \/><\/p>\n<p>2.4 U<strong>se the soft-max algorithm to normalize the output of a network to a probability distribution over the given array:<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-softmax.png\" alt=\"\" width=\"1000\" height=\"159\" \/><\/p>\n<p>2.5 <strong>Create the box instance:<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-single-box.png\" alt=\"\" width=\"1000\" height=\"350\" \/><\/p>\n<p><strong>where a box is a pure Kotlin data class.<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-data-class-box.png\" alt=\"\" width=\"1000\" height=\"216\" \/><\/p>\n<p>3. <strong>Filter boxes by non-max-suppression:<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-filter.png\" alt=\"\" width=\"1000\" height=\"218\" \/><\/p>\n<h3>Draw boxes around the object<\/h3>\n<p>At this point, we have returned a filtered list of boxes from the <strong>createBoxes<\/strong> Function (see Output Tensor Conversion I). What remains is to draw the best box on the initial given image.<\/p>\n<p>1.<strong> Draw box:<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-draw.png\" alt=\"\" width=\"1000\" height=\"156\" \/><\/p>\n<p>2.<strong> Create a box shape:<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-create-shape.png\" alt=\"\" width=\"1000\" height=\"384\" \/><\/p>\n<h2>Lessons learned<\/h2>\n<p>The above implementation leads to a list of boxes. The best box is drawn into the canvas of the given image (see [4]).<\/p>\n<p><figure style=\"width: 1000px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Android-Developer-Story-4.png\" alt=\"two identical pictures of the same cat. one picture has a framed cat with a 99% sign.\" width=\"1000\" height=\"374\" \/><figcaption class=\"wp-caption-text\">Image [4]: Input \u2192 Output<\/figcaption><\/figure>Finally implementing an algorithm to convert a Snapdragon neural network output tensor has been a challenge across all touched domains. On the machine learning side, we had to follow through with the algorithm and all its details in filtering, etc. However, on the app side, we started the implementation from scratch and prepared multiple test sets for running simple Android instrumented tests on given images. While implementing the algorithm we used a more test-driven development approach, which has been more suitable during the process.<\/p>\n<ul>\n<li>Communication between the domain developers is crucial for the successful implementation.<\/li>\n<li>Understanding the domain helped a lot while implementing the algorithm.<\/li>\n<li>The model abstraction in a config file helped to scale with other Yolo versions.<\/li>\n<li>Unnoticed corrupted test data sets make testing quite hard.<\/li>\n<li>A test is just as good as its test data set.<\/li>\n<li>The Snapdragon SDK runs on DSP and is quite fast<\/li>\n<\/ul>\n<h6>Follow up<\/h6>\n<ul>\n<li><a href=\"https:\/\/www.inovex.de\/de\/blog\/machine-learning-on-the-edge-parking-guidance-systems\/\">object detection edge parking guidance<\/a><\/li>\n<li><a href=\"https:\/\/www.inovex.de\/de\/blog\/tracking-on-the-edge-a-case-study-on-real-time-object-tracking\/\">real-time object detection<\/a><\/li>\n<\/ul>\n<p>Image sources:<\/p>\n<ul>\n<li><a href=\"https:\/\/commons.wikimedia.org\/wiki\/Commons:Licensing\" target=\"_blank\" rel=\"noopener\">Wikipedia common license<\/a><\/li>\n<li><a href=\"https:\/\/pixabay.com\" target=\"_blank\" rel=\"noopener\">pixabay.com<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>During a recent tech spike, we had the opportunity to evaluate the integration of the Qualcomm Snapdragon SDK\u00a0(SNPE) in an Android\/Kotlin environment. The spike was divided into two segments where we first integrated \u2013 and second, used the Snapdragon SDK for object detection on images. This article helps to understand the complexity of Snapdragon SDK [&hellip;]<\/p>\n","protected":false},"author":97,"featured_media":47303,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"ep_exclude_from_search":false,"footnotes":""},"tags":[149,372,511,150,353,365,218,366],"service":[420,76,436],"coauthors":[],"class_list":["post-43689","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-android","tag-app","tag-artificial-intelligence-2","tag-computer-vision","tag-mobile","tag-mobile-device","tag-model-deployment","tag-object-detection","service-apps","service-artificial-intelligence","service-computer-vision"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Android Snapdragon Integration &amp; Tensor Interpretation with Kotlin<\/title>\n<meta name=\"description\" content=\"Understand the complexity of Snapdragon SDK and learn how to convert an output tensor to drawable bounding boxes with Kotlin.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Android Snapdragon Integration &amp; Tensor Interpretation with Kotlin\" \/>\n<meta property=\"og:description\" content=\"Understand the complexity of Snapdragon SDK and learn how to convert an output tensor to drawable bounding boxes with Kotlin.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/\" \/>\n<meta property=\"og:site_name\" content=\"inovex GmbH\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/inovexde\" \/>\n<meta property=\"article:published_time\" content=\"2023-09-06T05:07:50+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-09-06T08:54:09+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Tino Kallinich-Friedrich\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1-1024x576.png\" \/>\n<meta name=\"twitter:creator\" content=\"@mx_tino\" \/>\n<meta name=\"twitter:site\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tino Kallinich-Friedrich\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"6\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/\"},\"author\":{\"name\":\"Tino Kallinich-Friedrich\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/fcabd1e46229e68364e666b6732ff86f\"},\"headline\":\"Android Snapdragon Integration &#038; Tensor Interpretation with Kotlin\",\"datePublished\":\"2023-09-06T05:07:50+00:00\",\"dateModified\":\"2023-09-06T08:54:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/\"},\"wordCount\":1299,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1.png\",\"keywords\":[\"Android\",\"App\",\"Artificial Intelligence\",\"Computer Vision\",\"Mobile\",\"Mobile Device\",\"Model Deployment\",\"Object Detection\"],\"articleSection\":[\"Applications\",\"General\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/\",\"url\":\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/\",\"name\":\"Android Snapdragon Integration & Tensor Interpretation with Kotlin\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1.png\",\"datePublished\":\"2023-09-06T05:07:50+00:00\",\"dateModified\":\"2023-09-06T08:54:09+00:00\",\"description\":\"Understand the complexity of Snapdragon SDK and learn how to convert an output tensor to drawable bounding boxes with Kotlin.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#primaryimage\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1.png\",\"width\":1920,\"height\":1080,\"caption\":\"A cube with the kotlin and snapdragon logos on its sides casting a shadow\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.inovex.de\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Android Snapdragon Integration &#038; Tensor Interpretation with Kotlin\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.inovex.de\/de\/#website\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"name\":\"inovex GmbH\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.inovex.de\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\",\"name\":\"inovex GmbH\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"width\":1921,\"height\":1081,\"caption\":\"inovex GmbH\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/inovexde\",\"https:\/\/x.com\/inovexgmbh\",\"https:\/\/www.instagram.com\/inovexlife\/\",\"https:\/\/www.linkedin.com\/company\/inovex\",\"https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/fcabd1e46229e68364e666b6732ff86f\",\"name\":\"Tino Kallinich-Friedrich\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/163197d5916185dd18c854751cbd8b08\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/cropped-profil-small-96x96.jpg\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/cropped-profil-small-96x96.jpg\",\"caption\":\"Tino Kallinich-Friedrich\"},\"description\":\"B.Sc. Informatik and B.Sc. Nautik\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/tino-k-friedrich\/\",\"https:\/\/x.com\/mx_tino\"],\"url\":\"https:\/\/www.inovex.de\/de\/blog\/author\/tkallinich-2-2-2-2-2\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Android Snapdragon Integration & Tensor Interpretation with Kotlin","description":"Understand the complexity of Snapdragon SDK and learn how to convert an output tensor to drawable bounding boxes with Kotlin.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/","og_locale":"de_DE","og_type":"article","og_title":"Android Snapdragon Integration & Tensor Interpretation with Kotlin","og_description":"Understand the complexity of Snapdragon SDK and learn how to convert an output tensor to drawable bounding boxes with Kotlin.","og_url":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/","og_site_name":"inovex GmbH","article_publisher":"https:\/\/www.facebook.com\/inovexde","article_published_time":"2023-09-06T05:07:50+00:00","article_modified_time":"2023-09-06T08:54:09+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1.png","type":"image\/png"}],"author":"Tino Kallinich-Friedrich","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1-1024x576.png","twitter_creator":"@mx_tino","twitter_site":"@inovexgmbh","twitter_misc":{"Verfasst von":"Tino Kallinich-Friedrich","Gesch\u00e4tzte Lesezeit":"6\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#article","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/"},"author":{"name":"Tino Kallinich-Friedrich","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/fcabd1e46229e68364e666b6732ff86f"},"headline":"Android Snapdragon Integration &#038; Tensor Interpretation with Kotlin","datePublished":"2023-09-06T05:07:50+00:00","dateModified":"2023-09-06T08:54:09+00:00","mainEntityOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/"},"wordCount":1299,"commentCount":0,"publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1.png","keywords":["Android","App","Artificial Intelligence","Computer Vision","Mobile","Mobile Device","Model Deployment","Object Detection"],"articleSection":["Applications","General"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/","url":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/","name":"Android Snapdragon Integration & Tensor Interpretation with Kotlin","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#primaryimage"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1.png","datePublished":"2023-09-06T05:07:50+00:00","dateModified":"2023-09-06T08:54:09+00:00","description":"Understand the complexity of Snapdragon SDK and learn how to convert an output tensor to drawable bounding boxes with Kotlin.","breadcrumb":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#primaryimage","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/snapdragon-integration-tensor-interpretation-1.png","width":1920,"height":1080,"caption":"A cube with the kotlin and snapdragon logos on its sides casting a shadow"},{"@type":"BreadcrumbList","@id":"https:\/\/www.inovex.de\/de\/blog\/android-snapdragon-integration-tensor-interpretation-with-kotlin\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.inovex.de\/de\/"},{"@type":"ListItem","position":2,"name":"Android Snapdragon Integration &#038; Tensor Interpretation with Kotlin"}]},{"@type":"WebSite","@id":"https:\/\/www.inovex.de\/de\/#website","url":"https:\/\/www.inovex.de\/de\/","name":"inovex GmbH","description":"","publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.inovex.de\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/www.inovex.de\/de\/#organization","name":"inovex GmbH","url":"https:\/\/www.inovex.de\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","width":1921,"height":1081,"caption":"inovex GmbH"},"image":{"@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/inovexde","https:\/\/x.com\/inovexgmbh","https:\/\/www.instagram.com\/inovexlife\/","https:\/\/www.linkedin.com\/company\/inovex","https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ"]},{"@type":"Person","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/fcabd1e46229e68364e666b6732ff86f","name":"Tino Kallinich-Friedrich","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/163197d5916185dd18c854751cbd8b08","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/cropped-profil-small-96x96.jpg","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/cropped-profil-small-96x96.jpg","caption":"Tino Kallinich-Friedrich"},"description":"B.Sc. Informatik and B.Sc. Nautik","sameAs":["https:\/\/www.linkedin.com\/in\/tino-k-friedrich\/","https:\/\/x.com\/mx_tino"],"url":"https:\/\/www.inovex.de\/de\/blog\/author\/tkallinich-2-2-2-2-2\/"}]}},"_links":{"self":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/43689","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/users\/97"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/comments?post=43689"}],"version-history":[{"count":8,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/43689\/revisions"}],"predecessor-version":[{"id":48910,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/43689\/revisions\/48910"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media\/47303"}],"wp:attachment":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media?parent=43689"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/tags?post=43689"},{"taxonomy":"service","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/service?post=43689"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/coauthors?post=43689"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}