Refactor: Rename NanoKVM to BatchuKVM and update server URL

This commit is contained in:
2025-12-09 20:35:38 +09:00
commit 8cf674c9e5
396 changed files with 54380 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
# Config enable component2 or not in Kconfig
################# Add include #################
list(APPEND ADD_INCLUDE "include"
"include/base"
)
if(PLATFORM_LINUX)
list(APPEND ADD_PRIVATE_INCLUDE "port/linux")
elseif(PLATFORM_MAIXCAM)
list(APPEND ADD_PRIVATE_INCLUDE "port/maixcam")
endif()
list(APPEND ADD_PRIVATE_INCLUDE "include_private")
###############################################
############## Add source files ###############
# list(APPEND ADD_SRCS "src/lib2.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
if(PLATFORM_LINUX)
append_srcs_dir(ADD_SRCS "port/linux")
elseif(PLATFORM_MAIXCAM)
append_srcs_dir(ADD_SRCS "port/maixcam")
endif()
# 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 opencv opencv_freetype websocket peripheral)
list(APPEND ADD_REQUIREMENTS omv)
list(APPEND ADD_REQUIREMENTS kvm_mmf)
###############################################
###### 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 dynamic libs ##################
# list(APPEND ADD_DYNAMIC_LIB "lib/arch/v831/libmaix_nn.so"
# "lib/arch/v831/libmaix_cam.so"
# )
###############################################
#### 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 denpend 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)
###############################################
# register component, DYNAMIC or SHARED flags will make component compiled to dynamic(shared) lib
register_component()

View File

View File

@@ -0,0 +1,109 @@
/**
* @file maix_camera_base.hpp
* @brief Maix camera SDL implementation
* @author neucrack@sipeed.com
* @license Apache 2.0 Sipeed Ltd
* @update date 2023-10-23 Create by neucrack
*/
#pragma once
#include <vector>
#include "maix_image.hpp"
#include "maix_err.hpp"
namespace maix::camera
{
class CameraBase
{
public:
/**
* @brief Construct a new Camera object
* @param device camera device name, you can get devices by list_devices method, by default(value is NULL(None in MaixPy)) means the first device
* @param width camera width, by default(value is -1) means auto detect,
* if width > max device supported width, will auto set to max device supported width
* @param height camera height, by default(value is -1) means auto detect,
* if height > max device supported height, will auto set to max device supported height
* @param format camera format, by default(value is FMT_RGB888)
* @param buff_num camera buffer number, by default(value is 3)
*/
CameraBase(const char *device = nullptr, int width = -1, int height = -1, image::Format format = image::Format::FMT_RGB888, int buff_num = 3){};
/**
* @brief Judge if the given format is supported by the camera
*/
virtual bool is_support_format(image::Format format) = 0;
/**
* @brief open camera device
* @param width camera width, by default(value is -1) means auto detect,
* if width > max device supported width, will auto set to max device supported width
* @param height camera height, by default(value is -1) means auto detect,
* if height > max device supported height, will auto set to max device supported height
* @param format camera format, by default(value is FMT_RGB888)
* @param buff_num camera buffer number, by default(value is 3)
* @return error code
*/
virtual err::Err open(int width = -1, int height = -1, image::Format format = image::Format::FMT_RGB888, int buff_num = 3) = 0;
/**
* @brief read a frame from camera
* @param buff buffer to store image data, if NULL, will alloc a new buffer
* @return image data
*/
virtual image::Image *read(void *buff = NULL, size_t buff_size = 0) = 0;
/**
* @brief close camera device
* @return none
*/
virtual void close() = 0;
/**
* Add a new channel and return a new Camera object, you can use close() to close this channel.
* @param width camera width, default is -1, means auto, mostly means max width of camera support
* @param height camera height, default is -1, means auto, mostly means max height of camera support
* @param format camera output format, default is RGB888
* @param buff_num camera buffer number, default is 3, means 3 buffer, one used by user, one used for cache the next frame,
* more than one buffer will accelerate image read speed, but will cost more memory.
* @return new Camera object
*/
virtual camera::CameraBase *add_channel(int width = -1, int height = -1, image::Format format = image::FMT_RGB888, int buff_num = 3) = 0;
/**
* @brief clear all buffer
* @return none
*/
virtual void clear_buff() = 0;
/**
* @brief check camera device is opened or not
* @return opened or not, bool type
*/
virtual bool is_opened() = 0;
/**
* Get camera supported channels(layers)
*/
virtual int get_ch_nums() = 0;
/**
* Get channel number of camera.
*/
virtual int get_channel() = 0;
/**
* Set/Get camera mirror
* @param en enable/disable mirror
*/
virtual int hmirror(int en) = 0;
/**
* Set/Get camera flip
* @param en enable/disable flip
*/
virtual int vflip(int en) = 0;
};
}

View File

