Add relocatable runtime and image rotation support

This commit is contained in:
Fabio 2026-09-25 11:14:51 +02:00
parent 647824fd26
commit 682147e51e
5 changed files with 359 additions and 23 deletions

View file

@ -13,7 +13,7 @@ CXXFLAGS := \
LDFLAGS := \
-L$(ROOT)/lib \
-Wl,-rpath,$(ROOT)/lib
-Wl,-rpath,'$$ORIGIN/../lib'
LDLIBS := \
-lrknnrt \

102
README1.md Normal file
View file

@ -0,0 +1,102 @@
cd /home/nvme/dockerdata/prove/face-clustering-rk3588
# Files e dir necessarie per far funzionare
prj_root/
├── bin/
│ └── face_scan
├── lib/
│ └── librknnrt.so
├── models/
│ ├── SCRFD_500M_KPS_640.rknn
│ └── face_recognition_sface_2021dec.rknn
└── test
└── test3f.jpg
### Copia
cd /home/nvme/dockerdata/prove/s121js || exit 1
mkdir -p bin lib models
cp -f \
/home/nvme/dockerdata/prove/face-clustering-rk3588/lib/librknnrt.so \
lib/
cp -f \
/home/nvme/dockerdata/prove/face-clustering-rk3588/models/SCRFD_500M_KPS_640.rknn \
models/
cp -f \
/home/nvme/dockerdata/prove/face-clustering-rk3588/models/face_recognition_sface_2021dec.rknn \
models/
### Compilazione
make clean
make -j"$(nproc)"
### Test delle quattro rotazioni
for rotation in 0 90 180 270; do
./bin/face_scan \
--rotation "$rotation" \
test/test3f.jpg \
> "/tmp/rotation_${rotation}.json" \
2> "/tmp/rotation_${rotation}.stderr"
status=$?
stderr_bytes=$(wc -c < "/tmp/rotation_${rotation}.stderr")
echo \
"rotation=$rotation" \
"status=$status" \
"stderr_bytes=$stderr_bytes"
done
### Verifica dimensioni, rotazione e volti
python3 - <<'PY'
import json
from pathlib import Path
for rotation in (0, 90, 180, 270):
json_path = Path(
"/tmp/rotation_"
+ str(rotation)
+ ".json"
)
data = json.loads(
json_path.read_text(encoding="utf-8")
)
image = data.get("image")
faces = data.get("faces")
if not isinstance(image, dict):
raise SystemExit(
"Campo image non valido per rotazione "
+ str(rotation)
)
if not isinstance(faces, list):
raise SystemExit(
"Campo faces non valido per rotazione "
+ str(rotation)
)
print(
"rotation:",
rotation,
"size:",
str(image.get("width"))
+ "x"
+ str(image.get("height")),
"json_rotation:",
image.get("rotation"),
"faces:",
len(faces),
)
PY

View file

@ -38,7 +38,8 @@ public:
const std::string& image_path,
std::vector<Face>& faces,
int& image_width,
int& image_height);
int& image_height,
int rotation_degrees = 0);
private:
struct Impl;

View file

