1# iOS quickstart 2 3This tutorial provides a simple iOS mobile application to classify images using 4the iOS device camera. In this tutorial, you will download the demo application 5from the Tensorflow repository, build it on your computer, and install it on 6your iOS Device. You will also learn how to customize the application to suit 7your requirements. 8 9## Prerequisites 10 11* You must have [Xcode](https://developer.apple.com/xcode/) installed and have 12 a valid Apple Developer ID, and have an iOS device set up and linked to your 13 developer account with all of the appropriate certificates. For these 14 instructions, we assume that you have already been able to build and deploy 15 an app to an iOS device with your current developer environment. 16 17* The demo app requires a camera and must be executed on a real iOS device. 18 You can build it and run with the iPhone Simulator but it won't have any 19 camera information to classify. 20 21* You don't need to build the entire TensorFlow library to run the demo, but 22 you will need to clone the TensorFlow repository if you haven't already: 23 24 git clone https://github.com/tensorflow/tensorflow 25 cd tensorflow 26 27* You'll also need the Xcode command-line tools: 28 29 xcode-select --install 30 31 If this is a new install, you will need to run the Xcode application once to 32 agree to the license before continuing. 33 34* Install CocoaPods if you don't have it: 35 36 sudo gem install cocoapods 37 38### Step 1. Clone the TensorFlow source code 39 40First, we clone the GitHub repository on the computer in a folder to get the 41demo application. 42 43``` 44git clone https://github.com/tensorflow/tensorflow 45``` 46 47### Step 2. Download required dependencies 48 49Execute the shell script to download the model files used by the demo app (this 50is done from inside the cloned directory): 51 52``` 53 tensorflow/lite/examples/ios/download_models.sh 54``` 55 56Run the following command to install TensorFlow Lite pod: 57 58``` 59 cd tensorflow/lite/examples/ios/camera 60 pod install 61``` 62 63If you have installed this pod before and that command doesn't work, try 64 65``` 66 pod repo update 67``` 68 69### Step 3. Build the XCode project 70 71Open the `tflite_camera_example.xcworkspace` project file generated in the last 72step: 73 74``` 75 open tflite_camera_example.xcworkspace 76``` 77 78Under `Project navigator -> tflite_camera_example -> Targets -> 79tflite_camera_example -> General` change the bundle identifier by pre-pending 80your name: 81 82![pre-pend your name to the bundle identifier](../images/ios/bundle_identifier.png) 83 84Plug in your iOS device. Note the app must be executed with a real device with 85camera. Select the iOS device from the drop-down menu. 86 87![Device selection](../images/ios/device_selection.png) 88 89Click the "Run" button to build and run the app 90 91![Build and execute](../images/ios/build_and_execute.png) 92 93Note that as mentioned earlier, you must already have a device set up and linked 94to your Apple Developer account in order to deploy the app on a device. 95 96You'll have to grant permissions for the app to use the device's camera. Point 97the camera at various objects and enjoy seeing how the model classifies things! 98 99## Understanding iOS App Code 100 101### Get camera input 102 103The main logic of this app is in the Objective C++ source file 104`tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm`. 105 106The `setupAVCapture` method constructs a `AVCaptureSession` and set itself as a 107delegate. The `captureOutput:didOutputSampleBuffer:fromConnection:` method is 108called for every captured frame. It calls `runModelOnFrame` to run the model for 109every frame. 110 111### Create an interpreter 112 113To create the interpreter, we need to load the model file. The following code 114will load a model and create an interpreter. 115 116``` 117model = tflite::FlatBufferModel::BuildFromFile([graph_path UTF8String]); 118``` 119 120Behind the scenes, the model is loaded as a memory-mapped file. It offers faster 121load times and reduce the dirty pages in memory. 122 123Construct a `BuiltinOpResolver` to use the TensorFlow Lite buildin ops. Then, 124create the interpreter object using `InterpreterBuilder` that takes the model 125file as argument as shown below. 126 127``` 128tflite::ops::builtin::BuiltinOpResolver resolver; 129tflite::InterpreterBuilder(*model, resolver)(&interpreter); 130``` 131 132### Obtain the input buffer 133 134By default, the app uses quantized model since it's smaller and faster. The 135buffer is a raw pointer to an array of 8 bit unsigned integers (`uint8_t`). The 136following code obtains the input buffer from the interpreter: 137 138``` 139// Get the index of first input tensor. 140int input_tensor_index = interpreter->inputs()[0]; 141// Get the pointer to the input buffer. 142uint8_t* buffer = interpreter->typed_tensor<uint8_t>(input_tensor_index); 143``` 144 145Throughout this document, it's assumed a quantized model is used. 146 147### Pre-process of bitmap image 148 149The MobileNet model we're using takes 224x224x3 inputs, where the dimensions are 150width, height, and colors (RGB). The images returned from `AVCaptureSession` is 151bigger, and has 4 color channels (RGBA). 152 153Many image classification models (like MobileNet) take fixe-sized inputs. It's 154required to scale or crop the image before feeding it into the model, and change 155the channels from RGBA to RGB. 156 157The code to pre-process the images is in `ProcessInputWithQuantizedModel` 158function in 159`tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm`. It's a 160simple implementation for nearest neighbor color sampling, and it only copies 161the first 3 bytes for each pixel. 162 163``` 164void ProcessInputWithQuantizedModel( 165 uint8_t* input, uint8_t* output, int image_width, int image_height, int image_channels) { 166 for (int y = 0; y < wanted_input_height; ++y) { 167 uint8_t* out_row = output + (y * wanted_input_width * wanted_input_channels); 168 for (int x = 0; x < wanted_input_width; ++x) { 169 const int in_x = (y * image_width) / wanted_input_width; 170 const int in_y = (x * image_height) / wanted_input_height; 171 uint8_t* in_pixel = input + (in_y * image_width * image_channels) + (in_x * image_channels); 172 uint8_t* out_pixel = out_row + (x * wanted_input_channels); 173 for (int c = 0; c < wanted_input_channels; ++c) { 174 out_pixel[c] = in_pixel[c]; 175 } 176 } 177 } 178} 179``` 180 181Note the code is preprocessing and preparing the model input from the camera 182data. Therefore the first parameter `input` should be the camera buffer. The 183second parameter `output` should be the buffer of model input. 184 185### Run inference and obtain output buffer 186 187After preprocessing and filling the data into the input buffer of the 188interpreter, it's really easy to run the interpreter: 189 190``` 191if (interpreter->Invoke() != kTfLiteOk) { 192 NSLog("Failed to invoke!"); 193} 194``` 195 196The result is stored in the output tensor buffer of the interpreter. The 197following code obtains the pointer to the buffer: 198 199``` 200// Get the index of first output tensor. 201const int output_tensor_index = interpreter->outputs()[0]; 202// Get the pointer to the output buffer. 203uint8_t* buffer = interpreter->typed_tensor<uint8_t>(output_tensor_index); 204``` 205 206### Post-process values 207 208The output buffer contains an array of `uint8_t`, and the value range is 0-255. 209We need to convert the value to float to get the probabilities with value range 2100.0-1.0. The formula of the quantization value mapping is: 211 212 float_value = (quantized_value - zero_point) * scale 213 214The following code converts quantized values back to float values, using the 215quantizaiton parameters in tensors: 216 217``` 218uint8_t* quantized_output = interpreter->typed_output_tensor<uint8_t>(0); 219int32_t zero_point = input_tensor->params.zero_point; 220float scale = input_tensor->params.scale; 221float output[output_size]; 222for (int i = 0; i < output_size; ++i) { 223 output[i] = (quantized_output[i] - zero_point) * scale; 224} 225``` 226 227Finally, we find the best set of classifications by storing them in a priority 228queue based on their confidence scores. See the `GetTopN` function in 229`tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm`. 230