add depth-anything-v2 support

This commit is contained in:
Neucrack
2025-06-11 11:36:30 +08:00
parent 4a96f01cd5
commit 252d2fe755
13 changed files with 6587 additions and 27 deletions

View File

@@ -280,6 +280,12 @@ namespace maix
*/
tensor::DType dtype() { return _dtype; }
/**
* get tensor raw data pointer, use it carefully.
* @return `void *` type.
* @maixcdk maix.tensor.Tensor.data
*/
void *data() { return _data; }
/**

View File

@@ -12,7 +12,7 @@ using RGB = std::array<uint8_t, 3>;
using CmapArray = std::vector<RGB>;
/**
* @brief Cmap
* @brief Cmap, !!!!depracated!!!!, please use maix.image.CMap.
* @maixpy maix.ext_dev.cmap.Cmap
*/
enum class Cmap {

View File

@@ -180,30 +180,6 @@ namespace maix::nn
return err::ERR_NONE;
}
err::Err _load_labels_from_file(std::vector<std::string> &labels, const std::string &label_path)
{
// load labels from labels file
labels.clear();
fs::File *f = fs::open(label_path, "r");
if (!f)
{
log::error("open label file %s failed", label_path.c_str());
return err::ERR_ARGS;
}
std::string line;
while (f->readline(line) > 0)
{
// strip line
line.erase(0, line.find_first_not_of(" \t\r\n"));
line.erase(line.find_last_not_of(" \t\r\n") + 1);
if(!line.empty())
labels.push_back(line);
}
f->close();
delete f;
return err::ERR_NONE;
}
/**
* Forward image to model, get result. Only for image input, use classify_raw for tensor input.
* @param img image, format should match model input_type, or will raise err.Exception

View File

@@ -0,0 +1,388 @@
/**
* @author neucrack@sipeed
* @copyright Sipeed Ltd 2023-
* @license Apache 2.0
* @update 2025.6.9: Add depth anything v2 support
*/
#pragma once
#include <cfloat>
#include "maix_basic.hpp"
#include "maix_nn.hpp"
#include "maix_image.hpp"
#include "maix_nn_F.hpp"
#include "maix_image_cmap.hpp"
namespace maix::nn
{
/**
* DepthAnything
* @maixpy maix.nn.DepthAnything
*/
class DepthAnything
{
public:
/**
* Construct a new DepthAnything object
* @param model MUD model path, if empty, will not load model, you can call load() later.
* if not empty, will load model and will raise err::Exception if load failed.
* @param[in] dual_buff prepare dual input output buffer to accelarate forward, that is, when NPU is forwarding we not wait and prepare the next input buff.
* If you want to ensure every time forward output the input's result, set this arg to false please.
* Default true to ensure speed.
* @maixpy maix.nn.DepthAnything.__init__
* @maixcdk maix.nn.DepthAnything.DepthAnything
*/
DepthAnything(const string &model = "", bool dual_buff = true)
{
_model = nullptr;
_dual_buff = dual_buff;
if (!model.empty())
{
err::Err e = load(model);
if (e != err::ERR_NONE)
{
throw err::Exception(e, "load model failed");
}
}
}
~DepthAnything()
{
if (_model)
{
delete _model;
_model = nullptr;
}
}
/**
* Load model from file, model format is .mud,
* MUD file should contain [extra] section, have key-values:
* - model_type: depth_anything_v2
* - input_type: rgb or bgr
* - mean: 123.675, 116.28, 103.53
* - scale: 0.017124753831663668, 0.01750700280112045, 0.017429193899782137
* - labels: imagenet_classes.txt
* @param model MUD model path
* @return error code, if load failed, return error code
* @maixpy maix.nn.DepthAnything.load
*/
err::Err load(const string &model)
{
if (_model)
{
delete _model;
_model = nullptr;
}
_model = new nn::NN(model, _dual_buff);
if (!_model)
{
return err::ERR_NO_MEM;
}
_extra_info = _model->extra_info();
if (_extra_info.find("model_type") != _extra_info.end())
{
if (_extra_info["model_type"] != "depth_anything_v2")
{
log::error("model_type not match, expect 'depth_anything_v2', but got '%s'", _extra_info["model_type"].c_str());
return err::ERR_ARGS;
}
}
else
{
log::error("model_type key not found");
return err::ERR_ARGS;
}
if (_extra_info.find("input_type") != _extra_info.end())
{
std::string input_type = _extra_info["input_type"];
if (input_type == "rgb")
{
_input_img_fmt = maix::image::FMT_RGB888;
}
else if (input_type == "bgr")
{
_input_img_fmt = maix::image::FMT_BGR888;
}
else if (input_type == "gray")
{
_input_img_fmt = maix::image::FMT_GRAYSCALE;
}
else
{
log::error("unknown input type: %s", input_type.c_str());
return err::ERR_ARGS;
}
_input_is_img = true;
}
else
{
log::error("input_type key not found");
return err::ERR_ARGS;
}
if (_extra_info.find("mean") != _extra_info.end())
{
std::string mean_str = _extra_info["mean"];
std::vector<std::string> mean_strs = split(mean_str, ",");
for (auto &it : mean_strs)
{
try
{
this->mean.push_back(std::stof(it));
}
catch (std::exception &e)
{
log::error("mean value error, should float");
return err::ERR_ARGS;
}
}
}
else
{
log::error("mean key not found");
return err::ERR_ARGS;
}
if (_extra_info.find("scale") != _extra_info.end())
{
std::string scale_str = _extra_info["scale"];
std::vector<std::string> scale_strs = split(scale_str, ",");
for (auto &it : scale_strs)
{
try
{
this->scale.push_back(std::stof(it));
}
catch (std::exception &e)
{
log::error("scale value error, should float");
return err::ERR_ARGS;
}
}
}
else
{
log::error("scale key not found");
return err::ERR_ARGS;
}
_inputs = _model->inputs_info();
if(_inputs[0].shape[3] <= 4) // nhwc
_input_size = image::Size(_inputs[0].shape[2], _inputs[0].shape[1]);
else
_input_size = image::Size(_inputs[0].shape[3], _inputs[0].shape[2]);
return err::ERR_NONE;
}
/**
* Forward model and get raw image depth estimation data.
* @param img image, format should match model input_type, or will raise err.Exception
* @param fit image resize fit mode if input image not equal to model' input size,
* will auto resize to model's input size then detect, and recover to image input size.
* Default Fit.FIT_CONTAIN, see image.Fit.
* @throw If error occurred, will raise err::Exception, you can find reason in log, mostly caused by args error or hardware error.
* @return result, a tensor.Tensor object. If in dual_buff mode, value can be None(in Python) or nullptr(in C++) when not ready. In C++, you need to delete it after use.
* @maixpy maix.nn.DepthAnything.get_depth
*/
tensor::Tensor *get_depth(image::Image &img, image::Fit fit = image::FIT_CONTAIN)
{
if (img.format() != _input_img_fmt)
{
throw err::Exception("image format not match, input_type: " + image::fmt_names[_input_img_fmt] + ", image format: " + image::fmt_names[img.format()]);
}
if(!(fit == image::FIT_CONTAIN || fit == image::FIT_FILL || fit == image::FIT_COVER))
{
throw err::Exception("fit only support FIT_CONTAIN, FIT_FILL, FIT_COVER.");
}
tensor::Tensors *outputs;
outputs = _model->forward_image(img, this->mean, this->scale, fit, false, false);
if (!outputs)
{
return nullptr;
}
tensor::Tensor *tensor = outputs->begin()->second;
if (tensor->dtype() != tensor::DType::FLOAT32)
{
throw err::Exception("output tensor dtype only support float32 now");
}
tensor::Tensor *result = new tensor::Tensor(tensor->shape(), tensor->dtype(), tensor->data(), true);
delete outputs;
return result;
}
/**
* Forward model and get image depth estimation data normlized to [0, 255] and as a image.Image object.
* @param img image, format should match model input_type, or will raise err.Exception
* @param fit image resize fit mode if input image not equal to model' input size,
* will auto resize to model's input size then detect, and recover to image input size.
* Default Fit.FIT_CONTAIN, see image.Fit.
* @param cmap Color map used convert grayscale distance estimation image to RGB image.
* Diiferent cmap will influence finally image.
* Default image.CMap.INFERNO.
* @throw If error occurred, will raise err::Exception, you can find reason in log, mostly caused by args error or hardware error.
* @return result, a image::Image object. If in dual_buff mode, value can be None(in Python) or nullptr(in C++) when not ready. In C++, you need to delete it after use.
* @maixpy maix.nn.DepthAnything.get_depth_image
*/
image::Image *get_depth_image(image::Image &img, image::Fit fit = image::FIT_CONTAIN, image::CMap cmap = image::CMap::INFERNO)
{
if (img.format() != _input_img_fmt)
{
throw err::Exception("image format not match, input_type: " + image::fmt_names[_input_img_fmt] + ", image format: " + image::fmt_names[img.format()]);
}
if(!(fit == image::FIT_CONTAIN || fit == image::FIT_FILL || fit == image::FIT_COVER))
{
throw err::Exception("fit only support FIT_CONTAIN, FIT_FILL, FIT_COVER.");
}
tensor::Tensors *outputs;
outputs = _model->forward_image(img, this->mean, this->scale, fit, false, false);
if (!outputs)
{
return nullptr;
}
tensor::Tensor *tensor = outputs->begin()->second;
if (tensor->dtype() != tensor::DType::FLOAT32)
{
throw err::Exception("output tensor dtype only support float32 now");
}
// convert to rgb
auto convert_image_with_cmap = [](float *data, int w, int h, image::CMap cmap){
auto &colors = image::cmap_colors_rgb(cmap);
image::Image *result = new image::Image(w, h, image::Format::FMT_RGB888);
float max_v = data[0];
float min_v = data[0];
for(int i = 1; i < w * h; ++i)
{
if (data[i] > max_v)
max_v = data[i];
else if (data[i] < min_v)
min_v = data[i];
}
if(min_v == max_v)
{
memset(result->data(), 127, w * h * 3);
}
else
{
float scale = 255.0f / (max_v - min_v);
uint8_t *img_data = (uint8_t*)result->data();
#pragma omp parallel for
for(int i = 0; i < w * h; ++i)
{
uint8_t gray = static_cast<uint8_t>(std::clamp((data[i] - min_v) * scale, 0.0f, 255.0f));
auto &rgb = colors[gray];
img_data[3 * i] = rgb[0];
img_data[3 * i + 1] = rgb[1];
img_data[3 * i + 2] = rgb[2];
}
}
return result;
};
image::Image *result = convert_image_with_cmap((float*)tensor->data(), input_width(), input_height(), cmap);
// check need resize
if(img.width() * img.height() != tensor->size_int())
{
image::Fit fit_r = (fit == image::FIT_FILL) ? fit : (fit == image::FIT_CONTAIN ? image::FIT_COVER : image::FIT_CONTAIN);
image::Image *result2 = result->resize(img.width(), img.height(), fit_r);
delete result;
result = result2;
}
delete outputs;
return result;
}
/**
* Get model input size, only for image input
* @return model input size
* @maixpy maix.nn.DepthAnything.input_size
*/
image::Size input_size()
{
return _input_size;
}
/**
* Get model input width, only for image input
* @return model input size of width
* @maixpy maix.nn.DepthAnything.input_width
*/
int input_width()
{
return _input_size.width();
}
/**
* Get model input height, only for image input
* @return model input size of height
* @maixpy maix.nn.DepthAnything.input_height
*/
int input_height()
{
return _input_size.height();
}
/**
* Get input image format, only for image input
* @return input image format, image::Format type.
* @maixpy maix.nn.DepthAnything.input_format
*/
image::Format input_format()
{
return _input_img_fmt;
}
/**
* Get input shape, if have multiple input, only return first input shape
* @return input shape, list type
* @maixpy maix.nn.DepthAnything.input_shape
*/
std::vector<int> input_shape()
{
return _inputs[0].shape;
}
public:
/**
* Get mean value, list type
* @maixpy maix.nn.DepthAnything.mean
*/
std::vector<float> mean;
/**
* Get scale value, list type
* @maixpy maix.nn.DepthAnything.scale
*/
std::vector<float> scale;
private:
image::Format _input_img_fmt;
bool _input_is_img;
bool _dual_buff;
nn::NN *_model;
std::map<string, string> _extra_info;
image::Size _input_size;
std::vector<nn::LayerInfo> _inputs;
static void split0(std::vector<std::string> &items, const std::string &s, const std::string &delimiter)
{
items.clear();
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
std::string token;
while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos)
{
token = s.substr(pos_start, pos_end - pos_start);
pos_start = pos_end + delim_len;
items.push_back(token);
}
items.push_back(s.substr(pos_start));
}
static std::vector<std::string> split(const std::string &s, const std::string &delimiter)
{
std::vector<std::string> tokens;
split0(tokens, s, delimiter);
return tokens;
}
};
} // namespace maix::nn