@ -132,6 +132,108 @@ struct Image {
std::vector<uint8_t> rgb;
};
static bool normalize_rotation(
int rotation_degrees,
int& normalized_rotation)
{
int value = rotation_degrees % 360;
if (value < 0)
value += 360;
if (
value != 0
&& value != 90
&& value != 180
&& value != 270
) {
return false;
}
normalized_rotation = value;
return true;
}
static Image rotate_image(
const Image& source,
int rotation_degrees)
{
if (rotation_degrees == 0)
return source;
Image destination;
if (
rotation_degrees == 90
|| rotation_degrees == 270
) {
destination.w = source.h;
destination.h = source.w;
} else {
destination.w = source.w;
destination.h = source.h;
}
destination.rgb.resize(
static_cast<std::size_t>(destination.w)
* static_cast<std::size_t>(destination.h)
* 3);
for (int source_y = 0; source_y < source.h; ++source_y) {
for (int source_x = 0; source_x < source.w; ++source_x) {
int destination_x = 0;
int destination_y = 0;
switch (rotation_degrees) {
case 90:
destination_x = source.h - 1 - source_y;
destination_y = source_x;
break;
case 180:
destination_x = source.w - 1 - source_x;
destination_y = source.h - 1 - source_y;
break;
case 270:
destination_x = source_y;
destination_y = source.w - 1 - source_x;
break;
default:
destination_x = source_x;
destination_y = source_y;
break;
}
const std::size_t source_offset =
(
static_cast<std::size_t>(source_y)
* static_cast<std::size_t>(source.w)
+ static_cast<std::size_t>(source_x)
) * 3;
const std::size_t destination_offset =
(
static_cast<std::size_t>(destination_y)
* static_cast<std::size_t>(destination.w)
+ static_cast<std::size_t>(destination_x)
) * 3;
destination.rgb[destination_offset + 0] =
source.rgb[source_offset + 0];
destination.rgb[destination_offset + 1] =
source.rgb[source_offset + 1];
destination.rgb[destination_offset + 2] =
source.rgb[source_offset + 2];
}
}
return destination;
}
static bool load_image(const std::string& path, Image& img)
{
int c = 0;
@ -314,7 +416,6 @@ public:
(const uint16_t*)outputs[6 + level].buf;
int feat_w = SCRFD_SIZE / stride;
int feat_h = SCRFD_SIZE / stride;
for (int i = 0; i < count; ++i) {
float score = fp16_to_float(scores[i]);
@ -692,7 +793,8 @@ bool FaceEngine::process_image(
const std::string& image_path,
std::vector<Face>& faces,
int& image_width,
int& image_height)
int& image_height,
int rotation_degrees)
{
faces.clear();
image_width = 0;
@ -703,16 +805,33 @@ bool FaceEngine::process_image(
return false;
}
Image image;
int normalized_rotation = 0;
if (!load_image(image_path, image))
if (!normalize_rotation(
rotation_degrees,
normalized_rotation)) {
std::cerr
<< "Rotazione non valida: "
<< rotation_degrees
<< ". Valori ammessi: 0, 90, 180, 270\n";
return false;
}
Image source_image;
if (!load_image(image_path, source_image))
return false;
image_width = image.w;
image_height = image.h;
Image oriented_image = rotate_image(
source_image,
normalized_rotation);
image_width = oriented_image.w;
image_height = oriented_image.h;
faces = ::process_image(
image,
oriented_image,
impl_->detector,
impl_->recognizer);

View file

@ -1,15 +1,72 @@
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <filesystem>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include <unistd.h>
#include "face_engine.h"
#include "face_config.h"
static constexpr std::size_t EMBEDDING_SIZE = 128;
static std::filesystem::path executable_path()
{
std::vector<char> buffer(4096);
while (true) {
const ssize_t length = readlink(
"/proc/self/exe",
buffer.data(),
buffer.size() - 1);
if (length < 0) {
throw std::runtime_error(
"Impossibile leggere /proc/self/exe");
}
const std::size_t path_length =
static_cast<std::size_t>(length);
if (path_length < buffer.size() - 1) {
buffer[path_length] = '\0';
return std::filesystem::path(
buffer.data());
}
buffer.resize(buffer.size() * 2);
}
}
static std::filesystem::path application_root()
{
/*
* Struttura prevista:
*
* root/
* bin/face_scan
* lib/librknnrt.so
* models/<model>.rknn
*
* executable_path():
* root/bin/face_scan
*
* parent_path():
* root/bin
*
* parent_path().parent_path():
* root
*/
return executable_path()
.parent_path()
.parent_path();
}
static void write_json_string(const std::string& value)
{
std::cout << '"';
@ -165,23 +222,77 @@ static void write_face_json(
int main(int argc, char** argv)
{
if (argc != 2) {
int rotation_degrees = 0;
const char* image_path = nullptr;
if (argc == 2) {
image_path = argv[1];
} else if (
argc == 4
&& std::string(argv[1]) == "--rotation"
) {
char* parse_end = nullptr;
const long parsed_rotation = std::strtol(
argv[2],
&parse_end,
10);
if (
parse_end == argv[2]
|| *parse_end != '\0'
|| parsed_rotation < -360000
|| parsed_rotation > 360000
) {
std::cerr
<< "Rotazione non valida: "
<< argv[2]
<< "\n";
return 2;
}
rotation_degrees =
static_cast<int>(parsed_rotation);
image_path = argv[3];
} else {
std::cerr
<< "Uso: "
<< argv[0]
<< " image.jpg\n";
<< "Uso:\n"
<< " " << argv[0]
<< " image.jpg\n"
<< " " << argv[0]
<< " --rotation 90 image.jpg\n";
return 2;
}
const std::string root =
FACE_CLUSTERING_ROOT;
std::filesystem::path root;
try {
root = application_root();
} catch (const std::exception& error) {
std::cerr
<< "Impossibile determinare la root applicativa: "
<< error.what()
<< "\n";
return 3;
}
const std::string scrfd_model =
root + "/models/SCRFD_500M_KPS_640.rknn";
(
root
/ "models"
/ "SCRFD_500M_KPS_640.rknn"
).string();
const std::string sface_model =
root + "/models/face_recognition_sface_2021dec.rknn";
(
root
/ "models"
/ "face_recognition_sface_2021dec.rknn"
).string();
FaceEngine engine;
@ -197,13 +308,14 @@ int main(int argc, char** argv)
int image_height = 0;
if (!engine.process_image(
argv[1],
image_path,
faces,
image_width,
image_height)) {
image_height,
rotation_degrees)) {
std::cerr
<< "Scansione fallita: "
<< argv[1]
<< image_path
<< "\n";
return 4;
@ -227,13 +339,15 @@ int main(int argc, char** argv)
std::cout << "\"image\":{";
std::cout << "\"path\":";
write_json_string(argv[1]);
write_json_string(image_path);
std::cout
<< ",\"width\":"
<< image_width
<< ",\"height\":"
<< image_height;
<< image_height
<< ",\"rotation\":"
<< rotation_degrees;
std::cout << "},";