Para melhorar o desempenho no Raspberry Pi, é possível utilizar a linguagem C++ e bibliotecas optimizadas para acelerar o cálculo dos modelos de deteção de objectos. É isto que o TensorFlow Lite oferece.
Um bom ponto de partida é o sítio Web QEngineering.
Hardware
- Raspberry Pi 4
- Ecrã+rato+teclado
- Cartão SD com o sistema operativo Raspbian 64bits
Configuração
Para obter o melhor desempenho, é necessário instalar a versão de 64 bits do Raspberry Pi OS. Esta versão está disponível no software Raspberry Pi Imager no menu Raspberry Pi OS (outros).

Instalando o Code::Blocks
O IDE de blocos de código é um software como o Thonny ou o Geany que permite compilar e executar código escrito em C
sudo apt-get install codeblocks
Instalando o OpenCV para Cpp
Para instalar a versão Cpp do OpenCV, usamos a ferramenta apt-get
sudo apt-get install libopencv-dev
Instalando o TensorFlow Lite no Raspberry Pi OS 64bits
Para obter o melhor desempenho no Raspberry Pi, uma solução é usar a versão Lite do TensorFlow. Por favor, siga o procedimento descrito no site da QEngineering para instalar o TensorFlow Lite no Raspberry Pi OS 64bits.
N.B.: não se esqueça de reiniciar o Raspberry Pi depois de instalar o tensorflow.
Código de deteção de objectos
Pode descarregar o código e o projeto no Github da QEngineering
O modelo é construído a partir do ficheiro tflite. Neste projeto, utilizamos o MobileNet V1
std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromFile("detect.tflite");
Em seguida, abra um fluxo de vídeo (ou um ficheiro de vídeo ou imagem)
VideoCapture cap(0);
O modelo é então executado em cada imagem
interpreter->Invoke();
Por fim, traçamos os resultados da deteção na imagem e apresentamo-los.
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <opencv2/highgui.hpp>
#include <fstream>
#include <iostream>
#include <opencv2/core/ocl.hpp>
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/string_util.h"
#include "tensorflow/lite/model.h"
#include <cmath>
using namespace cv;
using namespace std;
const size_t width = 300;
const size_t height = 300;
std::vector<std::string> Labels;
std::unique_ptr<tflite::Interpreter> interpreter;
static bool getFileContent(std::string fileName)
{
// Open the File
std::ifstream in(fileName.c_str());
// Check if object is valid
if(!in.is_open()) return false;
std::string str;
// Read the next line from File untill it reaches the end.
while (std::getline(in, str))
{
// Line contains string of length > 0 then save it in vector
if(str.size()>0) Labels.push_back(str);
}
// Close The File
in.close();
return true;
}
void detect_from_video(Mat &src)
{
Mat image;
int cam_width =src.cols;
int cam_height=src.rows;
// copy image to input as input tensor
cv::resize(src, image, Size(300,300));
memcpy(interpreter->typed_input_tensor<uchar>(0), image.data, image.total() * image.elemSize());
interpreter->SetAllowFp16PrecisionForFp32(true);
interpreter->SetNumThreads(4); //quad core
// cout << "tensors size: " << interpreter->tensors_size() << "\n";
// cout << "nodes size: " << interpreter->nodes_size() << "\n";
// cout << "inputs: " << interpreter->inputs().size() << "\n";
// cout << "input(0) name: " << interpreter->GetInputName(0) << "\n";
// cout << "outputs: " << interpreter->outputs().size() << "\n";
interpreter->Invoke(); // run your model
const float* detection_locations = interpreter->tensor(interpreter->outputs()[0])->data.f;
const float* detection_classes=interpreter->tensor(interpreter->outputs()[1])->data.f;
const float* detection_scores = interpreter->tensor(interpreter->outputs()[2])->data.f;
const int num_detections = *interpreter->tensor(interpreter->outputs()[3])->data.f;
//there are ALWAYS 10 detections no matter how many objects are detectable
// cout << "number of detections: " << num_detections << "\n";
const float confidence_threshold = 0.5;
for(int i = 0; i < num_detections; i++){
if(detection_scores[i] > confidence_threshold){
int det_index = (int)detection_classes[i]+1;
float y1=detection_locations[4*i ]*cam_height;
float x1=detection_locations[4*i+1]*cam_width;
float y2=detection_locations[4*i+2]*cam_height;
float x2=detection_locations[4*i+3]*cam_width;
Rect rec((int)x1, (int)y1, (int)(x2 - x1), (int)(y2 - y1));
rectangle(src,rec, Scalar(0, 0, 255), 1, 8, 0);
putText(src, format("%s", Labels[det_index].c_str()), Point(x1, y1-5) ,FONT_HERSHEY_SIMPLEX,0.5, Scalar(0, 0, 255), 1, 8, 0);
}
}
}
int main(int argc,char ** argv)
{
float f;
float FPS[16];
int i, Fcnt=0;
Mat frame;
chrono::steady_clock::time_point Tbegin, Tend;
for(i=0;i<16;i++) FPS[i]=0.0;
// Load model
std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromFile("detect.tflite");
// Build the interpreter
tflite::ops::builtin::BuiltinOpResolver resolver;
tflite::InterpreterBuilder(*model.get(), resolver)(&interpreter);
interpreter->AllocateTensors();
// Get the names
bool result = getFileContent("COCO_labels.txt");
if(!result)
{
cout << "loading labels failed";
exit(-1);
}
VideoCapture cap("James.mp4");
if (!cap.isOpened()) {
cerr << "ERROR: Unable to open the camera" << endl;
return 0;
}
cout << "Start grabbing, press ESC on Live window to terminate" << endl;
while(1){
// frame=imread("Traffic.jpg"); //need to refresh frame before dnn class detection
cap >> frame;
if (frame.empty()) {
cerr << "ERROR: Unable to grab from the camera" << endl;
break;
}
Tbegin = chrono::steady_clock::now();
detect_from_video(frame);
Tend = chrono::steady_clock::now();
//calculate frame rate
f = chrono::duration_cast <chrono::milliseconds> (Tend - Tbegin).count();
if(f>0.0) FPS[((Fcnt++)&0x0F)]=1000.0/f;
for(f=0.0, i=0;i<16;i++){ f+=FPS[i]; }
putText(frame, format("FPS %0.2f", f/16),Point(10,20),FONT_HERSHEY_SIMPLEX,0.6, Scalar(0, 0, 255));
//show output
// cout << "FPS" << f/16 << endl;
imshow("RPi 4 - 1,9 GHz - 2 Mb RAM", frame);
char esc = waitKey(5);
if(esc == 27) break;
}
cout << "Closing the camera" << endl;
destroyAllWindows();
cout << "Bye!" << endl;
return 0;
}
Os resultados deste código mostram a deteção de objectos a uma velocidade entre 10 e 20 FPS, mas com baixa precisão neste exemplo.

É necessário realizar um estudo com outros exemplos e modelos, mas este projeto mostra o interesse do C++ e do Tensorflow Lite para a deteção de objectos no Raspberry Pi.