@@ -0,0 +1,305 @@
/**
* @author neucrack@sipeed, lxowalle@sipeed
* @copyright Sipeed Ltd 2023-
* @license Apache 2.0
* @update 2023.9.8: Add framework, create this file.
*/
#pragma once
#include "maix_tensor.hpp"
#include "maix_log.hpp"
#include "maix_image.hpp"
#include "maix_err.hpp"
#include "maix_camera_base.hpp"
#include <stdlib.h>
#include <map>
#include <stdexcept>
#include <vector>
#include <opencv2/opencv.hpp>
/**
* @brief maix.camera module, access camera device and get image from it
* @maixpy maix.camera
*/
namespace maix::camera
{
/**
* List all supported camera devices.
* @return Returns the path to the camera device.
* @maixpy maix.camera.list_devices
*/
std::vector<std::string> list_devices();
/**
* Enable set camera registers, default is false, if set to true, will not set camera registers, you can manually set registers by write_reg API.
* @param enable enable/disable set camera registers
* @maixpy maix.camera.set_regs_enable
*/
void set_regs_enable(bool enable = true);
/**
* Camera class
* @maixpy maix.camera.Camera
*/
class Camera
{
public:
/**
* @brief Construct a new Camera object.
* Maximum resolution support 2560x1440.
* @param width camera width, default is -1, means auto, mostly means max width of camera support
* @param height camera height, default is -1, means auto, mostly means max height of camera support
* @param format camera output format, default is image.Format.FMT_RGB888
* @param device camera device path, you can get devices by list_devices method, by default(value is NULL(None in MaixPy)) means the first device
* @param fps camera fps, default is -1, means auto, mostly means max fps of camera support
* @param buff_num camera buffer number, default is 3, means 3 buffer, one used by user, one used for cache the next frame,
* more than one buffer will accelerate image read speed, but will cost more memory.
* @param open If true, camera will automatically call open() after creation. default is true.
* @maixpy maix.camera.Camera.__init__
* @maixcdk maix.camera.Camera.Camera
*/
Camera(int width = -1, int height = -1, image::Format format = image::FMT_RGB888, const char *device = nullptr, int fps = -1, int buff_num = 3, bool open = true);
/**
* @brief Construct a new Camera object.
* @attention CameraBase * parameter need to be set manually, otherwise the operation of this object will be invalid.
* @param device camera device path, you can get devices by list_devices method, by default(value is NULL(None in MaixPy)) means the first device
* @param base basic operation objects.
* @param width camera width, default is -1, means auto, mostly means max width of camera support
* @param height camera height, default is -1, means auto, mostly means max height of camera support
* @param format camera output format, default is image.Format.FMT_RGB888
* @param fps camera fps, default is -1, means auto, mostly means max fps of camera support
* @param buff_num camera buffer number, default is 3, means 3 buffer, one used by user, one used for cache the next frame,
* more than one buffer will accelerate image read speed, but will cost more memory.
* @param open If true, camera will automatically call open() after creation. default is true.
* @maixcdk maix.camera.Camera.Camera
*/
Camera(const char *device, CameraBase *base, int width = -1, int height = -1, image::Format format = image::FMT_RGB888, int fps = -1, int buff_num = -1, bool open = true);
~Camera();
void restart(int width = -1, int height = -1, image::Format format = image::FMT_RGB888, const char *device = nullptr, int fps = -1, int buff_num = 3, bool open = true);
/**
* Get the number of channels supported by the camera.
* @return Returns the maximum number of channels.
* @maixpy maix.camera.Camera.get_ch_nums
*/
int get_ch_nums();
/**
* Open camera and run
* @param width camera width, default is -1, means auto, mostly means max width of camera support
* @param height camera height, default is -1, means auto, mostly means max height of camera support
* @param format camera output format, default same as the constructor's format argument
* @param fps camera fps, default is -1, means auto, mostly means max fps of camera support
* @param buff_num camera buffer number, default is 3, means 3 buffer, one used by user, one used for cache the next frame,
* more than one buffer will accelerate image read speed, but will cost more memory.
* @return error code, err::ERR_NONE means success, others means failed
* @maixpy maix.camera.Camera.open
*/
err::Err open(int width = -1, int height = -1, image::Format format = image::FMT_INVALID, int fps = -1, int buff_num = -1);
/**
* Get one frame image from camera buffer, must call open method before read.
* If open method not called, will call it automatically, if open failed, will throw exception!
* So call open method before read is recommended.
* @param buff buffer to store image data, if buff is nullptr, will alloc memory automatically.
* In MaixPy, default to None, you can create a image.Image object, then pass img.data() to buff.
* @param block block read, default is true, means block util read image successfully,
* if set to false, will return nullptr if no image in buffer
* @return image::Image object, if failed, return nullptr, you should delete if manually in C++
* @maixpy maix.camera.Camera.read
*/
image::Image *read(void *buff = nullptr, size_t buff_size = 0, bool block = true);
/**
* Clear buff to ensure the next read image is the latest image
* @maixpy maix.camera.Camera.clear_buff
*/
void clear_buff();
/**
* Read some frames and drop, this is usually used avoid read not stable image when camera just opened.
* @param num number of frames to read and drop
* @maixpy maix.camera.Camera.skip_frames
*/
void skip_frames(int num);
/**
* Close camera
* @maixpy maix.camera.Camera.close
*/
void close();
/**
* Add a new channel and return a new Camera object, you can use close() to close this channel.
* @param width camera width, default is -1, means auto, mostly means max width of camera support
* @param height camera height, default is -1, means auto, mostly means max height of camera support
* @param format camera output format, default is RGB888
* @param fps camera fps, default is -1, means auto, mostly means max fps of camera support
* @param buff_num camera buffer number, default is 3, means 3 buffer, one used by user, one used for cache the next frame,
* more than one buffer will accelerate image read speed, but will cost more memory.
* @param open If true, camera will automatically call open() after creation. default is true.
* @return new Camera object
* @maixpy maix.camera.Camera.add_channel
*/
camera::Camera *add_channel(int width = -1, int height = -1, image::Format format = image::FMT_RGB888, int fps = -1, int buff_num = 3, bool open = true);
/**
* Check if camera is opened
* @return true if camera is opened, false if not
* @maixpy maix.camera.Camera.is_opened
*/
bool is_opened();
/**
* @brief check camera device is closed or not
* @return closed or not, bool type
* @maixpy maix.camera.Camera.is_closed
*/
bool is_closed() { return !is_opened();}
/**
* Get camera width
* @return camera width
* @maixpy maix.camera.Camera.width
*/
int width()
{
return _width;
}
/**
* Get camera height
* @return camera height
* @maixpy maix.camera.Camera.height
*/
int height()
{
return _height;
}
/**
* Get camera fps
* @return camera fps
* @maixpy maix.camera.Camera.fps
*/
int fps()
{
return _fps;
}
/**
* Get camera output format
* @return camera output format, image::Format object
* @maixpy maix.camera.Camera.format
*/
image::Format format()
{
return _format;
}
/**
* Get camera buffer number
* @return camera buffer number
* @maixpy maix.camera.Camera.buff_num
*/
int buff_num()
{
return _buff_num;
}
/**
* Set/Get camera horizontal mirror
* @return camera horizontal mirror
* @maixpy maix.camera.Camera.hmirror
*/
int hmirror(int value = -1);
/**
* Set/Get camera vertical flip
* @return camera vertical flip
* @maixpy maix.camera.Camera.vflip
*/
int vflip(int value = -1);
/**
* Get camera device path
* @return camera device path
* @maixpy maix.camera.Camera.device
*/
std::string device()
{
return _device;
}
/**
* Write camera register
* @param addr register address
* @param data register data
* @param bit_width register data bit width, default is 8
* @return error code, err::ERR_NONE means success, others means failed
* @maixpy maix.camera.Camera.write_reg
*/
err::Err write_reg(int addr, int data, int bit_width = 8)
{
return err::ERR_NONE;
}
/**
* Read camera register
* @param addr register address
* @return register data, -1 means failed
* @param bit_width register data bit width, default is 8
* @maixpy maix.camera.Camera.read_reg
*/
int read_reg(int addr, int bit_width = 8)
{
return -1;
}
/**
* Camera output color bar image for test
* @param enable enable/disable color bar
* @return error code, err::ERR_NONE means success, others means failed
* @maixpy maix.camera.Camera.show_colorbar
*/
err::Err show_colorbar(bool enable);
/**
* Get channel of camera
* @return channel number
* @maixpy maix.camera.Camera.get_channel
*/
int get_channel();
/**
* Set camera resolution
* @param width new width
* @param height new height
* @return error code, err::ERR_NONE means success, others means failed
* @maixpy maix.camera.Camera.set_resolution
*/
err::Err set_resolution(int width, int height);
private:
std::string _device;
int _ch;
int _width;
int _height;
int _fps;
int _buff_num;
image::Format _format;
image::Format _format_impl; // used by implement code and need convert to _format
int _hmirror;
int _vflip;
float _exposure;
float _gain;
bool _show_colorbar;
bool _open_set_regs;
CameraBase *_impl; // used by implement code
bool _check_format(image::Format format);
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,296 @@
/**
* @author neucrack@sipeed, lxowalle@sipeed
* @copyright Sipeed Ltd 2023-
* @license Apache 2.0
* @update 2023.9.8: Add framework, create this file.
*/
#pragma once
#include "maix_image_def.hpp"
#include "maix_log.hpp"
namespace maix::image
{
/**
* Color class
* @maixpy maix.image.Color
*/
class Color
{
public:
/**
* Color constructor
* @param alpha alpha channel, value range: 0 ~ 1
* @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)
{
if(alpha > 1 || alpha < 0)
throw std::runtime_error("alpha value range: 0 ~ 1");
this->format = format;
switch (format)
{
case image::FMT_RGB888:
r = ch1;
g = ch2;
b = ch3;
this->alpha = 1;
break;
case image::FMT_BGR888:
b = ch1;
g = ch2;
r = ch3;
this->alpha = 1;
break;
case image::FMT_GRAYSCALE:
gray = ch1;
break;
case image::FMT_BGRA8888:
b = ch1;
g = ch2;
r = ch3;
this->alpha = alpha;
break;
case image::FMT_RGBA8888:
r = ch1;
g = ch2;
b = ch3;
this->alpha = alpha;
break;
default:
throw std::runtime_error("not support format");
break;
}
}
/**
* Color red channel
* @maixpy maix.image.Color.r
*/
uint8_t r;
/**
* Color green channel
* @maixpy maix.image.Color.g
*/
uint8_t g;
/**
* Color blue channel
* @maixpy maix.image.Color.b
*/
uint8_t b;
/**
* Color alpha channel, value from 0.0 to 1.0, float value
* @maixpy maix.image.Color.alpha
*/
float alpha;
/**
* Color gray channel
* @maixpy maix.image.Color.gray
*/
uint8_t gray;
/**
* Color format
* @maixpy maix.image.Color.format
*/
image::Format format;
/**
* Get color's hex value
* @maixpy maix.image.Color.hex
*/
uint32_t hex()
{
uint32_t hex = 0;
switch (format)
{
case image::FMT_RGB888:
hex = r | (g << 8) | (b << 16);
break;
case image::FMT_BGR888:
hex = b | (g << 8) | (r << 16);
break;
case image::FMT_GRAYSCALE:
hex = gray;
break;
case image::FMT_BGRA8888:
hex = b | (g << 8) | (r << 16) | ((uint8_t)(alpha*255) << 24);
break;
case image::FMT_RGBA8888:
hex = r | (g << 8) | (b << 16) | ((uint8_t)(alpha*255) << 24);
break;
default:
throw std::runtime_error("not support format");
break;
}
return hex;
}
/**
* Create Color object from RGB channels
* @maixpy maix.image.Color.from_rgb
*/
static image::Color from_rgb(uint8_t r, uint8_t g, uint8_t b)
{
return Color(r, g, b, 1, image::Format::FMT_RGB888);
}
/**
* Create Color object from BGR channels
* @maixpy maix.image.Color.from_bgr
*/
static image::Color from_bgr(uint8_t b, uint8_t g, uint8_t r)
{
return Color(b, g, r, 1, image::Format::FMT_BGR888);
}
/**
* Create Color object from gray channel
* @maixpy maix.image.Color.from_gray
*/
static image::Color from_gray(uint8_t gray)
{
return Color(gray);
}
/**
* Create Color object from RGBA channels
* @param alpha alpha channel, float value, value range: 0 ~ 1
* @maixpy maix.image.Color.from_rgba
*/
static image::Color from_rgba(uint8_t r, uint8_t g, uint8_t b, float alpha)
{
return Color(r, g, b, alpha, image::Format::FMT_RGBA8888);
}
/**
* Create Color object from BGRA channels
* * @param alpha alpha channel, float value, value range: 0 ~ 1
* @maixpy maix.image.Color.from_bgra
*/
static image::Color from_bgra(uint8_t b, uint8_t g, uint8_t r, float alpha)
{
return Color(b, g, r, alpha, image::Format::FMT_BGRA8888);
}
/**
* Create Color object from hex value
* @param hex hex value, e.g. 0x0000FF00, lower address if first channel
* @param format color format, @see image::Format
* @maixpy maix.image.Color.from_hex
*/
static image::Color from_hex(uint32_t hex, image::Format &format)
{
return Color(hex & 0xFF, hex & 0xFF00, hex & 0xFF0000, (hex & 0xFF000000)/255.0, format);
}
/**
* Convert Color format
* @param format format want to convert to, @see image::Format, only support RGB888, BGR888, RGBA8888, BGRA8888, GRAYSCALE.
* @maixpy maix.image.Color.to_format
*/
void to_format(const image::Format &format)
{
if(!(format == image::FMT_RGB888 || format == image::FMT_BGR888 ||
format == image::FMT_RGBA8888 || format == image::FMT_BGRA8888 ||
format == image::FMT_GRAYSCALE))
{
log::error("convert format failed, not support format %d\n", format);
return;
}
if(this->format == format)
return;
if((this->format == image::FMT_RGB888 || this->format == image::FMT_BGR888) &&
(format == image::FMT_RGBA8888 || format == image::FMT_BGRA8888))
{
this->alpha = 1;
}
else if(this->format == image::FMT_GRAYSCALE && format != image::FMT_GRAYSCALE)
{
this->r = this->gray;
this->g = this->gray;
this->b = this->gray;
this->alpha = 1;
}
else if((this->format == image::FMT_RGBA8888 || this->format == image::FMT_BGRA8888) &&
(format == image::FMT_RGB888 || format == image::FMT_BGR888))
{
this->alpha = 0;
}
else if(this->format != image::FMT_GRAYSCALE && format == image::FMT_GRAYSCALE)
{
this->gray = (this->r + this->g + this->b) / 3;
this->r = this->gray;
this->g = this->gray;
this->b = this->gray;
this->alpha = 0;
}
this->format = format;
}
/**
* Convert color format and return a new Color object
* @param format format want to convert to, @see image::Format, only support RGB888, BGR888, RGBA8888, BGRA8888, GRAYSCALE.
* @return new Color object, you need to delete it manually in C++.
* @maixpy maix.image.Color.to_format2
*/
image::Color *to_format2(const image::Format &format)
{
image::Color *color = new image::Color(*this);
color->to_format(format);
return color;
}
};
/**
* Predefined color white
* @maixpy maix.image.COLOR_WHITE
*/
const image::Color COLOR_WHITE = image::Color::from_rgb(255, 255, 255);
/**
* Predefined color black
* @maixpy maix.image.COLOR_BLACK
*/
const image::Color COLOR_BLACK = image::Color::from_rgb(0, 0, 0);
/**
* Predefined color red
* @maixpy maix.image.COLOR_RED
*/
const image::Color COLOR_RED = image::Color::from_rgb(255, 0, 0);
/**
* Predefined color green
* @maixpy maix.image.COLOR_GREEN
*/
const image::Color COLOR_GREEN = image::Color::from_rgb(0, 255, 0);
/**
* Predefined color blue
* @maixpy maix.image.COLOR_BLUE
*/
const image::Color COLOR_BLUE = image::Color::from_rgb(0, 0, 255);
/**
* Predefined color yellow
* @maixpy maix.image.COLOR_YELLOW
*/
const image::Color COLOR_YELLOW = image::Color::from_rgb(255, 255, 0);
/**
* Predefined color purple
* @maixpy maix.image.COLOR_PURPLE
*/
const image::Color COLOR_PURPLE = image::Color::from_rgb(143, 0, 255);
/**
* Predefined color orange
* @maixpy maix.image.COLOR_ORANGE
*/
const image::Color COLOR_ORANGE = image::Color::from_rgb(255, 127, 0);
/**
* Predefined color gray
* @maixpy maix.image.COLOR_GRAY
*/
const image::Color COLOR_GRAY = image::Color::from_rgb(127, 127, 127);
}

View File

@@ -0,0 +1,313 @@
/**
* @author neucrack@sipeed, lxowalle@sipeed
* @copyright Sipeed Ltd 2023-
* @license Apache 2.0
* @update 2023.9.8: Add framework, create this file.
*/
#pragma once
#include <vector>
#include <string>
#include <map>
#include <stdint.h>
#include <stdexcept>
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.Format
*/
enum Format
{
FMT_RGB888 = 0, // RGBRGB...RGB, R at the lowest address
FMT_BGR888, // BGRBGR...BGR, B at the lowest address
FMT_RGBA8888, // RGBARGBA...RGBA, R at the lowest address
FMT_BGRA8888, // BGRABGRA...BGRA, B at the lowest address
FMT_RGB565,
FMT_BGR565,
FMT_YUV422SP, // YYY...UVUVUV...UVUV
FMT_YUV422P, // YYY...UUU...VVV
FMT_YVU420SP, // YYY...VUVUVU...VUVU, NV21
FMT_YUV420SP, // YYY...UVUVUV...UVUV, NV12
FMT_YVU420P, // YYY...VVV...UUU
FMT_YUV420P, // YYY...UUU...VVV
FMT_GRAYSCALE,
FMT_BGGR6, // 6-bit Bayer format with a BGGR pattern.
FMT_GBRG6, // 6-bit Bayer format with a GBRG pattern.
FMT_GRBG6, // 6-bit Bayer format with a GRBG pattern.
FMT_RGGB6, // 6-bit Bayer format with a RGGB pattern.
FMT_BGGR8, // 8-bit Bayer format with a BGGR pattern.
FMT_GBRG8, // 8-bit Bayer format with a GBRG pattern.
FMT_GRBG8, // 8-bit Bayer format with a GRBG pattern.
FMT_RGGB8, // 8-bit Bayer format with a RGGB pattern.
FMT_BGGR10, // 10-bit Bayer format with a BGGR pattern.
FMT_GBRG10, // 10-bit Bayer format with a GBRG pattern.
FMT_GRBG10, // 10-bit Bayer format with a GRBG pattern.
FMT_RGGB10, // 10-bit Bayer format with a RGGB pattern.
FMT_BGGR12, // 12-bit Bayer format with a BGGR pattern.
FMT_GBRG12, // 12-bit Bayer format with a GBRG pattern.
FMT_GRBG12, // 12-bit Bayer format with a GRBG pattern.
FMT_RGGB12, // 12-bit Bayer format with a RGGB pattern.
FMT_UNCOMPRESSED_MAX,
// compressed format below, not compressed should define upper
FMT_COMPRESSED_MIN,
FMT_JPEG,
FMT_PNG,
FMT_COMPRESSED_MAX,
FMT_INVALID = 0xFF // format not valid
}; // !!!! update this section please update fmt_size and fmt_names too !!!!
/**
* Image format size in bytes
* @attention It's a copy of this variable in MaixPy,
* so change it in C++ (e.g. update var in hello function) will not take effect the var inMaixPy.
* So we add const for this var to avoid this mistake.
* @maixpy maix.image.fmt_size
*/
const std::vector<float> fmt_size = {
3,
3,
4,
4,
2,
2,
2,
2,
1.5,
1.5,
1.5,
1.5,
1, // grayscale
0.75, // 6-bit Bayer format
0.75, // 6-bit Bayer format
0.75, // 6-bit Bayer format
0.75, // 6-bit Bayer format
1, // 8-bit Bayer format
1, // 8-bit Bayer format
1, // 8-bit Bayer format
1, // 8-bit Bayer format
1.25, // 10-bit Bayer format
1.25, // 10-bit Bayer format
1.25, // 10-bit Bayer format
1.25, // 10-bit Bayer format
1.5, // 12-bit Bayer format
1.5, // 12-bit Bayer format
1.5, // 12-bit Bayer format
1.5, // 12-bit Bayer format
0, // uncompereed_max
0, // compressed_min
1, // jpeg
1, // png
0, // compressed_max
0 // invalid
};
/**
* Image format string
* @maixpy maix.image.fmt_names
*/
const std::vector<std::string> fmt_names = {
"RGB888",
"BGR888",
"RGBA8888",
"BGRA8888",
"RGB565",
"BGR565",
"YUV422SP",
"YUV422P",
"YVU420SP",
"YUV420SP",
"YVU420P",
"YUV420P",
"GRAYSCALE",
"BGGR6",
"GBRG6",
"GRBG6",
"RG6B6",
"BGGR8",
"GBRG8",
"GRBG8",
"RG6B8",
"BGGR10",
"GBRG10",
"GRBG10",
"RG6B10",
"BGGR12",
"GBRG12",
"GRBG12",
"RG6B12",
"UNCOMPRESSED_MAX",
"COMPRESSED_MIN",
"JPEG",
"PNG",
"COMPRESSED_MAX",
"INVALID"
};
/**
* Image size type
* @maixpy maix.image.Size
*/
class Size
{
public:
/**
* Construct a new Size object
* @param width image width
* @param height image height
* @maixpy maix.image.Size.__init__
*/
Size(int width = 0, int height = 0)
{
this->_width = width;
this->_height = height;
}
/**
* width of size
* @param width set new width, if not set, only return current width
* @maixpy maix.image.Size.width
*/
int width(int width = -1)
{
if(width != -1)
{
this->_width = width;
}
return this->_width;
}
/**
* height of size
* @param height set new height, if not set, only return current height
* @maixpy maix.image.Size.height
*/
int height(int height = -1)
{
if(height != -1)
{
this->_height = height;
}
return this->_height;
}
/**
* Subscript operator
* @param index 0 for width, 1 for height
* @return int& width or height
* @maixpy maix.image.Size.__getitem__
* @maixcdk maix.image.Size.operator[]
*/
int &operator[](int index)
{
if (index == 0)
return _width;
else if (index == 1)
return _height;
else
throw std::out_of_range("Size index out of range");
}
/**
* to string
* @maixpy maix.image.Size.__str__
*/
std::string __str__()
{
return "Size(" + std::to_string(_width) + "x" + std::to_string(_height) + ")";
}
private:
int _width;
int _height;
};
/**
* Object fit method
* @maixpy maix.image.Fit
*/
enum Fit
{
FIT_NONE = -1, // no object fit, keep original
FIT_FILL = 0, // width to new width, height to new height, may be stretch
FIT_CONTAIN, // keep aspect ratio, fill blank area with black color
FIT_COVER, // keep aspect ratio, crop image to fit new size
FIT_MAX
};
/**
* Resize method
* @maixpy maix.image.ResizeMethod
*/
enum ResizeMethod
{
NEAREST = 0,
BILINEAR,
BICUBIC,
AREA,
LANCZOS,
HAMMING,
RESIZE_METHOD_MAX
};
/**
* Family of apriltag
* @maixpy maix.image.ApriltagFamilies
*/
enum ApriltagFamilies
{
TAG16H5 = 1,
TAG25H7 = 2,
TAG25H9 = 4,
TAG36H10 = 8,
TAG36H11 = 16,
ARTOOLKIT = 32
};
/**
* Template match method
* @maixpy maix.image.TemplateMatch
*/
enum TemplateMatch
{
SEARCH_EX, // Exhaustive search
SEARCH_DS, // Diamond search
};
/**
* CornerDetector class
* @maixpy maix.image.CornerDetector
*/
enum CornerDetector
{
CORNER_FAST,
CORNER_AGAST
};
/**
* EdgeDetector class
* @maixpy maix.image.EdgeDetector
*/
enum EdgeDetector
{
EDGE_CANNY,
EDGE_SIMPLE,
};
/**
* FlipDir
* @maixpy maix.image.FlipDir
*/
enum class FlipDir
{
X,
Y,
XY
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
#include "maix_image.hpp"
#include "maix_display.hpp"
#include "maix_camera.hpp"
#include "maix_video.hpp"

View File

@@ -0,0 +1,17 @@
#pragma once
#include "maix_image.hpp"
#include "omv.hpp"
namespace maix::image
{
/**
* Convert image to openmv image format
* @param image image
* @param imlib_image openmv image
* @return
*/
extern void convert_to_imlib_image(image::Image *image, image_t *imlib_image);
extern void _convert_to_lab_thresholds(std::vector<std::vector<int>> &in, list_t *out);
}

View File

@@ -0,0 +1,317 @@
/**
* @author lxowalle@sipeed
* @copyright Sipeed Ltd 2023-
* @license Apache 2.0
* @update 2023.9.8: Add framework, create this file.
*/
#pragma once
#include <stdint.h>
#include "maix_err.hpp"
#include "maix_basic.hpp"
#include "maix_log.hpp"
#include "maix_image.hpp"
#include "maix_time.hpp"
#include "maix_camera_base.hpp"
#include "kvm_mmf.hpp"
#include <signal.h>
static void try_deinit_mmf()
{
static uint8_t is_called = 0;
if (!is_called) {
mmf_try_deinit(true);
is_called = 1;
}
}
static void signal_handle(int signal)
{
const char *signal_msg = NULL;
switch (signal) {
case SIGILL: signal_msg = "SIGILL"; break;
case SIGTRAP: signal_msg = "SIGTRAP"; break;
case SIGABRT: signal_msg = "SIGABRT"; break;
case SIGBUS: signal_msg = "SIGBUS"; break;
case SIGFPE: signal_msg = "SIGFPE"; break;
case SIGKILL: signal_msg = "SIGKILL"; break;
case SIGSEGV: signal_msg = "SIGSEGV"; break;
default: signal_msg = "UNKNOWN"; break;
}
maix::log::error("Trigger signal, code:%s(%d)!\r\n", signal_msg, signal);
try_deinit_mmf();
exit(1);
}
// FIXME: move this function to port/maix_vision_maixcam.cpp ?
static __attribute__((constructor)) void maix_vision_register_signal(void)
{
signal(SIGILL, signal_handle);
signal(SIGTRAP, signal_handle);
signal(SIGABRT, signal_handle);
signal(SIGBUS, signal_handle);
signal(SIGFPE, signal_handle);
signal(SIGKILL, signal_handle);
signal(SIGSEGV, signal_handle);
maix::util::register_exit_function(try_deinit_mmf);
}
namespace maix::camera
{
class CameraCviMmf final : public CameraBase
{
public:
CameraCviMmf(const std::string device, int width, int height, image::Format format, int buff_num)
{
this->device = device;
this->format = format;
this->width = width;
this->height = height;
this->buffer_num = buff_num;
this->ch = -1;
if (0 != mmf_init()) {
err::check_raise(err::ERR_RUNTIME, "mmf init failed");
}
if (0 != mmf_vi_init()) {
err::check_raise(err::ERR_RUNTIME, "mmf vi init failed");
}
}
CameraCviMmf(const std::string device, int ch, int width, int height, image::Format format, int buff_num)
{
this->device = device;
this->format = format;
this->width = width;
this->height = height;
this->buffer_num = buff_num;
this->ch = ch;
if (0 != mmf_init()) {
err::check_raise(err::ERR_RUNTIME, "mmf init failed");
}
if (0 != mmf_vi_init()) {
err::check_raise(err::ERR_RUNTIME, "mmf vi init failed");
}
}
~CameraCviMmf()
{
mmf_del_vi_channel(this->ch);
if (0 != mmf_vi_deinit()) {
err::check_raise(err::ERR_RUNTIME, "mmf vi init failed");
}
mmf_try_deinit(true);
}
err::Err open(int width, int height, image::Format format, int buff_num)
{
if (format == image::FMT_GRAYSCALE) {
format = image::FMT_YVU420SP;
}
int ch = mmf_get_vi_unused_channel();
if (ch < 0) {
log::error("camera open: mmf get vi channel failed");
return err::ERR_RUNTIME;
}
if (0 != mmf_add_vi_channel(ch, width, height, mmf_invert_format_to_mmf(format))) {
log::error("camera open: mmf add vi channel failed");
return err::ERR_RUNTIME;
}
this->ch = ch;
this->width = (width == -1) ? this->width : width;
this->height = (height == -1) ? this->height : height;
this->align_width = mmf_vi_aligned_width(this->ch);
this->align_need = (this->width % this->align_width == 0) ? false : true; // Width need align only
return err::ERR_NONE;
} // open
bool is_support_format(image::Format format)
{
if(format == image::Format::FMT_RGB888 || format == image::Format::FMT_BGR888
|| format == image::Format::FMT_YVU420SP|| format == image::Format::FMT_GRAYSCALE)
return true;
return false;
}
void close()
{
if (mmf_vi_chn_is_open(this->ch) == true) {
if (0 != mmf_del_vi_channel(this->ch)) {
log::error("mmf del vi channel failed");
}
}
} // close
// read
image::Image *read(void *buff = NULL, size_t buff_size = 0)
{
// printf("Func: maix_image.cpp read\r\n");
image::Image *img = NULL;
void *buffer = NULL;
int buffer_len = 0, width = 0, height = 0, format = 0;
if (0 == mmf_vi_frame_pop(this->ch, &buffer, &buffer_len, &width, &height, &format)) {
if (buffer == NULL) {
mmf_vi_frame_free(this->ch);
printf("mmf_vi_frame_free error\r\n");
return NULL;
}
if(buff)
{
if(buff_size < (size_t)buffer_len)
{
log::error("camera read: buff size not enough, need %d, but %d", buffer_len, buff_size);
mmf_vi_frame_free(this->ch);
return NULL;
}
img = new image::Image(width, height, this->format, (uint8_t*)buff, buff_size, false);
}
else
{
img = new image::Image(this->width, this->height, this->format);
}
void *image_data = img->data();
switch (img->format()) {
case image::Format::FMT_GRAYSCALE:
if (this->align_need) {
for (int h = 0; h < this->height; h ++) {
memcpy((uint8_t *)image_data + h * this->width, (uint8_t *)buffer + h * width, this->width);
}
} else {
memcpy(image_data, buffer, this->width * this->height);
}
break;
case image::Format::FMT_BGR888: // fall through
case image::Format::FMT_RGB888:
if (this->align_need) {
for (int h = 0; h < this->height; h++) {
memcpy((uint8_t *)image_data + h * this->width * 3, (uint8_t *)buffer + h * width * 3, this->width * 3);
}
} else {
memcpy(image_data, buffer, this->width * this->height * 3);
}
break;
case image::Format::FMT_YVU420SP:
if (this->align_need) {
for (int h = 0; h < this->height * 3 / 2; h ++) {
memcpy((uint8_t *)image_data + h * this->width, (uint8_t *)buffer + h * width, this->width);
}
} else {
memcpy(image_data, buffer, this->width * this->height * 3 / 2);
}
break;
default:
printf("unknown format\n");
delete img;
mmf_vi_frame_free(this->ch);
printf("switch (img->format()\r\n");
return NULL;
}
mmf_vi_frame_free(this->ch);
// printf("mmf_vi_frame_free\r\n");
return img;
}
return img;
} // read
camera::CameraCviMmf *add_channel(int width, int height, image::Format format, int buff_num)
{
int new_channel = mmf_get_vi_unused_channel();
if (new_channel < 0) {
log::error("Support not more channel!\r\n");
return NULL;
}
return new camera::CameraCviMmf(this->device, new_channel, width, height, format, buff_num);
}
void clear_buff()
{
}
bool is_opened() {
return mmf_vi_chn_is_open(this->ch);
}
int get_ch_nums() {
return 1;
}
int get_channel() {
return this->ch;
}
int hmirror(int en)
{
bool out;
if (en == -1) {
mmf_get_vi_hmirror(this->ch, &out);
} else {
bool need_open = false;
if (this->is_opened()) {
this->close();
need_open = true;
}
mmf_set_vi_hmirror(this->ch, en);
if (need_open) {
err::check_raise(this->open(this->width, this->height, this->format, this->buffer_num), "Open failed");
}
out = en;
}
return out;
}
int vflip(int en)
{
bool out;
if (en == -1) {
mmf_get_vi_vflip(this->ch, &out);
} else {
bool need_open = false;
if (this->is_opened()) {
this->close();
need_open = true;
}
mmf_set_vi_vflip(this->ch, en);
if (need_open) {
err::check_raise(this->open(this->width, this->height, this->format, this->buffer_num), "Open failed");
}
out = en;
}
return out;
}
private:
std::string device;
image::Format format;
int fd;
int ch;
uint32_t raw_format;
std::vector<void*> buffers;
std::vector<int> buffers_len;
int buffer_num;
int queue_id; // user directly used buffer id
int width;
int height;
void *buff;
bool buff_alloc;
int align_width;
bool align_need;
};
} // namespace maix::camera

View File

@@ -0,0 +1,425 @@
/**
* @author neucrack@sipeed, lxowalle@sipeed
* @copyright Sipeed Ltd 2023-
* @license Apache 2.0
* @update 2023.9.8: Add framework, create this file.
*/
#include "maix_camera.hpp"
#include <dirent.h>
#ifdef PLATFORM_LINUX
#include "maix_camera_v4l2.hpp"
#endif
#ifdef PLATFORM_MAIXCAM
#include "maix_camera_mmf.hpp"
#endif
namespace maix::camera
{
static bool set_regs_flag = false;
std::vector<std::string> list_devices()
{
// find to /dev/video*
std::vector<std::string> devices;
std::string path = "/dev";
DIR *dir = opendir(path.c_str());
if (dir == NULL)
{
return devices;
}
struct dirent *ptr;
while ((ptr = readdir(dir)) != NULL)
{
if (ptr->d_type == DT_CHR)
{
std::string name = ptr->d_name;
if (name.find("video") != std::string::npos)
{
devices.push_back( path + "/" + name );
}
}
}
closedir(dir);
// sort devices with name
std::sort(devices.begin(), devices.end());
// print devices
for (size_t i = 0; i < devices.size(); i++)
{
log::debug("find device: %s\n", devices[i].c_str());
}
return devices;
}
void set_regs_enable(bool enable) {
set_regs_flag = enable;
}
err::Err Camera::show_colorbar(bool enable)
{
// only set variable now
// should control camera to show colorbar
_show_colorbar = enable;
return err::ERR_NONE;
}
static void generate_colorbar(image::Image &img)
{
int width = img.width();
int height = img.height();
int step = width / 8;
int color_step = 255 / 7;
int color = 0;
uint8_t colors[8][3] = {
{255, 255, 255},
{255, 0, 0},
{255, 127, 0},
{255, 255, 0},
{0, 255, 0},
{0, 0, 255},
{143, 0, 255},
{0, 0, 0},
};
for (int i = 0; i < 8; i++)
{
image::Color _color(colors[i][0], colors[i][1], colors[i][2], 0, image::FMT_RGB888);
img.draw_rect(i * step, 0, step, height, _color, -1);
color += color_step;
}
}
#ifdef PLATFORM_LINUX
static char * _get_device(const char *device)
{
if (device)
{
return (char *)device;
}
else
{
std::vector<std::string> devices = list_devices();
err::check_bool_raise(devices.size() > 0, "No camera device");
return (char *)devices[0].c_str();
}
}
#endif
Camera::Camera(int width, int height, image::Format format, const char *device, int fps, int buff_num, bool open)
{
err::Err e;
err::check_bool_raise(_check_format(format), "Format not support");
if (format == image::Format::FMT_RGB888 && width * height * 3 > 640 * 640 * 3) {
log::warn("Note that we do not recommend using large resolution RGB888 images, which can take up a lot of memory!\r\n");
}
_width = (width == -1) ? 640 : width;
_height = (height == -1) ? 480 : height;
_format = format;
_fps = (fps == -1) ? 30 : fps;
_buff_num = buff_num;
_show_colorbar = false;
_open_set_regs = set_regs_flag;
_impl = NULL;
#ifdef PLATFORM_LINUX
_device = _get_device(device);
_impl = new CameraV4L2(_device, _width, _height, _format, _buff_num);
#endif
#ifdef PLATFORM_MAIXCAM
_device = "";
_impl = new CameraCviMmf(_device, _width, _height, _format, _buff_num);
#endif
if (open) {
e = this->open(_width, _height, _format, _buff_num);
// err::check_raise(e, "camera open failed");
}
}
Camera::Camera(const char *device, CameraBase *base, int width, int height, image::Format format, int fps, int buff_num, bool open)
{
err::Err e;
err::check_bool_raise(_check_format(format), "Format not support");
_width = (width == -1) ? 640 : width;
_height = (height == -1) ? 480 : height;
_format = format;
_fps = (fps == -1) ? 30 : fps;
_buff_num = buff_num;
_show_colorbar = false;
_open_set_regs = set_regs_flag;
_impl = base;
if (open) {
e = this->open(_width, _height, _format, _buff_num);
err::check_raise(e, "camera open failed");
}
}
Camera::~Camera()
{
if (this->is_opened()) {
this->close();
}
#ifdef PLATFORM_LINUX
delete (CameraV4L2*)_impl;
#endif
#ifdef PLATFORM_MAIXCAM
delete (CameraCviMmf*)_impl;
#endif
}
void Camera::restart(int width, int height, image::Format format, const char *device, int fps, int buff_num, bool open)
{
if (this->is_opened()) {
this->close();
}
#ifdef PLATFORM_LINUX
delete (CameraV4L2*)_impl;
#endif
#ifdef PLATFORM_MAIXCAM
delete (CameraCviMmf*)_impl;
#endif
err::Err e;
err::check_bool_raise(_check_format(format), "Format not support");
if (format == image::Format::FMT_RGB888 && width * height * 3 > 640 * 640 * 3) {
log::warn("Note that we do not recommend using large resolution RGB888 images, which can take up a lot of memory!\r\n");
}
_width = (width == -1) ? 640 : width;
_height = (height == -1) ? 480 : height;
_format = format;
_fps = (fps == -1) ? 30 : fps;
_buff_num = buff_num;
_show_colorbar = false;
_open_set_regs = set_regs_flag;
_impl = NULL;
#ifdef PLATFORM_LINUX
_device = _get_device(device);
_impl = new CameraV4L2(_device, _width, _height, _format, _buff_num);
#endif
#ifdef PLATFORM_MAIXCAM
_device = "";
_impl = new CameraCviMmf(_device, _width, _height, _format, _buff_num);
#endif
if (open) {
e = this->open(_width, _height, _format, _buff_num);
// err::check_raise(e, "camera open failed");
}
}
int Camera::get_ch_nums()
{
return 2;
}
int Camera::get_channel()
{
if (_impl == NULL)
return err::ERR_NOT_INIT;
if (!this->is_opened()) {
return err::ERR_NOT_OPEN;
}
return _impl->get_channel();
}
bool Camera::_check_format(image::Format format) {
if (format == image::FMT_RGB888 || format == image::FMT_BGR888
|| format == image::FMT_RGBA8888 || format == image::FMT_BGRA8888
|| format == image::FMT_YVU420SP || format == image::FMT_GRAYSCALE) {
return true;
} else {
return false;
}
}
err::Err Camera::open(int width, int height, image::Format format, int fps, int buff_num)
{
if (_impl == NULL)
return err::Err::ERR_RUNTIME;
int width_tmp = (width == -1) ? _width : width;
int height_tmp = (height == -1) ? _height : height;
image::Format format_tmp = (format == image::FMT_INVALID) ? _format : format;
int fps_tmp = (fps == -1) ? 30 : fps;
int buff_num_tmp =( buff_num == -1) ? _buff_num : buff_num;
err::check_bool_raise(_check_format(format_tmp), "Format not support");
if (this->is_opened()) {
if (width == width_tmp && height == height_tmp && format == format_tmp && fps == fps_tmp && buff_num == buff_num_tmp) {
return err::ERR_NONE;
}
this->close(); // Get new param, close and reopen
}
_width = width_tmp;
_height = height_tmp;
_fps = fps_tmp;
_buff_num = buff_num_tmp;
_format = format_tmp;
_format_impl = _format;
if(!_impl->is_support_format(_format))
{
if(_impl->is_support_format(image::FMT_RGB888))
_format_impl = image::FMT_RGB888;
else if(_impl->is_support_format(image::FMT_BGR888))
_format_impl = image::FMT_BGR888;
else if(_impl->is_support_format(image::FMT_YVU420SP))
_format_impl = image::FMT_YVU420SP;
else if(_impl->is_support_format(image::FMT_YUV420SP))
_format_impl = image::FMT_YUV420SP;
else if(_impl->is_support_format(image::FMT_RGBA8888))
_format_impl = image::FMT_RGBA8888;
else if(_impl->is_support_format(image::FMT_BGRA8888))
_format_impl = image::FMT_BGRA8888;
else if(_impl->is_support_format(image::FMT_GRAYSCALE))
_format_impl = image::FMT_GRAYSCALE;
else
return err::ERR_ARGS;
}
return _impl->open(_width, _height, _format_impl, _buff_num);;
}
void Camera::close()
{
if (this->is_closed())
return;
_impl->close();
}
camera::Camera *Camera::add_channel(int width, int height, image::Format format, int fps, int buff_num, bool open)
{
err::check_bool_raise(_check_format(format), "Format not support");
int width_tmp = (width == -1) ? _width : width;
int height_tmp = (height == -1) ? _height : height;
image::Format format_tmp = (format == image::Format::FMT_INVALID) ? _format : format;
int fps_tmp = (fps == -1) ? _fps : fps;
int buff_num_tmp = buff_num == -1 ? _buff_num : buff_num;
Camera *cam = NULL;
if (_impl) {
CameraBase *cam_base = _impl->add_channel(width_tmp, height_tmp, format_tmp, buff_num);
err::check_bool_raise(cam_base, "Unable to add a new channel. Please check the maximum number of supported channels.");
cam = new Camera(_device.c_str(), cam_base, width_tmp, height_tmp, format_tmp, fps_tmp, buff_num_tmp, open);
}
return cam;
}
bool Camera::is_opened()
{
if (_impl == NULL)
return false;
return _impl->is_opened();
}
image::Image *Camera::read(void *buff, size_t buff_size, bool block)
{
if (!this->is_opened()) {
// err::Err e = open(_width, _height, _format, _buff_num);
// err::check_raise(e, "open camera failed");
return NULL;
}
if (_show_colorbar) {
image::Image *img = new image::Image(_width, _height);
generate_colorbar(*img);
err::check_null_raise(img, "camera read failed");
return img;
} else {
// it's better all done by impl to faster read, but if impl not support, we have to convert it
if(_format_impl == _format)
{
image::Image *img = _impl->read(buff, buff_size);
// err::check_null_raise(img, "camera read failed");
return img;
}
else
{
image::Image *img = _impl->read();
image::Image *img2 = img->to_format(_format, buff, buff_size);
delete img;
// err::check_null_raise(img2, "camera read failed");
return img2;
}
}
}
void Camera::clear_buff()
{
if (_impl == NULL)
return;
_impl->clear_buff();
}
void Camera::skip_frames(int num)
{
if (_impl == NULL)
return;
for(int i = 0; i < num; i++)
{
image::Image *img = _impl->read();
delete img;
}
}
err::Err Camera::set_resolution(int width, int height)
{
err::Err e;
if (_impl == NULL)
return err::ERR_NOT_INIT;
if (this->is_opened()) {
this->close();
}
_width = width;
_height = height;
e = this->open(_width, _height, _format, _buff_num);
err::check_raise(e, "camera open failed");
return err::ERR_NONE;
}
int Camera::hmirror(int value) {
if (_impl == NULL)
return err::ERR_NOT_INIT;
if (!this->is_opened()) {
return err::ERR_NOT_OPEN;
}
return _impl->hmirror(value);
}
int Camera::vflip(int value) {
if (_impl == NULL)
return err::ERR_NOT_INIT;
if (!this->is_opened()) {
return err::ERR_NOT_OPEN;
}
return _impl->vflip(value);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff