一. 添加人工智能框架
1. TensorFlow 是一个关于机器学习和深度神经网络的开源库,而 TensorFlow Lite 是TensorFlow 针对移动和嵌入式设备的轻量化解决方案。因而首先我们将库的依赖关系到 build.gradle 的文件中,并重新同步 Gradle 的项目。
dependencies {
// TODO: ADD ARTIFICIAL INTELLIGENCE
implementation'org.tensorflow:tensorflow-lite:0.1.1'
}
2. 在主程序中调用TensorFlowLite,打开ImageClassifierActivity.java并对程序进行部分代码的添加。
首先添加从 assets 中的模型文件中执行初始化 TensorFlow Interpreter 的动作,并且使用 loadModelFile()的方法来辅助读取文件;使用 readLabels()的方法读取标签列表,并将神经网络结果关联到已经识别的名称或类别;
import org.tensorflow.lite.Interpreter;
public class ImageClassifierActivity extends Activity {
private static final String LABELS_FILE = "labels.txt";
private static final String MODEL_FILE = "mobilenet_quant_v1_224.tflite";
...
private Interpreter mTensorFlowLite;
private List<String> mLabels;
...
/**
* Initialize the classifier that will be used to process images.
*/
private void initClassifier() {
try {
mTensorFlowLite = new Interpreter(TensorFlowHelper.loadModelFile(this, MODEL_FILE));
mLabels = TensorFlowHelper.readLabels(this, LABELS_FILE);
} catch (IOException e) {
Log.w(TAG, "Unable to initialize TensorFlow Lite.", e);
}
}
/**
* Clean up the resources used by the classifier.
*/
private void destroyClassifier() {
mTensorFlowLite.close();
}
...
}
完成上述操作后,需要执行 doRecognize()的方法,当用户需要进行照片的识别时则调用此方法。它将图像作为一个参数并且运行 onPhotoRecognitionReady 的回调方法,并且其中包含一个识别项目列表,用于描述输入图像所识别的内容和每个结果的可信度;
public class ImageClassifierActivity extends Activity {
...
private void doRecognize(Bitmap image) {
// Allocate space for the inference results
byte[][] confidencePerLabel = new byte[1][mLabels.size()];
// Allocate buffer for image pixels.
int[] intValues = new int[TF_INPUT_IMAGE_WIDTH * TF_INPUT_IMAGE_HEIGHT];
ByteBuffer imgData = ByteBuffer.allocateDirect(
DIM_BATCH_SIZE * TF_INPUT_IMAGE_WIDTH * TF_INPUT_IMAGE_HEIGHT * DIM_PIXEL_SIZE);
imgData.order(ByteOrder.nativeOrder());
// Read image data into buffer formatted for the TensorFlow model
TensorFlowHelper.convertBitmapToByteBuffer(image, intValues, imgData);
// Run inference on the network with the image bytes in imgData as input,
// storing results on the confidencePerLabel array.
mTensorFlowLite.run(imgData, confidencePerLabel);
// Get the results with the highest confidence and map them to their labels
Collection<Recognition> results = TensorFlowHelper.getBestResults(confidencePerLabel, mLabels);
// Report the results with the highest confidence
onPhotoRecognitionReady(results);
}
...
}
2. 添加摄像机
我们需要添加一部分代码,去实现摄像头对外部环境的拍照,通过这样的操作后,你将可以把摄像头对准一个物体,通过对物体的拍照获得的照片,通过后台树莓派的运算,获得识别拍照物体同的准确度。
添加摄像机的权限
跟编译一个安卓程序一样,当我们需要调用到摄像机的接口时,需要在AndroidManifest.xml 中去设置用户权限。但同安卓程序不一样的是,当你添加了摄像机的权限后,在后期调用摄像机应用的时候,在 things 中将不会再询问用户是否开启摄像机权限。
<!-- TODO: ADD CAMERA SUPPORT -->
<uses-permission android:name="android.permission.CAMERA"/>
更新代码
在主程序中,我们需要添加代码去实现摄像机的连接和拍照功能。打开ImageClassifierActivity,并在程序中添加:
1. 添加摄像机的相关变量;
...
public class ImageClassifierActivity extends Activity {
...
private CameraHandler mCameraHandler;
private ImagePreprocessor mImagePreprocessor;
...
}
2. 更新initCamera()的方法以便它可以去初始化ImagePreprocessor和CameraHandler 的对象;
3. 当摄像机的图像准备好后调用OnImageAvailableListener。这个监听会调用ImagePreprocessor.preprocessImage()的方法,并将处理后的位图传给onPhoteReady(),它将位图重新传回到上部分所讲的图像识别方法。
4. 将新的监听器传递给CameraHandler.initializeCamera()。
/**
* Initialize the camera that will be used to capture images.
*/
private void initCamera() {
mImagePreprocessor = new ImagePreprocessor(PREVIEW_IMAGE_WIDTH, PREVIEW_IMAGE_HEIGHT,
TF_INPUT_IMAGE_WIDTH, TF_INPUT_IMAGE_HEIGHT);
mCameraHandler = CameraHandler.getInstance();
mCameraHandler.initializeCamera(this,
PREVIEW_IMAGE_WIDTH, PREVIEW_IMAGE_HEIGHT, null,
new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
Bitmap bitmap = mImagePreprocessor.preprocessImage(imageReader.acquireNextImage());
onPhotoReady(bitmap);
}
});
}
5. 最后调用closeCamera()和loadPhoto()两个方法去关闭摄像机并触发CameraHandler。
/**
* Clean up resources used by the camera.
*/
private void closeCamera() {
mCameraHandler.shutDown();
}
/**
* Load the image that will be used in the classification process.
* When done, the method {@link #onPhotoReady(Bitmap)} must be called with the image.
*/
private void loadPhoto() {
mCameraHandler.takePicture();
}
6. 完成上述操作后,就可以将程序安装到我们的开发板中,去验证我们设计的程序,当你按下按钮时,摄像头将会把拍摄到的物体进行识别并在屏幕上提示识别的物体名称。