View File

@@ -0,0 +1,132 @@
/**
* @author neucrack@sipeed
* @copyright Sipeed Ltd 2023-
* @license Apache 2.0
* @update 2025.6.9: Add cmap def.
*/
#pragma once
#include <vector>
#include <string>
#include <map>
#include <stdint.h>
#include <stdexcept>
#include "maix_image_color.hpp"
namespace maix::image
{
/**
* Image formats
* @attention for MaixPy firmware developers, update this enum will also need to update the fmt_size and fmt_names too !!!
* @maixpy maix.image.CMap
*/
enum class CMap
{
// Sequential (Perceptually uniform linear gradients)
TURBO = 0, // Google-designed smooth, bright colormap; good Jet replacement for heatmaps
VIRIDIS, // Default perceptually uniform colormap; colorblind-friendly and widely recommended
INFERNO, // High-contrast, perceptually uniform; ideal for dark backgrounds and scientific data
PLASMA, // Bright and visually appealing; perceptually uniform and colorblind-friendly
CIVIDIS, // Grayscale-compatible and colorblind-safe; designed for visual accessibility
CUBEHELIX, // Perceptually uniform and printable in grayscale; spirals through color space
MAGMA, // Dark background-optimized; smooth gradient with good visibility in low-light visuals
TWILIGHT, // Cyclic gradient; useful for circular data such as angles or phase data
TWILIGHT_SHIFTED, // Phase-shifted version of Twilight; same use case but shifted zero point
GREYS, // Monotonic black-to-white gradient; useful for basic grayscale visualization
// Traditional (Legacy and visually distinct maps)
JET, // Classic but non-uniform RGB colormap; visually vibrant but not perceptually linear
// Diverging (Center-out maps for relative differences)
COOLWARM, // Blue-white-red diverging map; ideal for visualizing deviation from a neutral center
RDYBU, // Red-white-blue diverging map; suitable for highlighting opposing directions/values
// Qualitative (For categorical or class label data)
SET1, // High-contrast colors; up to 9 distinct categories, ideal for class segmentation
TAB10, // Matplotlib default for 10-category labeling; visually distinct and colorblind-friendly
TAB20, // Matplotlib default for 20-category labeling; visually distinct and colorblind-friendly
// thermal
THERMAL_WHITE_HOT, // Hotter whiter; used thermal imaging mode due to its natural contrast.
THERMAL_BLACK_HOT, // Hotter darker; Often used in security and tactical applications for better object detection.
THERMAL_RED_HOT, // Hotter red,cooler areas dark; Emphasizes hotspots, useful for quick temperature anomaly detection.
THERMAL_WHITE_HOT_SD, /* White Hot SD (Smooth Detail): Enhanced White Hot with improved local contrast and smoother tone transitions.
Helps distinguish fine temperature differences in subtle thermal scenes.
*/
THERMAL_BLACK_HOT_SD, /* Black Hot SD (Smooth Detail): Enhanced Black Hot with detail-preserving smoothing and finer thermal gradients.
Improves readability of dark-hot scenes with less visual noise.
*/
THERMAL_RED_HOT_SD, /* Red Hot SD (Smooth Detail): Enhanced Red Hot with more gradual color changes and smoother heat spot highlighting.
Offers better heat trace visualization with reduced abrupt transitions.
*/
THERMAL_IRONBOW, /* Ironbow: A classic thermal colormap that uses a smooth gradient from dark to bright (black → red → yellow → white).
Commonly used in industrial and medical thermography for better visualization.
*/
THERMAL_NIGHT, /* Night: A low-brightness thermal mode optimized for night operations or low-light display environments.
Typically enhances visibility in high-contrast night-time scenarios.
*/
// Special / Custom
GITHUB_GREEN, // GitHub-themed green-based palette; custom usage such as contribution graphs
MAX // Total count of valid colormaps (not a colormap itself)
};
/**
* Get the string representation of a colormap enum value.
* @param cmap Colormap enum value, @see image::CMap
* @return Corresponding colormap name as a string.
* @maixpy maix.image.cmap_to_str
*/
std::string cmap_to_str(image::CMap cmap);
/**
* Get the colormap enum value from a string name.
* @param name Name of the colormap (case-insensitive).
* @return Corresponding colormap enum value, or throws if name is invalid.
* @maixpy maix.image.cmap_from_str
*/
image::CMap cmap_from_str(const std::string& name);
/**
* Get a list of all available colormap name strings.
* @param claasify cmaps for classify, wihch cmap size not equal to 256.
* @return Vector of all supported colormap name strings.
* @maixpy maix.image.cmap_strs
*/
std::vector<std::string> cmap_strs(bool classify = false);
/**
* Get the mapped color of a grayscale value under a specific colormap.
* @param gray Grayscale value in [0, 255].
* @param cmap Colormap enum value to map the grayscale to color.
* @return The mapped image::Color.
* @maixpy maix.image.cmap_color
*/
image::Color cmap_color(uint8_t gray, image::CMap cmap);
/**
* Get all 256 mapped colors of a colormap.
* @param cmap Colormap enum value.
* @return Vector of 256 image::Color values corresponding to grayscale values [0, 255].
* Return value will alloc data, you need to delete it after use in C++.
* @maixpy maix.image.cmap_colors
*/
std::vector<image::Color> cmap_colors(image::CMap cmap);
/**
* Get all 256 mapped RGB colors of a colormap.
* @param cmap Colormap enum value.
* @return Vector of 256 RGB arrays (each array has 3 uint8_t: R, G, B).
* Return value is a internal table refrence.
* @maixpy maix.image.cmap_colors_rgb
*/
const std::vector<std::array<uint8_t, 3>> &cmap_colors_rgb(image::CMap cmap);
}; // namespace maix::image

View File

@@ -21,7 +21,7 @@ namespace maix::image
public:
/**
* Color constructor
* @param alpha alpha channel, value range: 0 ~ 1
* @param alpha alpha channel, value range: 0 ~ 1, 0 means transparent.
* @maixpy maix.image.Color.__init__
*/
Color(uint8_t ch1, uint8_t ch2 = 0, uint8_t ch3 = 0, float alpha = 0, image::Format format = image::FMT_GRAYSCALE)
@@ -65,6 +65,11 @@ namespace maix::image
}
}
Color(const Color&) = default;
Color& operator=(const Color&) = default;
Color(Color&&) noexcept = default;
Color& operator=(Color&&) noexcept = default;
/**
* Color red channel
* @maixpy maix.image.Color.r
@@ -84,7 +89,7 @@ namespace maix::image
uint8_t b;
/**
* Color alpha channel, value from 0.0 to 1.0, float value
* Color alpha channel, value from 0.0 to 1.0, float value, 0 means transparent.
* @maixpy maix.image.Color.alpha
*/
float alpha;

File diff suppressed because it is too large Load Diff

9
examples/nn_depth_anything/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
build
dist
.config.mk
.flash.conf.json
data
/CMakeLists.txt
__pycache__

View File

@@ -0,0 +1,5 @@
Hello World Project based on MaixCDK
====
Hello world example code for MaixCDK of Sipeed, build method please visit [MaixCDK](https://github.com/sipeed/MaixCDK).

View File

@@ -0,0 +1,74 @@
############### Add include ###################
list(APPEND ADD_INCLUDE "include"
)
list(APPEND ADD_PRIVATE_INCLUDE "")
###############################################
############ Add source files #################
# list(APPEND ADD_SRCS "src/main.c"
# "src/test.c"
# )
append_srcs_dir(ADD_SRCS "src") # append source file in src dir to var ADD_SRCS
# list(REMOVE_ITEM COMPONENT_SRCS "src/test2.c")
# FILE(GLOB_RECURSE EXTRA_SRC "src/*.c")
# FILE(GLOB EXTRA_SRC "src/*.c")
# list(APPEND ADD_SRCS ${EXTRA_SRC})
# aux_source_directory(src ADD_SRCS) # collect all source file in src dir, will set var ADD_SRCS
# append_srcs_dir(ADD_SRCS "src") # append source file in src dir to var ADD_SRCS
# list(REMOVE_ITEM COMPONENT_SRCS "src/test.c")
# set(ADD_ASM_SRCS "src/asm.S")
# list(APPEND ADD_SRCS ${ADD_ASM_SRCS})
# SET_PROPERTY(SOURCE ${ADD_ASM_SRCS} PROPERTY LANGUAGE C) # set .S ASM file as C language
# SET_SOURCE_FILES_PROPERTIES(${ADD_ASM_SRCS} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -D BBBBB")
###############################################
###### Add required/dependent components ######
list(APPEND ADD_REQUIREMENTS basic nn vision)
###############################################
###### Add link search path for requirements/libs ######
# list(APPEND ADD_LINK_SEARCH_PATH "${CONFIG_TOOLCHAIN_PATH}/lib")
# list(APPEND ADD_REQUIREMENTS pthread m) # add system libs, pthread and math lib for example here
# set (OpenCV_DIR opencv/lib/cmake/opencv4)
# find_package(OpenCV REQUIRED)
###############################################
############ Add static libs ##################
# list(APPEND ADD_STATIC_LIB "lib/libtest.a")
###############################################
#### Add compile option for this component ####
#### Just for this component, won't affect other
#### modules, including component that depend
#### on this component
# list(APPEND ADD_DEFINITIONS_PRIVATE -DAAAAA=1)
#### Add compile option for this component
#### and components depend on this component
# list(APPEND ADD_DEFINITIONS -DAAAAA222=1
# -DAAAAA333=1)
###############################################
############ Add static libs ##################
#### Update parent's variables like CMAKE_C_LINK_FLAGS
# set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group libmaix/libtest.a -ltest2 -Wl,--end-group" PARENT_SCOPE)
###############################################
######### Add files need to download #########
# list(APPEND ADD_FILE_DOWNLOADS "{
# 'url': 'https://*****/abcde.tar.xz',
# 'urls': [], # backup urls, if url failed, will try urls
# 'sites': [], # download site, user can manually download file and put it into dl_path
# 'sha256sum': '',
# 'filename': 'abcde.tar.xz',
# 'path': 'toolchains/xxxxx',
# 'check_files': []
# }"
# )
#
# then extracted file in ${DL_EXTRACTED_PATH}/toolchains/xxxxx,
# you can directly use then, for example use it in add_custom_command
##############################################
# register component, DYNAMIC or SHARED flags will make component compiled to dynamic(shared) lib
register_component()

View File

View File

@@ -0,0 +1,3 @@
#pragma once

View File

@@ -0,0 +1,85 @@
#include "maix_basic.hpp"
#include "maix_vision.hpp"
#include "maix_nn_depth_anything.hpp"
#include "main.h"
using namespace maix;
int _main(int argc, char* argv[])
{
int ret = 0;
log::info("Program start");
std::string help = "Usage: " + std::string(argv[0]) + " mud_model_path image_path";
if(argc < 2)
{
log::error(help.c_str());
return -1;
}
const char *model_path = argv[1];
bool dual_buff = argc < 3;
image::CMap cmap = image::CMap::TURBO;
log::info("model path: %s", model_path);
nn::DepthAnything model(model_path, dual_buff);
log::info("load model %s success", model_path);
log::info("dual buff mode: %d", dual_buff);
if(argc >= 3)
{
const char *img_path = argv[2];
log::info("load image now");
maix::image::Image *img = maix::image::load(img_path, model.input_format());
err::check_null_raise(img, "load image " + std::string(img_path) + " failed");
log::info("load image %s success: %s", img_path, img->to_str().c_str());
if(img->width() != model.input_size().width() || img->height() != model.input_size().height())
{
log::warn("image size not match model input size, will auto resize from %dx%d to %dx%d", img->width(), img->height(), model.input_size().width(), model.input_size().height());
}
image::Image *result = model.get_depth_image(*img, image::FIT_CONTAIN, cmap);
result->save("result.jpg");
delete result;
delete img;
}
else
{
log::info("open camera now");
image::Size input_size = model.input_size();
camera::Camera cam = camera::Camera(input_size.width(), input_size.height(), model.input_format());
log::info("open camera success");
display::Display disp = display::Display();
while(!app::need_exit())
{
uint64_t t = time::ticks_ms();
image::Image *img = cam.read();
err::check_null_raise(img, "read camera failed");
image::Image *result = model.get_depth_image(*img);
if(result)
{
disp.show(*result);
delete result;
}
delete img;
log::info("time: %d ms", time::ticks_ms() - t);
}
}
log::info("Program exit");
return ret;
}
int main(int argc, char* argv[])
{
// Catch signal and process
sys::register_default_signal_handle();
// Use CATCH_EXCEPTION_RUN_RETURN to catch exception,
// if we don't catch exception, when program throw exception, the objects will not be destructed.
// So we catch exception here to let resources be released(call objects' destructor) before exit.
CATCH_EXCEPTION_RUN_RETURN(_main, -1, argc, argv);
}