Showing preview only (2,265K chars total). Download the full file or copy to clipboard to get everything.
Repository: Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB
Branch: master
Commit: dffdddda9794
Files: 168
Total size: 18.5 MB
Directory structure:
gitextract_rj4enlci/
├── .gitignore
├── .gitmodules
├── LICENSE
├── MNN/
│ ├── CMakeLists.txt
│ ├── README.md
│ ├── mnn/
│ │ └── include/
│ │ ├── AutoTime.hpp
│ │ ├── Backend.hpp
│ │ ├── ErrorCode.hpp
│ │ ├── HalideRuntime.h
│ │ ├── ImageProcess.hpp
│ │ ├── Interpreter.hpp
│ │ ├── MNNDefine.h
│ │ ├── MNNForwardType.h
│ │ ├── MNNSharedContext.h
│ │ ├── Matrix.h
│ │ ├── NonCopyable.hpp
│ │ ├── Rect.h
│ │ ├── Tensor.hpp
│ │ └── revertMNNModel.hpp
│ ├── model/
│ │ ├── version-RFB/
│ │ │ ├── RFB-320-quant-ADMM-32.mnn
│ │ │ ├── RFB-320-quant-KL-5792.mnn
│ │ │ └── RFB-320.mnn
│ │ └── version-slim/
│ │ ├── slim-320-quant-ADMM-50.mnn
│ │ └── slim-320.mnn
│ ├── python/
│ │ ├── README.md
│ │ └── ultraface_py_mnn.py
│ └── src/
│ ├── UltraFace.cpp
│ ├── UltraFace.hpp
│ └── main.cpp
├── README.md
├── README_CN.md
├── caffe/
│ ├── MyCaffe.py
│ ├── README.md
│ ├── convertCaffe.py
│ ├── model/
│ │ ├── RFB-320/
│ │ │ ├── RFB-320.caffemodel
│ │ │ └── RFB-320.prototxt
│ │ └── Slim-320/
│ │ ├── slim-320.caffemodel
│ │ └── slim-320.prototxt
│ ├── onnx2caffe/
│ │ ├── __init__.py
│ │ ├── _error_utils.py
│ │ ├── _graph.py
│ │ ├── _operators.py
│ │ ├── _transformers.py
│ │ └── _weightloader.py
│ ├── ultra_face_caffe_inference.py
│ └── ultra_face_opencvdnn_inference.py
├── cal_flops.py
├── check_gt_box.py
├── convert_to_onnx.py
├── data/
│ ├── retinaface_labels/
│ │ ├── test/
│ │ │ └── label.txt
│ │ ├── train/
│ │ │ └── label.txt
│ │ └── val/
│ │ └── label.txt
│ └── wider_face_2_voc_add_landmark.py
├── detect_imgs.py
├── detect_imgs_onnx.py
├── masked_face/
│ ├── README.md
│ ├── detect_imgs.py
│ ├── mafa2voc.py
│ ├── pretrained/
│ │ ├── RFB-1280-masked_face-v2.onnx
│ │ ├── RFB-320-masked_face-v2.pth
│ │ ├── RFB-640-masked_face-v2.onnx
│ │ └── RFB-640-masked_face-v2.pth
│ └── voc-model-labels.txt
├── models/
│ ├── onnx/
│ │ ├── version-RFB-320.onnx
│ │ ├── version-RFB-320_simplified.onnx
│ │ ├── version-RFB-320_without_postprocessing.onnx
│ │ ├── version-RFB-640.onnx
│ │ ├── version-slim-320.onnx
│ │ ├── version-slim-320_simplified.onnx
│ │ └── version-slim-320_without_postprocessing.onnx
│ ├── pretrained/
│ │ ├── version-RFB-320.pth
│ │ ├── version-RFB-640.pth
│ │ ├── version-slim-320.pth
│ │ └── version-slim-640.pth
│ ├── readme
│ └── voc-model-labels.txt
├── ncnn/
│ ├── .clang-format
│ ├── CMakeLists.txt
│ ├── README.md
│ ├── data/
│ │ ├── version-RFB/
│ │ │ └── RFB-320.param
│ │ └── version-slim/
│ │ └── slim_320.param
│ └── src/
│ ├── UltraFace.cpp
│ ├── UltraFace.hpp
│ └── main.cpp
├── opencv_dnn/
│ ├── cv_dnn_ultraface.cpp
│ └── cv_dnn_ultraface.h
├── paddle/
│ ├── train-version-RFB.sh
│ ├── train-version-slim.sh
│ ├── train.py
│ └── vision/
│ ├── __init__.py
│ ├── datasets/
│ │ ├── __init__.py
│ │ └── voc_dataset.py
│ ├── nn/
│ │ ├── __init__.py
│ │ ├── mb_tiny.py
│ │ ├── mb_tiny_RFB.py
│ │ └── multibox_loss.py
│ ├── ssd/
│ │ ├── __init__.py
│ │ ├── config/
│ │ │ ├── __init__.py
│ │ │ └── fd_config.py
│ │ ├── data_preprocessing.py
│ │ ├── mb_tiny_RFB_fd.py
│ │ ├── mb_tiny_fd.py
│ │ ├── predictor.py
│ │ └── ssd.py
│ ├── transforms/
│ │ ├── __init__.py
│ │ └── transforms.py
│ └── utils/
│ ├── __init__.py
│ ├── box_utils.py
│ ├── box_utils_numpy.py
│ └── misc.py
├── requirements.txt
├── run_video_face_detect.py
├── run_video_face_detect_onnx.py
├── tf/
│ ├── README.md
│ ├── backend/
│ │ ├── op.py
│ │ └── utils.py
│ ├── convert_tensorflow.py
│ ├── det_image.py
│ ├── export_models/
│ │ ├── RFB/
│ │ │ ├── saved_model.pb
│ │ │ └── variables/
│ │ │ ├── variables.data-00000-of-00001
│ │ │ └── variables.index
│ │ └── slim/
│ │ ├── saved_model.pb
│ │ └── variables/
│ │ ├── variables.data-00000-of-00001
│ │ └── variables.index
│ ├── mapping_tables/
│ │ ├── rfb_320.json
│ │ └── slim_320.json
│ └── model/
│ ├── rfb_320.py
│ └── slim_320.py
├── tflite/
│ ├── README.md
│ ├── TFLiteFaceDetector.py
│ ├── inference_test.py
│ ├── model/
│ │ ├── tflite_RFB_320_without_postprocessing.py
│ │ └── tflite_slim_320_without_postprocessing.py
│ └── pretrained/
│ ├── version-RFB-320_without_postprocessing.tflite
│ └── version-slim-320_without_postprocessing.tflite
├── train-version-RFB.sh
├── train-version-slim.sh
├── train.py
├── vision/
│ ├── __init__.py
│ ├── datasets/
│ │ ├── __init__.py
│ │ └── voc_dataset.py
│ ├── nn/
│ │ ├── __init__.py
│ │ ├── mb_tiny.py
│ │ ├── mb_tiny_RFB.py
│ │ └── multibox_loss.py
│ ├── ssd/
│ │ ├── __init__.py
│ │ ├── config/
│ │ │ ├── __init__.py
│ │ │ └── fd_config.py
│ │ ├── data_preprocessing.py
│ │ ├── mb_tiny_RFB_fd.py
│ │ ├── mb_tiny_fd.py
│ │ ├── predictor.py
│ │ └── ssd.py
│ ├── transforms/
│ │ ├── __init__.py
│ │ └── transforms.py
│ └── utils/
│ ├── __init__.py
│ ├── box_utils.py
│ ├── box_utils_numpy.py
│ └── misc.py
└── widerface_evaluate/
├── README.md
├── box_overlaps.pyx
├── evaluation.py
├── evaluation_on_widerface.py
├── ground_truth/
│ ├── wider_easy_val.mat
│ ├── wider_face_val.mat
│ ├── wider_hard_val.mat
│ └── wider_medium_val.mat
└── setup.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.idea
data/wider_face_add_lm_10_10
__pycache__/
*.py[cod]
*$py.class
detect_imgs_results
detect_imgs_results_onnx
widerface_evaluation
widerface_evaluate/build
widerface_evaluate/*.so
widerface_evaluate/*.c
================================================
FILE: .gitmodules
================================================
[submodule "ncnn/3rdparty/ncnn"]
path = ncnn/3rdparty/ncnn
url = https://github.com/Tencent/ncnn
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 linzai
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: MNN/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.10)
project(Ultra-face-mnn)
set(CMAKE_CXX_STANDARD 11)
find_package(OpenCV REQUIRED)
include_directories(
mnn/include
src
)
link_directories(mnn/lib)
add_executable(Ultra-face-mnn src/main.cpp src/UltraFace.cpp)
target_link_libraries(Ultra-face-mnn MNN ${OpenCV_LIBS})
================================================
FILE: MNN/README.md
================================================
# C++ implemententation of [Ultra-Light-Fast-Generic-Face-Detector-1MB](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB) with [MNN](https://github.com/alibaba/MNN)
## Build
```bash
git clone --recursive --depth=1 https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB
cd Ultra-Light-Fast-Generic-Face-Detector-1MB/MNN
```
* Replace **libMNN.so** under ./mnn/lib with your compiled libMNN.so and then :
```bash
mkdir build && cd build && cmake ..
make -j$(nproc)
```
## Run
* Use FP32 model and run in FP16 mode:
```bash
./Ultra-face-mnn ../model/version-RFB/RFB-320.mnn ../imgs/1.jpg ../imgs/2.jpg ../imgs/3.jpg ../imgs/4.jpg
```
* Use quantized INT8 model:
```bash
./Ultra-face-mnn ../model/version-RFB/RFB-320-quant-KL-5792.mnn ../imgs/1.jpg ../imgs/2.jpg ../imgs/3.jpg ../imgs/4.jpg
```
* We provide both converted MNN FP32 and **quantized INT8** models of version-slim-320 and version-RFB-320 in ./MNN/model . The xxx-quant-KL-xxx.mnn is quantified by the **KL** method and xxx-quant-ADMM-xxx.mnn is quantified by the **ADMM** method.
## How to convert pretrained model to MNN
* Code bellow (```vision/ssd/ssd.py```) should be commented out when convert pytorch pretrained model to onnx. Comment it out and use the **convert_to_onnx.py** in official repo to finish this step.
```python
if self.is_test:
confidences = F.softmax(confidences, dim=2)
boxes = locations # this line should be added.
#boxes = box_utils.convert_locations_to_boxes(
# locations, self.priors, self.config.center_variance, self.config.size_variance
#)
# boxes = box_utils.center_form_to_corner_form(boxes) # these lines should be commented out. detail information and analyze comming soon.
return confidences, boxes
else:
return confidences, locations
```
Then you can generate the onnx model like **version-RFB-320_without_postprocessing.onnx** in onnx directory. (You need to rename your model when convert.)
* Then we can use this tool to simplify onnx :
https://github.com/daquexian/onnx-simplifier
```
python3 -m onnxsim version-RFB-320_without_postprocessing.onnx version-RFB-320_simplified.onnx
```
Next, you can convert this onnx model like **version-RFB-320_simplified.onnx** into a MNN model. Here is a website for online conversion : https://convertmodel.com. You can also use the MNN compiled conversion tool **MNNConvert**.
## PS
* Since MNN mainly accelerates model inference on mobile, so the INT8 quantified model will run slower on **PC** than FP32 model in CPU mode.
* If you want to run faster, try using the version-slim model ,using lower-resolution inputs like 160x120 /128x96 or using quantified models(On the mobile).
## Result

================================================
FILE: MNN/mnn/include/AutoTime.hpp
================================================
//
// AutoTime.hpp
// MNN
//
// Created by MNN on 2018/07/27.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef AutoTime_hpp
#define AutoTime_hpp
#include <stdint.h>
#include <stdio.h>
#include "MNNDefine.h"
namespace MNN {
/** time tracing util. prints duration between init and deinit. */
class MNN_PUBLIC AutoTime {
public:
AutoTime(int line, const char* func);
~AutoTime();
AutoTime(const AutoTime&) = delete;
AutoTime(const AutoTime&&) = delete;
AutoTime& operator=(const AutoTime&) = delete;
AutoTime& operator=(const AutoTime&&) = delete;
private:
int mLine;
char* mName;
uint64_t mCurrentTime;
};
} // namespace MNN
#ifdef MNN_OPEN_TIME_TRACE
#define AUTOTIME MNN::AutoTime ___t(__LINE__, __func__)
#else
#define AUTOTIME
#endif
#endif /* AutoTime_hpp */
================================================
FILE: MNN/mnn/include/Backend.hpp
================================================
//
// Backend.hpp
// MNN
//
// Created by MNN on 2018/07/06.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef Backend_hpp
#define Backend_hpp
#include <stdio.h>
#include <map>
#include <memory>
#include <vector>
#include "ErrorCode.hpp"
#include "MNNForwardType.h"
#include "NonCopyable.hpp"
#include "Tensor.hpp"
namespace MNN {
struct Op;
struct GpuLibrary;
class Execution;
/** abstract backend */
class Backend : public NonCopyable {
public:
/** info used to create backend */
struct Info {
/** forward type. */
MNNForwardType type = MNN_FORWARD_CPU;
/** for CPU only. number of threads. */
int numThread = 4;
/** user data. */
BackendConfig* user = NULL;
enum Mode {
// The Op will be run in execution->onExecute
DIRECT = 0,
// The Op will be recorded. Run in onExecuteBegin and Wait in onExecuteEnd
INDIRECT = 1
};
Mode mode = DIRECT;
};
/** backend buffer storage type */
enum StorageType {
/**
use NOT reusable memory.
- allocates memory when `onAcquireBuffer` is called.
- releases memory when `onReleaseBuffer` is called or when the backend is deleted.
- do NOTHING when `onClearBuffer` is called.
*/
STATIC,
/**
use reusable memory.
- allocates or reuses memory when `onAcquireBuffer` is called. prefers reusing.
- collects memory for reuse when `onReleaseBuffer` is called.
- releases memory when `onClearBuffer` is called or when the backend is deleted.
*/
DYNAMIC,
/**
use NOT reusable memory.
- allocates memory when `onAcquireBuffer` is called.
- do NOTHING when `onReleaseBuffer` is called.
- releases memory when `onClearBuffer` is called or when the backend is deleted.
*/
DYNAMIC_SEPERATE
};
public:
/**
* @brief initializer.
* @param type forward type.
*/
Backend(MNNForwardType type) : mType(type) {
// nothing to do
}
/**
* @brief deinitializer.
*/
virtual ~Backend() = default;
public:
/**
* @brief measure the cost for op with input and output tensors.
* @param inputs input tensors.
* @param outputs output tensors.
* @param op given op.
* @return std::make_pair(timeDelayInMs, support);
*/
virtual std::pair<float, bool> onMeasure(const std::vector<Tensor*>& inputs, const std::vector<Tensor*>& outputs,
const MNN::Op* op) {
return std::make_pair(0.0f, false);
}
/**
* @brief create execution for op with input and output tensors.
* @param inputs input tensors.
* @param outputs output tensors.
* @param op given op.
* @return created execution if op is supported, nullptr otherwise.
*/
virtual Execution* onCreate(const std::vector<Tensor*>& inputs, const std::vector<Tensor*>& outputs,
const MNN::Op* op) = 0;
/**
* @brief callback before resize ops.
*/
virtual void onResizeBegin() {
// nothing to do
}
/**
* @brief callback after resize ops.
*/
virtual void onResizeEnd() {
// nothing to do
}
/**
* @brief callback before executing ops.
*/
virtual void onExecuteBegin() const = 0;
/**
* @brief callback after executing ops.
*/
virtual void onExecuteEnd() const = 0;
/**
* @brief wait for all async execution to be finished.
* @return success or not.
*/
virtual bool onWaitFinish() {
return true;
}
/**
* @brief load GPU library resource.
* @param library loading load GPU library.
* @return success or not.
*/
virtual bool onLoadLibrary(const GpuLibrary* library) {
return false;
}
public:
/**
* @brief allocate buffer of tensor for given storage type.
* @param tensor buffer provider.
* @param storageType buffer storage type.
* @return success or not.
*/
virtual bool onAcquireBuffer(const Tensor* tensor, StorageType storageType) = 0;
/**
* @brief release buffer of tensor for given storage type.
* @param tensor buffer provider.
* @param storageType buffer storage type.
* @return success or not.
*/
virtual bool onReleaseBuffer(const Tensor* tensor, StorageType storageType) = 0;
/**
* @brief callback after all buffers needed by backend ops were allocated.
* @return success or not. (result not used currently)
*/
virtual bool onAllocateBuffer() {
return true;
}
/**
* @brief clear all dynamic buffers.
* @return success or not.
*/
virtual bool onClearBuffer() = 0;
/**
* @brief copy buffer from tensor to tensor.
* @param srcTensor source buffer provider.
* @param dstTensor dest buffer provider.
*/
virtual void onCopyBuffer(const Tensor* srcTensor, const Tensor* dstTensor) const = 0;
public:
/**
* @brief get forward type.
* @return forward type.
*/
inline MNNForwardType type() const {
return mType;
}
private:
const MNNForwardType mType;
};
/** abstract backend register */
class BackendCreator {
public:
/**
@brief initializer.
*/
virtual ~BackendCreator() = default;
/**
@brief create backend with given info.
@param info info to create backend.
@return created backend
*/
virtual Backend* onCreate(const Backend::Info& info) const = 0;
/**
@brief Turn info to supported.
@param info info to valid.
@return success or not
*/
virtual bool onValid(Backend::Info& info) const {
info.mode = Backend::Info::DIRECT;
return true;
}
protected:
/**
@brief deinitializer.
*/
BackendCreator() = default;
};
/**
* @brief get registered backend creator for given forward type.
* @param type given forward type.
* @return backend creator pointer if registered, nullptr otherwise.
*/
MNN_PUBLIC const BackendCreator* MNNGetExtraBackendCreator(MNNForwardType type);
/**
* @brief register backend creator for given forward type.
* @param type given forward type.
* @param creator registering backend creator.
* @return true if backend creator for given forward type was not registered before, false otherwise.
*/
MNN_PUBLIC bool MNNInsertExtraBackendCreator(MNNForwardType type, const BackendCreator* creator,
bool needCheck = false);
} // namespace MNN
#endif /* Backend_hpp */
================================================
FILE: MNN/mnn/include/ErrorCode.hpp
================================================
//
// ErrorCode.hpp
// MNN
//
// Created by MNN on 2018/09/18.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef ErrorCode_h
#define ErrorCode_h
namespace MNN {
enum ErrorCode {
#ifdef NO_ERROR
#undef NO_ERROR
#endif // NO_ERROR
NO_ERROR = 0,
OUT_OF_MEMORY = 1,
NOT_SUPPORT = 2,
COMPUTE_SIZE_ERROR = 3,
NO_EXECUTION = 4,
INVALID_VALUE = 5,
// User error
INPUT_DATA_ERROR = 10,
CALL_BACK_STOP = 11,
// Op Resize Error
TENSOR_NOT_SUPPORT = 20,
TENSOR_NEED_DIVIDE = 21,
};
} // namespace MNN
#endif /* ErrorCode_h */
================================================
FILE: MNN/mnn/include/HalideRuntime.h
================================================
#ifndef HALIDE_HALIDERUNTIME_H
#define HALIDE_HALIDERUNTIME_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
// Note that you should not use "inline" along with HALIDE_ALWAYS_INLINE;
// it is not necessary, and may produce warnings for some build configurations.
#ifdef _MSC_VER
#define HALIDE_ALWAYS_INLINE __forceinline
#define HALIDE_NEVER_INLINE __declspec(noinline)
#else
#define HALIDE_ALWAYS_INLINE __attribute__((always_inline)) inline
#define HALIDE_NEVER_INLINE __attribute__((noinline))
#endif
/** \file
*
* This file declares the routines used by Halide internally in its
* runtime. On platforms that support weak linking, these can be
* replaced with user-defined versions by defining an extern "C"
* function with the same name and signature.
*
* When doing Just In Time (JIT) compilation methods on the Func being
* compiled must be called instead. The corresponding methods are
* documented below.
*
* All of these functions take a "void *user_context" parameter as their
* first argument; if the Halide kernel that calls back to any of these
* functions has been compiled with the UserContext feature set on its Target,
* then the value of that pointer passed from the code that calls the
* Halide kernel is piped through to the function.
*
* Some of these are also useful to call when using the default
* implementation. E.g. halide_shutdown_thread_pool.
*
* Note that even on platforms with weak linking, some linker setups
* may not respect the override you provide. E.g. if the override is
* in a shared library and the halide object files are linked directly
* into the output, the builtin versions of the runtime functions will
* be called. See your linker documentation for more details. On
* Linux, LD_DYNAMIC_WEAK=1 may help.
*
*/
// Forward-declare to suppress warnings if compiling as C.
struct halide_buffer_t;
/** Types in the halide type system. They can be ints, unsigned ints,
* or floats (of various bit-widths), or a handle (which is always 64-bits).
* Note that the int/uint/float values do not imply a specific bit width
* (the bit width is expected to be encoded in a separate value).
*/
typedef enum halide_type_code_t
{
halide_type_int = 0, //!< signed integers
halide_type_uint = 1, //!< unsigned integers
halide_type_float = 2, //!< floating point numbers
halide_type_handle = 3 //!< opaque pointer type (void *)
} halide_type_code_t;
// Note that while __attribute__ can go before or after the declaration,
// __declspec apparently is only allowed before.
#ifndef HALIDE_ATTRIBUTE_ALIGN
#ifdef _MSC_VER
#define HALIDE_ATTRIBUTE_ALIGN(x) __declspec(align(x))
#else
#define HALIDE_ATTRIBUTE_ALIGN(x) __attribute__((aligned(x)))
#endif
#endif
/** A runtime tag for a type in the halide type system. Can be ints,
* unsigned ints, or floats of various bit-widths (the 'bits'
* field). Can also be vectors of the same (by setting the 'lanes'
* field to something larger than one). This struct should be
* exactly 32-bits in size. */
struct halide_type_t {
/** The basic type code: signed integer, unsigned integer, or floating point. */
#if __cplusplus >= 201103L
HALIDE_ATTRIBUTE_ALIGN(1) halide_type_code_t code; // halide_type_code_t
#else
HALIDE_ATTRIBUTE_ALIGN(1) uint8_t code; // halide_type_code_t
#endif
/** The number of bits of precision of a single scalar value of this type. */
HALIDE_ATTRIBUTE_ALIGN(1) uint8_t bits;
/** How many elements in a vector. This is 1 for scalar types. */
HALIDE_ATTRIBUTE_ALIGN(2) uint16_t lanes;
#ifdef __cplusplus
/** Construct a runtime representation of a Halide type from:
* code: The fundamental type from an enum.
* bits: The bit size of one element.
* lanes: The number of vector elements in the type. */
HALIDE_ALWAYS_INLINE halide_type_t(halide_type_code_t code, uint8_t bits, uint16_t lanes = 1)
: code(code), bits(bits), lanes(lanes) {
}
/** Default constructor is required e.g. to declare halide_trace_event
* instances. */
HALIDE_ALWAYS_INLINE halide_type_t() : code((halide_type_code_t)0), bits(0), lanes(0) {}
/** Compare two types for equality. */
HALIDE_ALWAYS_INLINE bool operator==(const halide_type_t &other) const {
return (code == other.code &&
bits == other.bits &&
lanes == other.lanes);
}
HALIDE_ALWAYS_INLINE bool operator!=(const halide_type_t &other) const {
return !(*this == other);
}
/** Size in bytes for a single element, even if width is not 1, of this type. */
HALIDE_ALWAYS_INLINE int bytes() const { return (bits + 7) / 8; }
#endif
};
/** An opaque struct containing per-GPU API implementations of the
* device functions. */
struct halide_device_interface_impl_t;
/** Each GPU API provides a halide_device_interface_t struct pointing
* to the code that manages device allocations. You can access these
* functions directly from the struct member function pointers, or by
* calling the functions declared below. Note that the global
* functions are not available when using Halide as a JIT compiler.
* If you are using raw halide_buffer_t in that context you must use
* the function pointers in the device_interface struct.
*
* The function pointers below are currently the same for every GPU
* API; only the impl field varies. These top-level functions do the
* bookkeeping that is common across all GPU APIs, and then dispatch
* to more API-specific functions via another set of function pointers
* hidden inside the impl field.
*/
struct halide_device_interface_t {
int (*device_malloc)(void *user_context, struct halide_buffer_t *buf,
const struct halide_device_interface_t *device_interface);
int (*device_free)(void *user_context, struct halide_buffer_t *buf);
int (*device_sync)(void *user_context, struct halide_buffer_t *buf);
void (*device_release)(void *user_context,
const struct halide_device_interface_t *device_interface);
int (*copy_to_host)(void *user_context, struct halide_buffer_t *buf);
int (*copy_to_device)(void *user_context, struct halide_buffer_t *buf,
const struct halide_device_interface_t *device_interface);
int (*device_and_host_malloc)(void *user_context, struct halide_buffer_t *buf,
const struct halide_device_interface_t *device_interface);
int (*device_and_host_free)(void *user_context, struct halide_buffer_t *buf);
int (*buffer_copy)(void *user_context, struct halide_buffer_t *src,
const struct halide_device_interface_t *dst_device_interface, struct halide_buffer_t *dst);
int (*device_crop)(void *user_context, const struct halide_buffer_t *src,
struct halide_buffer_t *dst);
int (*device_release_crop)(void *user_context, struct halide_buffer_t *buf);
int (*wrap_native)(void *user_context, struct halide_buffer_t *buf, uint64_t handle,
const struct halide_device_interface_t *device_interface);
int (*detach_native)(void *user_context, struct halide_buffer_t *buf);
const struct halide_device_interface_impl_t *impl;
};
typedef struct halide_dimension_t {
int32_t min, extent, stride;
// Per-dimension flags. None are defined yet (This is reserved for future use).
uint32_t flags;
#ifdef __cplusplus
HALIDE_ALWAYS_INLINE halide_dimension_t() : min(0), extent(0), stride(0), flags(0) {}
HALIDE_ALWAYS_INLINE halide_dimension_t(int32_t m, int32_t e, int32_t s, uint32_t f = 0) :
min(m), extent(e), stride(s), flags(f) {}
HALIDE_ALWAYS_INLINE bool operator==(const halide_dimension_t &other) const {
return (min == other.min) &&
(extent == other.extent) &&
(stride == other.stride) &&
(flags == other.flags);
}
HALIDE_ALWAYS_INLINE bool operator!=(const halide_dimension_t &other) const {
return !(*this == other);
}
#endif
} halide_dimension_t;
#ifdef __cplusplus
} // extern "C"
#endif
typedef enum {halide_buffer_flag_host_dirty = 1,
halide_buffer_flag_device_dirty = 2} halide_buffer_flags;
/**
* The raw representation of an image passed around by generated
* Halide code. It includes some stuff to track whether the image is
* not actually in main memory, but instead on a device (like a
* GPU). For a more convenient C++ wrapper, use Halide::Buffer<T>. */
typedef struct halide_buffer_t {
/** A device-handle for e.g. GPU memory used to back this buffer. */
uint64_t device;
/** The interface used to interpret the above handle. */
const struct halide_device_interface_t *device_interface;
/** A pointer to the start of the data in main memory. In terms of
* the Halide coordinate system, this is the address of the min
* coordinates (defined below). */
uint8_t* host;
/** flags with various meanings. */
uint64_t flags;
/** The type of each buffer element. */
struct halide_type_t type;
/** The dimensionality of the buffer. */
int32_t dimensions;
/** The shape of the buffer. Halide does not own this array - you
* must manage the memory for it yourself. */
halide_dimension_t *dim;
/** Pads the buffer up to a multiple of 8 bytes */
void *padding;
} halide_buffer_t;
#ifdef __cplusplus
namespace {
template<typename T> struct check_is_pointer;
template<typename T> struct check_is_pointer<T *> {};
}
/** Construct the halide equivalent of a C type */
template<typename T>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of() {
// Create a compile-time error if T is not a pointer (without
// using any includes - this code goes into the runtime).
check_is_pointer<T> check;
(void)check;
return halide_type_t(halide_type_handle, 64);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<float>() {
return halide_type_t(halide_type_float, 32);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<double>() {
return halide_type_t(halide_type_float, 64);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<bool>() {
return halide_type_t(halide_type_uint, 1);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint8_t>() {
return halide_type_t(halide_type_uint, 8);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint16_t>() {
return halide_type_t(halide_type_uint, 16);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint32_t>() {
return halide_type_t(halide_type_uint, 32);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint64_t>() {
return halide_type_t(halide_type_uint, 64);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int8_t>() {
return halide_type_t(halide_type_int, 8);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int16_t>() {
return halide_type_t(halide_type_int, 16);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int32_t>() {
return halide_type_t(halide_type_int, 32);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int64_t>() {
return halide_type_t(halide_type_int, 64);
}
#endif
#endif // HALIDE_HALIDERUNTIME_H
================================================
FILE: MNN/mnn/include/ImageProcess.hpp
================================================
//
// ImageProcess.hpp
// MNN
//
// Created by MNN on 2018/09/19.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef ImageProcess_hpp
#define ImageProcess_hpp
#include "ErrorCode.hpp"
#include "Matrix.h"
#include "Tensor.hpp"
namespace MNN {
namespace CV {
enum ImageFormat {
RGBA = 0,
RGB,
BGR,
GRAY,
BGRA,
YUV_NV21 = 11,
};
enum Filter { NEAREST = 0, BILINEAR = 1, BICUBIC = 2 };
enum Wrap { CLAMP_TO_EDGE = 0, ZERO = 1, REPEAT = 2 };
/**
* handle image process for tensor.
* step:
* 1: Do transform compute and get points
* 2: Sample line and do format convert
* 3: Turn RGBA to float tensor, and do sub and normalize
*/
class MNN_PUBLIC ImageProcess {
public:
struct Inside;
struct Config {
/** data filter */
Filter filterType = NEAREST;
/** format of source data */
ImageFormat sourceFormat = RGBA;
/** format of destination data */
ImageFormat destFormat = RGBA;
// Only valid if the dest type is float
float mean[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float normal[4] = {1.0f, 1.0f, 1.0f, 1.0f};
/** edge wrapper */
Wrap wrap = CLAMP_TO_EDGE;
};
public:
/**
* @brief create image process with given config for given tensor.
* @param config given config.
* @param dstTensor given tensor.
* @return image processor.
*/
static ImageProcess* create(const Config& config, const Tensor* dstTensor = nullptr);
/**
* @brief create image process with given config for given tensor.
* @param means given means
* @param meanCount given means count
* @param normals given normals
* @param normalCount given normal count
* @param sourceFormat format of source data
* @param destFormat format of destination data
* @param dstTensor given tensor.
* @return image processor.
*/
static ImageProcess* create(const ImageFormat sourceFormat = RGBA, const ImageFormat destFormat = RGBA,
const float* means = nullptr, const int meanCount = 0, const float* normals = nullptr,
const int normalCount = 0, const Tensor* dstTensor = nullptr);
~ImageProcess();
/**
* @brief get affine transform matrix.
* @return affine transform matrix.
*/
inline const Matrix& matrix() const {
return mTransform;
}
void setMatrix(const Matrix& matrix);
/**
* @brief convert source data to given tensor.
* @param source source data.
* @param iw source width.
* @param ih source height.
* @param stride number of elements per row. eg: 100 width RGB contains at least 300 elements.
* @param dest given tensor.
* @return result code.
*/
ErrorCode convert(const uint8_t* source, int iw, int ih, int stride, Tensor* dest);
/**
* @brief convert source data to given tensor.
* @param source source data.
* @param iw source width.
* @param ih source height.
* @param stride number of elements per row. eg: 100 width RGB contains at least 300 elements.
* @param dest dest data.
* @param ow output width.
* @param oh output height.
* @param outputBpp output bpp, if 0, set as the save and config.destFormat.
* @param outputStride output stride, if 0, set as ow * outputBpp.
* @param type Only support halide_type_of<uint8_t> and halide_type_of<float>.
* @return result code.
*/
ErrorCode convert(const uint8_t* source, int iw, int ih, int stride, void* dest, int ow, int oh, int outputBpp = 0,
int outputStride = 0, halide_type_t type = halide_type_of<float>());
/**
* @brief create tensor with given data.
* @param w image width.
* @param h image height.
* @param bpp bytes per pixel.
* @param p pixel data pointer.
* @return created tensor.
*/
template <typename T>
static Tensor* createImageTensor(int w, int h, int bpp, void* p = nullptr) {
return createImageTensor(halide_type_of<T>(), w, h, bpp, p);
}
static Tensor* createImageTensor(halide_type_t type, int w, int h, int bpp, void* p = nullptr);
private:
ImageProcess(const Config& config);
Matrix mTransform;
Matrix mTransformInvert;
Inside* mInside;
};
} // namespace CV
} // namespace MNN
#endif /* ImageProcess_hpp */
================================================
FILE: MNN/mnn/include/Interpreter.hpp
================================================
//
// Interpreter.hpp
// MNN
//
// Created by MNN on 2018/07/23.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef Interpreter_hpp
#define Interpreter_hpp
#include <functional>
#include <map>
#include <string>
#include "ErrorCode.hpp"
#include "MNNForwardType.h"
#include "Tensor.hpp"
namespace MNN {
/** session schedule config */
struct ScheduleConfig {
/** which tensor should be kept */
std::vector<std::string> saveTensors;
/** forward type */
MNNForwardType type = MNN_FORWARD_CPU;
/** number of threads in parallel */
int numThread = 4;
/** subpath to run */
struct Path {
std::vector<std::string> inputs;
std::vector<std::string> outputs;
enum Mode {
/**
* Op Mode
* - inputs means the source op, can NOT be empty.
* - outputs means the sink op, can be empty.
* The path will start from source op, then flow when encounter the sink op.
* The sink op will not be compute in this path.
*/
Op = 0,
/**
* Tensor Mode (NOT supported yet)
* - inputs means the inputs tensors, can NOT be empty.
* - outputs means the outputs tensors, can NOT be empty.
* It will find the pipeline that compute outputs from inputs.
*/
Tensor = 1
};
/** running mode */
Mode mode = Op;
};
Path path;
/** backup backend used to create execution when desinated backend do NOT support any op */
MNNForwardType backupType = MNN_FORWARD_CPU;
/** extra backend config */
BackendConfig* backendConfig = nullptr;
};
class Session;
struct Content;
class Tensor;
class Backend;
class MNN_PUBLIC OperatorInfo {
struct Info;
public:
/** Operator's name*/
const std::string& name() const;
/** Operator's type*/
const std::string& type() const;
/** Operator's flops, in M*/
float flops() const;
protected:
OperatorInfo();
~OperatorInfo();
Info* mContent;
};
typedef std::function<bool(const std::vector<Tensor*>&, const std::string& /*opName*/)> TensorCallBack;
typedef std::function<bool(const std::vector<Tensor*>&, const OperatorInfo*)> TensorCallBackWithInfo;
/** net data holder. multiple sessions could share same net. */
class MNN_PUBLIC Interpreter {
public:
/**
* @brief create net from file.
* @param file given file.
* @return created net if success, NULL otherwise.
*/
static Interpreter* createFromFile(const char* file);
/**
* @brief create net from buffer.
* @param buffer given data buffer.
* @param size size of data buffer.
* @return created net if success, NULL otherwise.
*/
static Interpreter* createFromBuffer(const void* buffer, size_t size);
~Interpreter();
public:
/**
* @brief create session with schedule config. created session will be managed in net.
* @param config session schedule config.
* @return created session if success, NULL otherwise.
*/
Session* createSession(const ScheduleConfig& config);
/**
* @brief create multi-path session with schedule configs. created session will be managed in net.
* @param configs session schedule configs.
* @return created session if success, NULL otherwise.
*/
Session* createMultiPathSession(const std::vector<ScheduleConfig>& configs);
/**
* @brief release session.
* @param session given session.
* @return true if given session is held by net and is freed.
*/
bool releaseSession(Session* session);
/**
* @brief call this function to get tensors ready. output tensor buffer (host or deviceId) should be retrieved
* after resize of any input tensor.
* @param session given session.
*/
void resizeSession(Session* session);
/**
* @brief call this function if don't need resize or create session any more, it will save a few memory that equal
* to the size of model buffer
*/
void releaseModel();
/**
* @brief Get the model buffer for user to save
* @return std::make_pair(modleBuffer, modelSize).
* @example:
* std::ofstream output("trainResult.alinn")
* auto buffer = net->getModelBuffer();
* output.write((const char*)buffer.first, buffer.second);
*/
std::pair<const void*, size_t> getModelBuffer() const;
/**
* @brief update Session's Tensor to model's Const Op
* @param session given session.
* @return result of running.
*/
ErrorCode updateSessionToModel(Session* session);
/**
* @brief run session.
* @param session given session.
* @return result of running.
*/
ErrorCode runSession(Session* session) const;
/*
* @brief run session.
* @param session given session.
* @param before callback before each op. return true to run the op; return false to skip the op.
* @param after callback after each op. return true to continue running; return false to interrupt the session.
* @param sync synchronously wait for finish of execution or not.
* @return result of running.
*/
ErrorCode runSessionWithCallBack(const Session* session, const TensorCallBack& before, const TensorCallBack& end,
bool sync = false) const;
/*
* @brief run session.
* @param session given session.
* @param before callback before each op. return true to run the op; return false to skip the op.
* @param after callback after each op. return true to continue running; return false to interrupt the session.
* @param sync synchronously wait for finish of execution or not.
* @return result of running.
*/
ErrorCode runSessionWithCallBackInfo(const Session* session, const TensorCallBackWithInfo& before,
const TensorCallBackWithInfo& end, bool sync = false) const;
/**
* @brief get input tensor for given name.
* @param session given session.
* @param name given name. if NULL, return first input.
* @return tensor if found, NULL otherwise.
*/
Tensor* getSessionInput(const Session* session, const char* name);
/**
* @brief get output tensor for given name.
* @param session given session.
* @param name given name. if NULL, return first output.
* @return tensor if found, NULL otherwise.
*/
Tensor* getSessionOutput(const Session* session, const char* name);
/**
* @brief get all input tensors.
* @param session given session.
* @return all input tensors mapped with name.
*/
const std::map<std::string, Tensor*>& getSessionOutputAll(const Session* session) const;
/**
* @brief get all output tensors.
* @param session given session.
* @return all output tensors mapped with name.
*/
const std::map<std::string, Tensor*>& getSessionInputAll(const Session* session) const;
public:
/**
* @brief resize given tensor.
* @param tensor given tensor.
* @param dims new dims. at most 6 dims.
*/
void resizeTensor(Tensor* tensor, const std::vector<int>& dims);
/**
* @brief resize given tensor by nchw.
* @param batch / N.
* @param channel / C.
* @param height / H.
* @param width / W
*/
void resizeTensor(Tensor* tensor, int batch, int channel, int height, int width);
/**
* @brief get backend used to create given tensor.
* @param session given session.
* @param tensor given tensor.
* @return backend used to create given tensor, may be NULL.
*/
const Backend* getBackend(const Session* session, const Tensor* tensor) const;
/**
* @brief get business code (model identifier).
* @return business code.
*/
const char* bizCode() const;
private:
static Interpreter* createFromBufferInternal(Content* net);
Content* mNet = nullptr;
Interpreter(Content* net);
Interpreter(const Interpreter&) = delete;
Interpreter(const Interpreter&&) = delete;
Interpreter& operator=(const Interpreter&) = delete;
Interpreter& operator=(const Interpreter&&) = delete;
};
} // namespace MNN
#endif /* Interpreter_hpp */
================================================
FILE: MNN/mnn/include/MNNDefine.h
================================================
//
// MNNDefine.h
// MNN
//
// Created by MNN on 2018/08/09.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef MNNDefine_h
#define MNNDefine_h
#include <assert.h>
#include <stdio.h>
#if defined(__APPLE__)
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE
#define MNN_BUILD_FOR_IOS
#endif
#endif
#ifdef MNN_USE_LOGCAT
#include <android/log.h>
#define MNN_ERROR(format, ...) __android_log_print(ANDROID_LOG_ERROR, "MNNJNI", format, ##__VA_ARGS__)
#define MNN_PRINT(format, ...) __android_log_print(ANDROID_LOG_INFO, "MNNJNI", format, ##__VA_ARGS__)
#else
#define MNN_PRINT(format, ...) printf(format, ##__VA_ARGS__)
#define MNN_ERROR(format, ...) printf(format, ##__VA_ARGS__)
#endif
#ifdef DEBUG
#define MNN_ASSERT(x) \
{ \
int res = (x); \
if (!res) { \
MNN_ERROR("Error for %s, %d\n", __FILE__, __LINE__); \
assert(res); \
} \
}
#else
#define MNN_ASSERT(x) \
{ \
int res = (x); \
if (!res) { \
MNN_ERROR("Error for %s, %d\n", __FILE__, __LINE__); \
} \
}
#endif
#define FUNC_PRINT(x) MNN_PRINT(#x "=%d in %s, %d \n", x, __func__, __LINE__);
#define FUNC_PRINT_ALL(x, type) MNN_PRINT(#x "=" #type " %" #type " in %s, %d \n", x, __func__, __LINE__);
#define MNN_CHECK(success, log) \
if(!(success)){ \
MNN_ERROR("Check failed: %s ==> %s\n", #success, #log); \
}
#if defined(_MSC_VER)
#if defined(BUILDING_MNN_DLL)
#define MNN_PUBLIC __declspec(dllexport)
#elif defined(USING_MNN_DLL)
#define MNN_PUBLIC __declspec(dllimport)
#else
#define MNN_PUBLIC
#endif
#else
#define MNN_PUBLIC __attribute__((visibility("default")))
#endif
#endif /* MNNDefine_h */
================================================
FILE: MNN/mnn/include/MNNForwardType.h
================================================
//
// MNNForwardType.h
// MNN
//
// Created by MNN on 2019/01/19.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef MNNForwardType_h
#define MNNForwardType_h
#include <stdint.h>
#include <stddef.h>
typedef enum {
MNN_FORWARD_CPU = 0,
/*
Firtly find the first available backends not equal to CPU
If no other backends, use cpu
*/
MNN_FORWARD_AUTO = 4,
/*Hand write metal*/
MNN_FORWARD_METAL = 1,
/*Use IOS's MPS instead of hand-write metal, Not Support yet*/
MNN_FORWARD_MPS = 2,
/*Android / Common Device GPU API*/
MNN_FORWARD_OPENCL = 3,
MNN_FORWARD_OPENGL = 6,
MNN_FORWARD_VULKAN = 7,
/*Android 8.1's NNAPI, Not Support yet*/
MNN_FORWARD_NN = 5,
/*User can use API from Backend.hpp to add or search Backend*/
MNN_FORWARD_USER_0 = 8,
MNN_FORWARD_USER_1 = 9,
MNN_FORWARD_USER_2 = 10,
MNN_FORWARD_USER_3 = 11,
MNN_FORWARD_ALL
} MNNForwardType;
#ifdef __cplusplus
namespace MNN {
struct BackendConfig {
enum MemoryMode { Memory_Normal = 0, Memory_High, Memory_Low };
MemoryMode memory = Memory_Normal;
enum PowerMode { Power_Normal = 0, Power_High, Power_Low };
PowerMode power = Power_Normal;
enum PrecisionMode { Precision_Normal = 0, Precision_High, Precision_Low };
PrecisionMode precision = Precision_Normal;
/** user defined context */
union {
void* sharedContext = nullptr;
size_t flags; // Valid for CPU Backend
};
};
}; // namespace MNN
#endif
#endif /* MNNForwardType_h */
================================================
FILE: MNN/mnn/include/MNNSharedContext.h
================================================
//
// MNNSharedContext.h
// MNN
//
// Created by MNN on 2018/10/11.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef MNNSharedContext_h
#define MNNSharedContext_h
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h> /*uint32_t*/
#ifndef VK_DEFINE_HANDLE
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
VK_DEFINE_HANDLE(VkInstance)
VK_DEFINE_HANDLE(VkPhysicalDevice)
VK_DEFINE_HANDLE(VkDevice)
VK_DEFINE_HANDLE(VkQueue)
#endif
struct MNNVulkanContext {
VkInstance pInstance;
VkPhysicalDevice pPhysicalDevice;
VkDevice pDevice;
VkQueue pQueue;
uint32_t iQueueFamilyIndex;
};
#ifdef __cplusplus
}
#endif
#endif /* MNNSharedContext_h */
================================================
FILE: MNN/mnn/include/Matrix.h
================================================
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Generated by tools/bookmaker from include/core/Matrix.h and docs/SkMatrix_Reference.bmh
on 2018-07-13 08:15:11. Additional documentation and examples can be found at:
https://skia.org/user/api/SkMatrix_Reference
You may edit either file directly. Structural changes to public interfaces require
editing both files. After editing docs/SkMatrix_Reference.bmh, run:
bookmaker -b docs -i include/core/Matrix.h -p
to create an updated version of this file.
*/
//
// Modified by jiangxiaotang on 2018/09/19.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef SkMatrix_DEFINED
#define SkMatrix_DEFINED
#include <string.h>
#include <cstdint>
#include "Rect.h"
namespace MNN {
namespace CV {
/** \class Matrix
Matrix holds a 3x3 matrix for transforming coordinates. This allows mapping
Point and vectors with translation, scaling, skewing, rotation, and
perspective.
Matrix elements are in row major order. Matrix does not have a constructor,
so it must be explicitly initialized. setIdentity() initializes Matrix
so it has no effect. setTranslate(), setScale(), setSkew(), setRotate(), set9 and setAll()
initializes all Matrix elements with the corresponding mapping.
Matrix includes a hidden variable that classifies the type of matrix to
improve performance. Matrix is not thread safe unless getType() is called first.
*/
class MNN_PUBLIC Matrix {
public:
Matrix() {
setIdentity();
}
/** Sets Matrix to scale by (sx, sy). Returned matrix is:
| sx 0 0 |
| 0 sy 0 |
| 0 0 1 |
@param sx horizontal scale factor
@param sy vertical scale factor
@return Matrix with scale
*/
static Matrix MakeScale(float sx, float sy) {
Matrix m;
m.setScale(sx, sy);
return m;
}
/** Sets Matrix to scale by (scale, scale). Returned matrix is:
| scale 0 0 |
| 0 scale 0 |
| 0 0 1 |
@param scale horizontal and vertical scale factor
@return Matrix with scale
*/
static Matrix MakeScale(float scale) {
Matrix m;
m.setScale(scale, scale);
return m;
}
/** Sets Matrix to translate by (dx, dy). Returned matrix is:
| 1 0 dx |
| 0 1 dy |
| 0 0 1 |
@param dx horizontal translation
@param dy vertical translation
@return Matrix with translation
*/
static Matrix MakeTrans(float dx, float dy) {
Matrix m;
m.setTranslate(dx, dy);
return m;
}
/** Sets Matrix to:
| scaleX skewX transX |
| skewY scaleY transY |
| pers0 pers1 pers2 |
@param scaleX horizontal scale factor
@param skewX horizontal skew factor
@param transX horizontal translation
@param skewY vertical skew factor
@param scaleY vertical scale factor
@param transY vertical translation
@param pers0 input x-axis perspective factor
@param pers1 input y-axis perspective factor
@param pers2 perspective scale factor
@return Matrix constructed from parameters
*/
static Matrix MakeAll(float scaleX, float skewX, float transX, float skewY, float scaleY, float transY, float pers0,
float pers1, float pers2) {
Matrix m;
m.setAll(scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2);
return m;
}
/** \enum Matrix::TypeMask
Enum of bit fields for mask returned by getType().
Used to identify the complexity of Matrix, to optimize performance.
*/
enum TypeMask {
kIdentity_Mask = 0, //!< identity Matrix; all bits clear
kTranslate_Mask = 0x01, //!< translation Matrix
kScale_Mask = 0x02, //!< scale Matrix
kAffine_Mask = 0x04, //!< skew or rotate Matrix
kPerspective_Mask = 0x08, //!< perspective Matrix
};
/** Returns a bit field describing the transformations the matrix may
perform. The bit field is computed conservatively, so it may include
false positives. For example, when kPerspective_Mask is set, all
other bits are set.
@return kIdentity_Mask, or combinations of: kTranslate_Mask, kScale_Mask,
kAffine_Mask, kPerspective_Mask
*/
TypeMask getType() const {
if (fTypeMask & kUnknown_Mask) {
fTypeMask = this->computeTypeMask();
}
// only return the public masks
return (TypeMask)(fTypeMask & 0xF);
}
/** Returns true if Matrix is identity. Identity matrix is:
| 1 0 0 |
| 0 1 0 |
| 0 0 1 |
@return true if Matrix has no effect
*/
bool isIdentity() const {
return this->getType() == 0;
}
/** Returns true if Matrix at most scales and translates. Matrix may be identity,
contain only scale elements, only translate elements, or both. Matrix form is:
| scale-x 0 translate-x |
| 0 scale-y translate-y |
| 0 0 1 |
@return true if Matrix is identity; or scales, translates, or both
*/
bool isScaleTranslate() const {
return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
}
/** Returns true if Matrix is identity, or translates. Matrix form is:
| 1 0 translate-x |
| 0 1 translate-y |
| 0 0 1 |
@return true if Matrix is identity, or translates
*/
bool isTranslate() const {
return !(this->getType() & ~(kTranslate_Mask));
}
/** Returns true Matrix maps Rect to another Rect. If true, Matrix is identity,
or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all
cases, Matrix may also have translation. Matrix form is either:
| scale-x 0 translate-x |
| 0 scale-y translate-y |
| 0 0 1 |
or
| 0 rotate-x translate-x |
| rotate-y 0 translate-y |
| 0 0 1 |
for non-zero values of scale-x, scale-y, rotate-x, and rotate-y.
Also called preservesAxisAlignment(); use the one that provides better inline
documentation.
@return true if Matrix maps one Rect into another
*/
bool rectStaysRect() const {
if (fTypeMask & kUnknown_Mask) {
fTypeMask = this->computeTypeMask();
}
return (fTypeMask & kRectStaysRect_Mask) != 0;
}
/** Returns true Matrix maps Rect to another Rect. If true, Matrix is identity,
or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all
cases, Matrix may also have translation. Matrix form is either:
| scale-x 0 translate-x |
| 0 scale-y translate-y |
| 0 0 1 |
or
| 0 rotate-x translate-x |
| rotate-y 0 translate-y |
| 0 0 1 |
for non-zero values of scale-x, scale-y, rotate-x, and rotate-y.
Also called rectStaysRect(); use the one that provides better inline
documentation.
@return true if Matrix maps one Rect into another
*/
bool preservesAxisAlignment() const {
return this->rectStaysRect();
}
/** Matrix organizes its values in row order. These members correspond to
each value in Matrix.
*/
static constexpr int kMScaleX = 0; //!< horizontal scale factor
static constexpr int kMSkewX = 1; //!< horizontal skew factor
static constexpr int kMTransX = 2; //!< horizontal translation
static constexpr int kMSkewY = 3; //!< vertical skew factor
static constexpr int kMScaleY = 4; //!< vertical scale factor
static constexpr int kMTransY = 5; //!< vertical translation
static constexpr int kMPersp0 = 6; //!< input x perspective factor
static constexpr int kMPersp1 = 7; //!< input y perspective factor
static constexpr int kMPersp2 = 8; //!< perspective bias
/** Affine arrays are in column major order to match the matrix used by
PDF and XPS.
*/
static constexpr int kAScaleX = 0; //!< horizontal scale factor
static constexpr int kASkewY = 1; //!< vertical skew factor
static constexpr int kASkewX = 2; //!< horizontal skew factor
static constexpr int kAScaleY = 3; //!< vertical scale factor
static constexpr int kATransX = 4; //!< horizontal translation
static constexpr int kATransY = 5; //!< vertical translation
/** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is
defined.
@param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
kMPersp0, kMPersp1, kMPersp2
@return value corresponding to index
*/
float operator[](int index) const {
MNN_ASSERT((unsigned)index < 9);
return fMat[index];
}
/** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is
defined.
@param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
kMPersp0, kMPersp1, kMPersp2
@return value corresponding to index
*/
float get(int index) const {
MNN_ASSERT((unsigned)index < 9);
return fMat[index];
}
/** Returns scale factor multiplied by x-axis input, contributing to x-axis output.
With mapPoints(), scales Point along the x-axis.
@return horizontal scale factor
*/
float getScaleX() const {
return fMat[kMScaleX];
}
/** Returns scale factor multiplied by y-axis input, contributing to y-axis output.
With mapPoints(), scales Point along the y-axis.
@return vertical scale factor
*/
float getScaleY() const {
return fMat[kMScaleY];
}
/** Returns scale factor multiplied by x-axis input, contributing to y-axis output.
With mapPoints(), skews Point along the y-axis.
Skewing both axes can rotate Point.
@return vertical skew factor
*/
float getSkewY() const {
return fMat[kMSkewY];
}
/** Returns scale factor multiplied by y-axis input, contributing to x-axis output.
With mapPoints(), skews Point along the x-axis.
Skewing both axes can rotate Point.
@return horizontal scale factor
*/
float getSkewX() const {
return fMat[kMSkewX];
}
/** Returns translation contributing to x-axis output.
With mapPoints(), moves Point along the x-axis.
@return horizontal translation factor
*/
float getTranslateX() const {
return fMat[kMTransX];
}
/** Returns translation contributing to y-axis output.
With mapPoints(), moves Point along the y-axis.
@return vertical translation factor
*/
float getTranslateY() const {
return fMat[kMTransY];
}
/** Returns factor scaling input x-axis relative to input y-axis.
@return input x-axis perspective factor
*/
float getPerspX() const {
return fMat[kMPersp0];
}
/** Returns factor scaling input y-axis relative to input x-axis.
@return input y-axis perspective factor
*/
float getPerspY() const {
return fMat[kMPersp1];
}
/** Returns writable Matrix value. Asserts if index is out of range and SK_DEBUG is
defined. Clears internal cache anticipating that caller will change Matrix value.
Next call to read Matrix state may recompute cache; subsequent writes to Matrix
value must be followed by dirtyMatrixTypeCache().
@param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
kMPersp0, kMPersp1, kMPersp2
@return writable value corresponding to index
*/
float& operator[](int index) {
MNN_ASSERT((unsigned)index < 9);
this->setTypeMask(kUnknown_Mask);
return fMat[index];
}
/** Sets Matrix value. Asserts if index is out of range and SK_DEBUG is
defined. Safer than operator[]; internal cache is always maintained.
@param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
kMPersp0, kMPersp1, kMPersp2
@param value scalar to store in Matrix
*/
void set(int index, float value) {
MNN_ASSERT((unsigned)index < 9);
fMat[index] = value;
this->setTypeMask(kUnknown_Mask);
}
/** Sets horizontal scale factor.
@param v horizontal scale factor to store
*/
void setScaleX(float v) {
this->set(kMScaleX, v);
}
/** Sets vertical scale factor.
@param v vertical scale factor to store
*/
void setScaleY(float v) {
this->set(kMScaleY, v);
}
/** Sets vertical skew factor.
@param v vertical skew factor to store
*/
void setSkewY(float v) {
this->set(kMSkewY, v);
}
/** Sets horizontal skew factor.
@param v horizontal skew factor to store
*/
void setSkewX(float v) {
this->set(kMSkewX, v);
}
/** Sets horizontal translation.
@param v horizontal translation to store
*/
void setTranslateX(float v) {
this->set(kMTransX, v);
}
/** Sets vertical translation.
@param v vertical translation to store
*/
void setTranslateY(float v) {
this->set(kMTransY, v);
}
/** Sets input x-axis perspective factor, which causes mapXY() to vary input x-axis values
inversely proportional to input y-axis values.
@param v perspective factor
*/
void setPerspX(float v) {
this->set(kMPersp0, v);
}
/** Sets input y-axis perspective factor, which causes mapXY() to vary input y-axis values
inversely proportional to input x-axis values.
@param v perspective factor
*/
void setPerspY(float v) {
this->set(kMPersp1, v);
}
/** Sets all values from parameters. Sets matrix to:
| scaleX skewX transX |
| skewY scaleY transY |
| persp0 persp1 persp2 |
@param scaleX horizontal scale factor to store
@param skewX horizontal skew factor to store
@param transX horizontal translation to store
@param skewY vertical skew factor to store
@param scaleY vertical scale factor to store
@param transY vertical translation to store
@param persp0 input x-axis values perspective factor to store
@param persp1 input y-axis values perspective factor to store
@param persp2 perspective scale factor to store
*/
void setAll(float scaleX, float skewX, float transX, float skewY, float scaleY, float transY, float persp0,
float persp1, float persp2) {
fMat[kMScaleX] = scaleX;
fMat[kMSkewX] = skewX;
fMat[kMTransX] = transX;
fMat[kMSkewY] = skewY;
fMat[kMScaleY] = scaleY;
fMat[kMTransY] = transY;
fMat[kMPersp0] = persp0;
fMat[kMPersp1] = persp1;
fMat[kMPersp2] = persp2;
this->setTypeMask(kUnknown_Mask);
}
/** Copies nine scalar values contained by Matrix into buffer, in member value
ascending order: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
kMPersp0, kMPersp1, kMPersp2.
@param buffer storage for nine scalar values
*/
void get9(float buffer[9]) const {
memcpy(buffer, fMat, 9 * sizeof(float));
}
/** Sets Matrix to nine scalar values in buffer, in member value ascending order:
kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, kMPersp0, kMPersp1,
kMPersp2.
Sets matrix to:
| buffer[0] buffer[1] buffer[2] |
| buffer[3] buffer[4] buffer[5] |
| buffer[6] buffer[7] buffer[8] |
In the future, set9 followed by get9 may not return the same values. Since Matrix
maps non-homogeneous coordinates, scaling all nine values produces an equivalent
transformation, possibly improving precision.
@param buffer nine scalar values
*/
void set9(const float buffer[9]);
/** Sets Matrix to identity; which has no effect on mapped Point. Sets Matrix to:
| 1 0 0 |
| 0 1 0 |
| 0 0 1 |
Also called setIdentity(); use the one that provides better inline
documentation.
*/
void reset();
/** Sets Matrix to identity; which has no effect on mapped Point. Sets Matrix to:
| 1 0 0 |
| 0 1 0 |
| 0 0 1 |
Also called reset(); use the one that provides better inline
documentation.
*/
void setIdentity() {
this->reset();
}
/** Sets Matrix to translate by (dx, dy).
@param dx horizontal translation
@param dy vertical translation
*/
void setTranslate(float dx, float dy);
/** Sets Matrix to scale by sx and sy, about a pivot point at (px, py).
The pivot point is unchanged when mapped with Matrix.
@param sx horizontal scale factor
@param sy vertical scale factor
@param px pivot x
@param py pivot y
*/
void setScale(float sx, float sy, float px, float py);
/** Sets Matrix to scale by sx and sy about at pivot point at (0, 0).
@param sx horizontal scale factor
@param sy vertical scale factor
*/
void setScale(float sx, float sy);
/** Sets Matrix to rotate by degrees about a pivot point at (px, py).
The pivot point is unchanged when mapped with Matrix.
Positive degrees rotates clockwise.
@param degrees angle of axes relative to upright axes
@param px pivot x
@param py pivot y
*/
void setRotate(float degrees, float px, float py);
/** Sets Matrix to rotate by degrees about a pivot point at (0, 0).
Positive degrees rotates clockwise.
@param degrees angle of axes relative to upright axes
*/
void setRotate(float degrees);
/** Sets Matrix to rotate by sinValue and cosValue, about a pivot point at (px, py).
The pivot point is unchanged when mapped with Matrix.
Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1).
Vector length specifies scale.
@param sinValue rotation vector x-axis component
@param cosValue rotation vector y-axis component
@param px pivot x-axis
@param py pivot y-axis
*/
void setSinCos(float sinValue, float cosValue, float px, float py);
/** Sets Matrix to rotate by sinValue and cosValue, about a pivot point at (0, 0).
Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1).
Vector length specifies scale.
@param sinValue rotation vector x-axis component
@param cosValue rotation vector y-axis component
*/
void setSinCos(float sinValue, float cosValue);
/** Sets Matrix to skew by kx and ky, about a pivot point at (px, py).
The pivot point is unchanged when mapped with Matrix.
@param kx horizontal skew factor
@param ky vertical skew factor
@param px pivot x
@param py pivot y
*/
void setSkew(float kx, float ky, float px, float py);
/** Sets Matrix to skew by kx and ky, about a pivot point at (0, 0).
@param kx horizontal skew factor
@param ky vertical skew factor
*/
void setSkew(float kx, float ky);
/** Sets Matrix to Matrix a multiplied by Matrix b. Either a or b may be this.
Given:
| A B C | | J K L |
a = | D E F |, b = | M N O |
| G H I | | P Q R |
sets Matrix to:
| A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR |
a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
| G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR |
@param a Matrix on left side of multiply expression
@param b Matrix on right side of multiply expression
*/
void setConcat(const Matrix& a, const Matrix& b);
/** Sets Matrix to Matrix multiplied by Matrix constructed from translation (dx, dy).
This can be thought of as moving the point to be mapped before applying Matrix.
Given:
| A B C | | 1 0 dx |
Matrix = | D E F |, T(dx, dy) = | 0 1 dy |
| G H I | | 0 0 1 |
sets Matrix to:
| A B C | | 1 0 dx | | A B A*dx+B*dy+C |
Matrix * T(dx, dy) = | D E F | | 0 1 dy | = | D E D*dx+E*dy+F |
| G H I | | 0 0 1 | | G H G*dx+H*dy+I |
@param dx x-axis translation before applying Matrix
@param dy y-axis translation before applying Matrix
*/
void preTranslate(float dx, float dy);
/** Sets Matrix to Matrix multiplied by Matrix constructed from scaling by (sx, sy)
about pivot point (px, py).
This can be thought of as scaling about a pivot point before applying Matrix.
Given:
| A B C | | sx 0 dx |
Matrix = | D E F |, S(sx, sy, px, py) = | 0 sy dy |
| G H I | | 0 0 1 |
where
dx = px - sx * px
dy = py - sy * py
sets Matrix to:
| A B C | | sx 0 dx | | A*sx B*sy A*dx+B*dy+C |
Matrix * S(sx, sy, px, py) = | D E F | | 0 sy dy | = | D*sx E*sy D*dx+E*dy+F |
| G H I | | 0 0 1 | | G*sx H*sy G*dx+H*dy+I |
@param sx horizontal scale factor
@param sy vertical scale factor
@param px pivot x
@param py pivot y
*/
void preScale(float sx, float sy, float px, float py);
/** Sets Matrix to Matrix multiplied by Matrix constructed from scaling by (sx, sy)
about pivot point (0, 0).
This can be thought of as scaling about the origin before applying Matrix.
Given:
| A B C | | sx 0 0 |
Matrix = | D E F |, S(sx, sy) = | 0 sy 0 |
| G H I | | 0 0 1 |
sets Matrix to:
| A B C | | sx 0 0 | | A*sx B*sy C |
Matrix * S(sx, sy) = | D E F | | 0 sy 0 | = | D*sx E*sy F |
| G H I | | 0 0 1 | | G*sx H*sy I |
@param sx horizontal scale factor
@param sy vertical scale factor
*/
void preScale(float sx, float sy);
/** Sets Matrix to Matrix multiplied by Matrix constructed from rotating by degrees
about pivot point (px, py).
This can be thought of as rotating about a pivot point before applying Matrix.
Positive degrees rotates clockwise.
Given:
| A B C | | c -s dx |
Matrix = | D E F |, R(degrees, px, py) = | s c dy |
| G H I | | 0 0 1 |
where
c = cos(degrees)
s = sin(degrees)
dx = s * py + (1 - c) * px
dy = -s * px + (1 - c) * py
sets Matrix to:
| A B C | | c -s dx | | Ac+Bs -As+Bc A*dx+B*dy+C |
Matrix * R(degrees, px, py) = | D E F | | s c dy | = | Dc+Es -Ds+Ec D*dx+E*dy+F |
| G H I | | 0 0 1 | | Gc+Hs -Gs+Hc G*dx+H*dy+I |
@param degrees angle of axes relative to upright axes
@param px pivot x
@param py pivot y
*/
void preRotate(float degrees, float px, float py);
/** Sets Matrix to Matrix multiplied by Matrix constructed from rotating by degrees
about pivot point (0, 0).
This can be thought of as rotating about the origin before applying Matrix.
Positive degrees rotates clockwise.
Given:
| A B C | | c -s 0 |
Matrix = | D E F |, R(degrees, px, py) = | s c 0 |
| G H I | | 0 0 1 |
where
c = cos(degrees)
s = sin(degrees)
sets Matrix to:
| A B C | | c -s 0 | | Ac+Bs -As+Bc C |
Matrix * R(degrees, px, py) = | D E F | | s c 0 | = | Dc+Es -Ds+Ec F |
| G H I | | 0 0 1 | | Gc+Hs -Gs+Hc I |
@param degrees angle of axes relative to upright axes
*/
void preRotate(float degrees);
/** Sets Matrix to Matrix multiplied by Matrix constructed from skewing by (kx, ky)
about pivot point (px, py).
This can be thought of as skewing about a pivot point before applying Matrix.
Given:
| A B C | | 1 kx dx |
Matrix = | D E F |, K(kx, ky, px, py) = | ky 1 dy |
| G H I | | 0 0 1 |
where
dx = -kx * py
dy = -ky * px
sets Matrix to:
| A B C | | 1 kx dx | | A+B*ky A*kx+B A*dx+B*dy+C |
Matrix * K(kx, ky, px, py) = | D E F | | ky 1 dy | = | D+E*ky D*kx+E D*dx+E*dy+F |
| G H I | | 0 0 1 | | G+H*ky G*kx+H G*dx+H*dy+I |
@param kx horizontal skew factor
@param ky vertical skew factor
@param px pivot x
@param py pivot y
*/
void preSkew(float kx, float ky, float px, float py);
/** Sets Matrix to Matrix multiplied by Matrix constructed from skewing by (kx, ky)
about pivot point (0, 0).
This can be thought of as skewing about the origin before applying Matrix.
Given:
| A B C | | 1 kx 0 |
Matrix = | D E F |, K(kx, ky) = | ky 1 0 |
| G H I | | 0 0 1 |
sets Matrix to:
| A B C | | 1 kx 0 | | A+B*ky A*kx+B C |
Matrix * K(kx, ky) = | D E F | | ky 1 0 | = | D+E*ky D*kx+E F |
| G H I | | 0 0 1 | | G+H*ky G*kx+H I |
@param kx horizontal skew factor
@param ky vertical skew factor
*/
void preSkew(float kx, float ky);
/** Sets Matrix to Matrix multiplied by Matrix other.
This can be thought of mapping by other before applying Matrix.
Given:
| A B C | | J K L |
Matrix = | D E F |, other = | M N O |
| G H I | | P Q R |
sets Matrix to:
| A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR |
Matrix * other = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
| G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR |
@param other Matrix on right side of multiply expression
*/
void preConcat(const Matrix& other);
/** Sets Matrix to Matrix constructed from translation (dx, dy) multiplied by Matrix.
This can be thought of as moving the point to be mapped after applying Matrix.
Given:
| J K L | | 1 0 dx |
Matrix = | M N O |, T(dx, dy) = | 0 1 dy |
| P Q R | | 0 0 1 |
sets Matrix to:
| 1 0 dx | | J K L | | J+dx*P K+dx*Q L+dx*R |
T(dx, dy) * Matrix = | 0 1 dy | | M N O | = | M+dy*P N+dy*Q O+dy*R |
| 0 0 1 | | P Q R | | P Q R |
@param dx x-axis translation after applying Matrix
@param dy y-axis translation after applying Matrix
*/
void postTranslate(float dx, float dy);
/** Sets Matrix to Matrix constructed from scaling by (sx, sy) about pivot point
(px, py), multiplied by Matrix.
This can be thought of as scaling about a pivot point after applying Matrix.
Given:
| J K L | | sx 0 dx |
Matrix = | M N O |, S(sx, sy, px, py) = | 0 sy dy |
| P Q R | | 0 0 1 |
where
dx = px - sx * px
dy = py - sy * py
sets Matrix to:
| sx 0 dx | | J K L | | sx*J+dx*P sx*K+dx*Q sx*L+dx+R |
S(sx, sy, px, py) * Matrix = | 0 sy dy | | M N O | = | sy*M+dy*P sy*N+dy*Q sy*O+dy*R |
| 0 0 1 | | P Q R | | P Q R |
@param sx horizontal scale factor
@param sy vertical scale factor
@param px pivot x
@param py pivot y
*/
void postScale(float sx, float sy, float px, float py);
/** Sets Matrix to Matrix constructed from scaling by (sx, sy) about pivot point
(0, 0), multiplied by Matrix.
This can be thought of as scaling about the origin after applying Matrix.
Given:
| J K L | | sx 0 0 |
Matrix = | M N O |, S(sx, sy) = | 0 sy 0 |
| P Q R | | 0 0 1 |
sets Matrix to:
| sx 0 0 | | J K L | | sx*J sx*K sx*L |
S(sx, sy) * Matrix = | 0 sy 0 | | M N O | = | sy*M sy*N sy*O |
| 0 0 1 | | P Q R | | P Q R |
@param sx horizontal scale factor
@param sy vertical scale factor
*/
void postScale(float sx, float sy);
/** Sets Matrix to Matrix constructed from scaling by (1/divx, 1/divy) about pivot point (px, py), multiplied by
Matrix.
Returns false if either divx or divy is zero.
Given:
| J K L | | sx 0 0 |
Matrix = | M N O |, I(divx, divy) = | 0 sy 0 |
| P Q R | | 0 0 1 |
where
sx = 1 / divx
sy = 1 / divy
sets Matrix to:
| sx 0 0 | | J K L | | sx*J sx*K sx*L |
I(divx, divy) * Matrix = | 0 sy 0 | | M N O | = | sy*M sy*N sy*O |
| 0 0 1 | | P Q R | | P Q R |
@param divx integer divisor for inverse scale in x
@param divy integer divisor for inverse scale in y
@return true on successful scale
*/
bool postIDiv(int divx, int divy);
/** Sets Matrix to Matrix constructed from rotating by degrees about pivot point
(px, py), multiplied by Matrix.
This can be thought of as rotating about a pivot point after applying Matrix.
Positive degrees rotates clockwise.
Given:
| J K L | | c -s dx |
Matrix = | M N O |, R(degrees, px, py) = | s c dy |
| P Q R | | 0 0 1 |
where
c = cos(degrees)
s = sin(degrees)
dx = s * py + (1 - c) * px
dy = -s * px + (1 - c) * py
sets Matrix to:
|c -s dx| |J K L| |cJ-sM+dx*P cK-sN+dx*Q cL-sO+dx+R|
R(degrees, px, py) * Matrix = |s c dy| |M N O| = |sJ+cM+dy*P sK+cN+dy*Q sL+cO+dy*R|
|0 0 1| |P Q R| | P Q R|
@param degrees angle of axes relative to upright axes
@param px pivot x
@param py pivot y
*/
void postRotate(float degrees, float px, float py);
/** Sets Matrix to Matrix constructed from rotating by degrees about pivot point
(0, 0), multiplied by Matrix.
This can be thought of as rotating about the origin after applying Matrix.
Positive degrees rotates clockwise.
Given:
| J K L | | c -s 0 |
Matrix = | M N O |, R(degrees, px, py) = | s c 0 |
| P Q R | | 0 0 1 |
where
c = cos(degrees)
s = sin(degrees)
sets Matrix to:
| c -s dx | | J K L | | cJ-sM cK-sN cL-sO |
R(degrees, px, py) * Matrix = | s c dy | | M N O | = | sJ+cM sK+cN sL+cO |
| 0 0 1 | | P Q R | | P Q R |
@param degrees angle of axes relative to upright axes
*/
void postRotate(float degrees);
/** Sets Matrix to Matrix constructed from skewing by (kx, ky) about pivot point
(px, py), multiplied by Matrix.
This can be thought of as skewing about a pivot point after applying Matrix.
Given:
| J K L | | 1 kx dx |
Matrix = | M N O |, K(kx, ky, px, py) = | ky 1 dy |
| P Q R | | 0 0 1 |
where
dx = -kx * py
dy = -ky * px
sets Matrix to:
| 1 kx dx| |J K L| |J+kx*M+dx*P K+kx*N+dx*Q L+kx*O+dx+R|
K(kx, ky, px, py) * Matrix = |ky 1 dy| |M N O| = |ky*J+M+dy*P ky*K+N+dy*Q ky*L+O+dy*R|
| 0 0 1| |P Q R| | P Q R|
@param kx horizontal skew factor
@param ky vertical skew factor
@param px pivot x
@param py pivot y
*/
void postSkew(float kx, float ky, float px, float py);
/** Sets Matrix to Matrix constructed from skewing by (kx, ky) about pivot point
(0, 0), multiplied by Matrix.
This can be thought of as skewing about the origin after applying Matrix.
Given:
| J K L | | 1 kx 0 |
Matrix = | M N O |, K(kx, ky) = | ky 1 0 |
| P Q R | | 0 0 1 |
sets Matrix to:
| 1 kx 0 | | J K L | | J+kx*M K+kx*N L+kx*O |
K(kx, ky) * Matrix = | ky 1 0 | | M N O | = | ky*J+M ky*K+N ky*L+O |
| 0 0 1 | | P Q R | | P Q R |
@param kx horizontal skew factor
@param ky vertical skew factor
*/
void postSkew(float kx, float ky);
/** Sets Matrix to Matrix other multiplied by Matrix.
This can be thought of mapping by other after applying Matrix.
Given:
| J K L | | A B C |
Matrix = | M N O |, other = | D E F |
| P Q R | | G H I |
sets Matrix to:
| A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR |
other * Matrix = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
| G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR |
@param other Matrix on left side of multiply expression
*/
void postConcat(const Matrix& other);
/** \enum Matrix::ScaleToFit
ScaleToFit describes how Matrix is constructed to map one Rect to another.
ScaleToFit may allow Matrix to have unequal horizontal and vertical scaling,
or may restrict Matrix to square scaling. If restricted, ScaleToFit specifies
how Matrix maps to the side or center of the destination Rect.
*/
enum ScaleToFit {
kFill_ScaleToFit, //!< scales in x and y to fill destination Rect
kStart_ScaleToFit, //!< scales and aligns to left and top
kCenter_ScaleToFit, //!< scales and aligns to center
kEnd_ScaleToFit, //!< scales and aligns to right and bottom
};
/** Sets Matrix to scale and translate src Rect to dst Rect. stf selects whether
mapping completely fills dst or preserves the aspect ratio, and how to align
src within dst. Returns false if src is empty, and sets Matrix to identity.
Returns true if dst is empty, and sets Matrix to:
| 0 0 0 |
| 0 0 0 |
| 0 0 1 |
@param src Rect to map from
@param dst Rect to map to
@param stf one of: kFill_ScaleToFit, kStart_ScaleToFit,
kCenter_ScaleToFit, kEnd_ScaleToFit
@return true if Matrix can represent Rect mapping
*/
bool setRectToRect(const Rect& src, const Rect& dst, ScaleToFit stf);
/** Returns Matrix set to scale and translate src Rect to dst Rect. stf selects
whether mapping completely fills dst or preserves the aspect ratio, and how to
align src within dst. Returns the identity Matrix if src is empty. If dst is
empty, returns Matrix set to:
| 0 0 0 |
| 0 0 0 |
| 0 0 1 |
@param src Rect to map from
@param dst Rect to map to
@param stf one of: kFill_ScaleToFit, kStart_ScaleToFit,
kCenter_ScaleToFit, kEnd_ScaleToFit
@return Matrix mapping src to dst
*/
static Matrix MakeRectToRect(const Rect& src, const Rect& dst, ScaleToFit stf) {
Matrix m;
m.setRectToRect(src, dst, stf);
return m;
}
/** Sets Matrix to map src to dst. count must be zero or greater, and four or less.
If count is zero, sets Matrix to identity and returns true.
If count is one, sets Matrix to translate and returns true.
If count is two or more, sets Matrix to map Point if possible; returns false
if Matrix cannot be constructed. If count is four, Matrix may include
perspective.
@param src Point to map from
@param dst Point to map to
@param count number of Point in src and dst
@return true if Matrix was constructed successfully
*/
bool setPolyToPoly(const Point src[], const Point dst[], int count);
/** Sets inverse to reciprocal matrix, returning true if Matrix can be inverted.
Geometrically, if Matrix maps from source to destination, inverse Matrix
maps from destination to source. If Matrix can not be inverted, inverse is
unchanged.
@param inverse storage for inverted Matrix; may be nullptr
@return true if Matrix can be inverted
*/
bool invert(Matrix* inverse) const {
// Allow the trivial case to be inlined.
if (this->isIdentity()) {
if (inverse) {
inverse->reset();
}
return true;
}
return this->invertNonIdentity(inverse);
}
/** Fills affine with identity values in column major order.
Sets affine to:
| 1 0 0 |
| 0 1 0 |
Affine 3x2 matrices in column major order are used by OpenGL and XPS.
@param affine storage for 3x2 affine matrix
*/
static void SetAffineIdentity(float affine[6]);
/** Fills affine in column major order. Sets affine to:
| scale-x skew-x translate-x |
| skew-y scale-y translate-y |
If Matrix contains perspective, returns false and leaves affine unchanged.
@param affine storage for 3x2 affine matrix; may be nullptr
@return true if Matrix does not contain perspective
*/
bool asAffine(float affine[6]) const;
/** Sets Matrix to affine values, passed in column major order. Given affine,
column, then row, as:
| scale-x skew-x translate-x |
| skew-y scale-y translate-y |
Matrix is set, row, then column, to:
| scale-x skew-x translate-x |
| skew-y scale-y translate-y |
| 0 0 1 |
@param affine 3x2 affine matrix
*/
void setAffine(const float affine[6]);
/** Maps src Point array of length count to dst Point array of equal or greater
length. Point are mapped by multiplying each Point by Matrix. Given:
| A B C | | x |
Matrix = | D E F |, pt = | y |
| G H I | | 1 |
where
for (i = 0; i < count; ++i) {
x = src[i].fX
y = src[i].fY
}
each dst Point is computed as:
|A B C| |x| Ax+By+C Dx+Ey+F
Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
|G H I| |1| Gx+Hy+I Gx+Hy+I
src and dst may point to the same storage.
@param dst storage for mapped Point
@param src Point to transform
@param count number of Point to transform
*/
void mapPoints(Point dst[], const Point src[], int count) const {
MNN_ASSERT((dst && src && count > 0) || 0 == count);
// no partial overlap
MNN_ASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
this->getMapPtsProc()(*this, dst, src, count);
}
/** Maps pts Point array of length count in place. Point are mapped by multiplying
each Point by Matrix. Given:
| A B C | | x |
Matrix = | D E F |, pt = | y |
| G H I | | 1 |
where
for (i = 0; i < count; ++i) {
x = pts[i].fX
y = pts[i].fY
}
each resulting pts Point is computed as:
|A B C| |x| Ax+By+C Dx+Ey+F
Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
|G H I| |1| Gx+Hy+I Gx+Hy+I
@param pts storage for mapped Point
@param count number of Point to transform
*/
void mapPoints(Point pts[], int count) const {
this->mapPoints(pts, pts, count);
}
/** Maps Point (x, y) to result. Point is mapped by multiplying by Matrix. Given:
| A B C | | x |
Matrix = | D E F |, pt = | y |
| G H I | | 1 |
result is computed as:
|A B C| |x| Ax+By+C Dx+Ey+F
Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
|G H I| |1| Gx+Hy+I Gx+Hy+I
@param x x-axis value of Point to map
@param y y-axis value of Point to map
@param result storage for mapped Point
*/
void mapXY(float x, float y, Point* result) const {
this->getMapXYProc()(*this, x, y, result);
}
/** Returns Point (x, y) multiplied by Matrix. Given:
| A B C | | x |
Matrix = | D E F |, pt = | y |
| G H I | | 1 |
result is computed as:
|A B C| |x| Ax+By+C Dx+Ey+F
Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
|G H I| |1| Gx+Hy+I Gx+Hy+I
@param x x-axis value of Point to map
@param y y-axis value of Point to map
@return mapped Point
*/
Point mapXY(float x, float y) const {
Point result;
this->getMapXYProc()(*this, x, y, &result);
return result;
}
/** Sets dst to bounds of src corners mapped by Matrix.
Returns true if mapped corners are dst corners.
Returned value is the same as calling rectStaysRect().
@param dst storage for bounds of mapped Point
@param src Rect to map
@return true if dst is equivalent to mapped src
*/
bool mapRect(Rect* dst, const Rect& src) const;
/** Sets rect to bounds of rect corners mapped by Matrix.
Returns true if mapped corners are computed rect corners.
Returned value is the same as calling rectStaysRect().
@param rect rectangle to map, and storage for bounds of mapped corners
@return true if result is equivalent to mapped src
*/
bool mapRect(Rect* rect) const {
return this->mapRect(rect, *rect);
}
/** Returns bounds of src corners mapped by Matrix.
@param src rectangle to map
@return mapped bounds
*/
Rect mapRect(const Rect& src) const {
Rect dst;
(void)this->mapRect(&dst, src);
return dst;
}
/** Sets dst to bounds of src corners mapped by Matrix. If matrix contains
elements other than scale or translate: asserts if SK_DEBUG is defined;
otherwise, results are undefined.
@param dst storage for bounds of mapped Point
@param src Rect to map
*/
void mapRectScaleTranslate(Rect* dst, const Rect& src) const;
/** Returns true if Matrix equals m, using an efficient comparison.
Returns false when the sign of zero values is the different; when one
matrix has positive zero value and the other has negative zero value.
Returns true even when both Matrix contain NaN.
NaN never equals any value, including itself. To improve performance, NaN values
are treated as bit patterns that are equal if their bit patterns are equal.
@param m Matrix to compare
@return true if m and Matrix are represented by identical bit patterns
*/
bool cheapEqualTo(const Matrix& m) const {
return 0 == memcmp(fMat, m.fMat, sizeof(fMat));
}
/** Compares a and b; returns true if a and b are numerically equal. Returns true
even if sign of zero values are different. Returns false if either Matrix
contains NaN, even if the other Matrix also contains NaN.
@param a Matrix to compare
@param b Matrix to compare
@return true if Matrix a and Matrix b are numerically equal
*/
friend MNN_PUBLIC bool operator==(const Matrix& a, const Matrix& b);
/** Compares a and b; returns true if a and b are not numerically equal. Returns false
even if sign of zero values are different. Returns true if either Matrix
contains NaN, even if the other Matrix also contains NaN.
@param a Matrix to compare
@param b Matrix to compare
@return true if Matrix a and Matrix b are numerically not equal
*/
friend MNN_PUBLIC bool operator!=(const Matrix& a, const Matrix& b) {
return !(a == b);
}
/** Writes text representation of Matrix to standard output. Floating point values
are written with limited precision; it may not be possible to reconstruct
original Matrix from output.
*/
void dump() const;
/** Returns the minimum scaling factor of Matrix by decomposing the scaling and
skewing elements.
Returns -1 if scale factor overflows or Matrix contains perspective.
@return minimum scale factor
*/
float getMinScale() const;
/** Returns the maximum scaling factor of Matrix by decomposing the scaling and
skewing elements.
Returns -1 if scale factor overflows or Matrix contains perspective.
@return maximum scale factor
*/
float getMaxScale() const;
/** Sets scaleFactors[0] to the minimum scaling factor, and scaleFactors[1] to the
maximum scaling factor. Scaling factors are computed by decomposing
the Matrix scaling and skewing elements.
Returns true if scaleFactors are found; otherwise, returns false and sets
scaleFactors to undefined values.
@param scaleFactors storage for minimum and maximum scale factors
@return true if scale factors were computed correctly
*/
bool getMinMaxScales(float scaleFactors[2]) const;
/** Returns reference to const identity Matrix. Returned Matrix is set to:
| 1 0 0 |
| 0 1 0 |
| 0 0 1 |
@return const identity Matrix
*/
static const Matrix& I();
/** Returns reference to a const Matrix with invalid values. Returned Matrix is set
to:
| SK_ScalarMax SK_ScalarMax SK_ScalarMax |
| SK_ScalarMax SK_ScalarMax SK_ScalarMax |
| SK_ScalarMax SK_ScalarMax SK_ScalarMax |
@return const invalid Matrix
*/
static const Matrix& InvalidMatrix();
/** Returns Matrix a multiplied by Matrix b.
Given:
| A B C | | J K L |
a = | D E F |, b = | M N O |
| G H I | | P Q R |
sets Matrix to:
| A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR |
a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
| G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR |
@param a Matrix on left side of multiply expression
@param b Matrix on right side of multiply expression
@return Matrix computed from a times b
*/
static Matrix Concat(const Matrix& a, const Matrix& b) {
Matrix result;
result.setConcat(a, b);
return result;
}
/** Sets internal cache to unknown state. Use to force update after repeated
modifications to Matrix element reference returned by operator[](int index).
*/
void dirtyMatrixTypeCache() {
this->setTypeMask(kUnknown_Mask);
}
/** Initializes Matrix with scale and translate elements.
| sx 0 tx |
| 0 sy ty |
| 0 0 1 |
@param sx horizontal scale factor to store
@param sy vertical scale factor to store
@param tx horizontal translation to store
@param ty vertical translation to store
*/
void setScaleTranslate(float sx, float sy, float tx, float ty) {
fMat[kMScaleX] = sx;
fMat[kMSkewX] = 0;
fMat[kMTransX] = tx;
fMat[kMSkewY] = 0;
fMat[kMScaleY] = sy;
fMat[kMTransY] = ty;
fMat[kMPersp0] = 0;
fMat[kMPersp1] = 0;
fMat[kMPersp2] = 1;
unsigned mask = 0;
if (sx != 1 || sy != 1) {
mask |= kScale_Mask;
}
if (tx || ty) {
mask |= kTranslate_Mask;
}
this->setTypeMask(mask | kRectStaysRect_Mask);
}
/** Returns true if all elements of the matrix are finite. Returns false if any
element is infinity, or NaN.
@return true if matrix has only finite elements
*/
private:
/** Set if the matrix will map a rectangle to another rectangle. This
can be true if the matrix is scale-only, or rotates a multiple of
90 degrees.
This bit will be set on identity matrices
*/
static constexpr int kRectStaysRect_Mask = 0x10;
/** Set if the perspective bit is valid even though the rest of
the matrix is Unknown.
*/
static constexpr int kOnlyPerspectiveValid_Mask = 0x40;
static constexpr int kUnknown_Mask = 0x80;
static constexpr int kORableMasks = kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask;
static constexpr int kAllMasks =
kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask | kRectStaysRect_Mask;
float fMat[9];
mutable uint32_t fTypeMask;
static void ComputeInv(float dst[9], const float src[9], double invDet, bool isPersp);
uint8_t computeTypeMask() const;
uint8_t computePerspectiveTypeMask() const;
void setTypeMask(int mask) {
// allow kUnknown or a valid mask
MNN_ASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask) ==
(kUnknown_Mask | kOnlyPerspectiveValid_Mask));
fTypeMask = (uint8_t)(mask);
}
void orTypeMask(int mask) {
MNN_ASSERT((mask & kORableMasks) == mask);
fTypeMask = (uint8_t)(fTypeMask | mask);
}
void clearTypeMask(int mask) {
// only allow a valid mask
MNN_ASSERT((mask & kAllMasks) == mask);
fTypeMask = fTypeMask & ~mask;
}
TypeMask getPerspectiveTypeMaskOnly() const {
if ((fTypeMask & kUnknown_Mask) && !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
fTypeMask = this->computePerspectiveTypeMask();
}
return (TypeMask)(fTypeMask & 0xF);
}
/** Returns true if we already know that the matrix is identity;
false otherwise.
*/
bool isTriviallyIdentity() const {
if (fTypeMask & kUnknown_Mask) {
return false;
}
return ((fTypeMask & 0xF) == 0);
}
inline void updateTranslateMask() {
if ((fMat[kMTransX] != 0) | (fMat[kMTransY] != 0)) {
fTypeMask |= kTranslate_Mask;
} else {
fTypeMask &= ~kTranslate_Mask;
}
}
typedef void (*MapXYProc)(const Matrix& mat, float x, float y, Point* result);
static MapXYProc GetMapXYProc(TypeMask mask) {
MNN_ASSERT((mask & ~kAllMasks) == 0);
return gMapXYProcs[mask & kAllMasks];
}
MapXYProc getMapXYProc() const {
return GetMapXYProc(this->getType());
}
typedef void (*MapPtsProc)(const Matrix& mat, Point dst[], const Point src[], int count);
static MapPtsProc GetMapPtsProc(TypeMask mask) {
MNN_ASSERT((mask & ~kAllMasks) == 0);
return gMapPtsProcs[mask & kAllMasks];
}
MapPtsProc getMapPtsProc() const {
return GetMapPtsProc(this->getType());
}
bool invertNonIdentity(Matrix* inverse) const;
static void Identity_xy(const Matrix&, float, float, Point*);
static void Trans_xy(const Matrix&, float, float, Point*);
static void Scale_xy(const Matrix&, float, float, Point*);
static void ScaleTrans_xy(const Matrix&, float, float, Point*);
static void Rot_xy(const Matrix&, float, float, Point*);
static void RotTrans_xy(const Matrix&, float, float, Point*);
static void Persp_xy(const Matrix&, float, float, Point*);
static const MapXYProc gMapXYProcs[];
static void Identity_pts(const Matrix&, Point[], const Point[], int);
static void Trans_pts(const Matrix&, Point dst[], const Point[], int);
static void Scale_pts(const Matrix&, Point dst[], const Point[], int);
static void ScaleTrans_pts(const Matrix&, Point dst[], const Point[], int count);
static void Persp_pts(const Matrix&, Point dst[], const Point[], int);
static void Affine_vpts(const Matrix&, Point dst[], const Point[], int);
static const MapPtsProc gMapPtsProcs[];
static bool Poly2Proc(const Point srcPt[], Matrix* dst);
static bool Poly3Proc(const Point srcPt[], Matrix* dst);
static bool Poly4Proc(const Point srcPt[], Matrix* dst);
};
} // namespace CV
} // namespace MNN
#endif
================================================
FILE: MNN/mnn/include/NonCopyable.hpp
================================================
//
// NonCopyable.hpp
// MNN
//
// Created by MNN on 2018/09/19.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef NonCopyable_hpp
#define NonCopyable_hpp
namespace MNN {
/** protocol class. used to delete assignment operator. */
class NonCopyable {
public:
NonCopyable() = default;
NonCopyable(const NonCopyable&) = delete;
NonCopyable(const NonCopyable&&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&&) = delete;
};
} // namespace MNN
#endif /* NonCopyable_hpp */
================================================
FILE: MNN/mnn/include/Rect.h
================================================
//
// Rect.h
// MNN
//
// Modified by jiangxiaotang on 2018/09/19.
// Copyright © 2018, Alibaba Group Holding Limited
//
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Generated by tools/bookmaker from include/core/Rect.h and docs/SkRect_Reference.bmh
on 2018-07-13 08:15:11. Additional documentation and examples can be found at:
https://skia.org/user/api/SkRect_Reference
You may edit either file directly. Structural changes to public interfaces require
editing both files. After editing docs/SkRect_Reference.bmh, run:
bookmaker -b docs -i include/core/Rect.h -p
to create an updated version of this file.
*/
#ifndef SkRect_DEFINED
#define SkRect_DEFINED
#include <math.h>
#include <algorithm>
#include <utility>
#include "MNNDefine.h"
namespace MNN {
namespace CV {
struct Point {
float fX;
float fY;
void set(float x, float y) {
fX = x;
fY = y;
}
};
/** \struct Rect
Rect holds four float coordinates describing the upper and
lower bounds of a rectangle. Rect may be created from outer bounds or
from position, width, and height. Rect describes an area; if its right
is less than or equal to its left, or if its bottom is less than or equal to
its top, it is considered empty.
*/
struct MNN_PUBLIC Rect {
float fLeft; //!< smaller x-axis bounds
float fTop; //!< smaller y-axis bounds
float fRight; //!< larger x-axis bounds
float fBottom; //!< larger y-axis bounds
/** Returns constructed Rect set to (0, 0, 0, 0).
Many other rectangles are empty; if left is equal to or greater than right,
or if top is equal to or greater than bottom. Setting all members to zero
is a convenience, but does not designate a special empty rectangle.
@return bounds (0, 0, 0, 0)
*/
static constexpr Rect MakeEmpty() {
return Rect{0, 0, 0, 0};
}
#ifdef SK_SUPPORT_LEGACY_RECTMAKELARGEST
/** Deprecated.
*/
static Rect MakeLargest() {
return {SK_ScalarMin, SK_ScalarMin, SK_ScalarMax, SK_ScalarMax};
}
#endif
/** Returns constructed Rect set to float values (0, 0, w, h). Does not
validate input; w or h may be negative.
Passing integer values may generate a compiler warning since Rect cannot
represent 32-bit integers exactly. Use SkIRect for an exact integer rectangle.
@param w float width of constructed Rect
@param h float height of constructed Rect
@return bounds (0, 0, w, h)
*/
static constexpr Rect MakeWH(float w, float h) {
return Rect{0, 0, w, h};
}
/** Returns constructed Rect set to integer values (0, 0, w, h). Does not validate
input; w or h may be negative.
Use to avoid a compiler warning that input may lose precision when stored.
Use SkIRect for an exact integer rectangle.
@param w integer width of constructed Rect
@param h integer height of constructed Rect
@return bounds (0, 0, w, h)
*/
static Rect MakeIWH(int w, int h) {
Rect r;
r.set(0, 0, (float)(w), (float)(h));
return r;
}
/** Returns constructed Rect set to (l, t, r, b). Does not sort input; Rect may
result in fLeft greater than fRight, or fTop greater than fBottom.
@param l float stored in fLeft
@param t float stored in fTop
@param r float stored in fRight
@param b float stored in fBottom
@return bounds (l, t, r, b)
*/
static constexpr Rect MakeLTRB(float l, float t, float r, float b) {
return Rect{l, t, r, b};
}
/** Returns constructed Rect set to (x, y, x + w, y + h). Does not validate input;
w or h may be negative.
@param x stored in fLeft
@param y stored in fTop
@param w added to x and stored in fRight
@param h added to y and stored in fBottom
@return bounds at (x, y) with width w and height h
*/
static constexpr Rect MakeXYWH(float x, float y, float w, float h) {
return Rect{x, y, x + w, y + h};
}
/** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal
to or greater than fBottom. Call sort() to reverse rectangles with negative
width() or height().
@return true if width() or height() are zero or negative
*/
bool isEmpty() const {
// We write it as the NOT of a non-empty rect, so we will return true if any values
// are NaN.
return !(fLeft < fRight && fTop < fBottom);
}
/** Returns true if fLeft is equal to or less than fRight, or if fTop is equal
to or less than fBottom. Call sort() to reverse rectangles with negative
width() or height().
@return true if width() or height() are zero or positive
*/
bool isSorted() const {
return fLeft <= fRight && fTop <= fBottom;
}
/** Returns left edge of Rect, if sorted. Call isSorted() to see if Rect is valid.
Call sort() to reverse fLeft and fRight if needed.
@return fLeft
*/
float x() const {
return fLeft;
}
/** Returns top edge of Rect, if sorted. Call isEmpty() to see if Rect may be invalid,
and sort() to reverse fTop and fBottom if needed.
@return fTop
*/
float y() const {
return fTop;
}
/** Returns left edge of Rect, if sorted. Call isSorted() to see if Rect is valid.
Call sort() to reverse fLeft and fRight if needed.
@return fLeft
*/
float left() const {
return fLeft;
}
/** Returns top edge of Rect, if sorted. Call isEmpty() to see if Rect may be invalid,
and sort() to reverse fTop and fBottom if needed.
@return fTop
*/
float top() const {
return fTop;
}
/** Returns right edge of Rect, if sorted. Call isSorted() to see if Rect is valid.
Call sort() to reverse fLeft and fRight if needed.
@return fRight
*/
float right() const {
return fRight;
}
/** Returns bottom edge of Rect, if sorted. Call isEmpty() to see if Rect may be invalid,
and sort() to reverse fTop and fBottom if needed.
@return fBottom
*/
float bottom() const {
return fBottom;
}
/** Returns span on the x-axis. This does not check if Rect is sorted, or if
result fits in 32-bit float; result may be negative or infinity.
@return fRight minus fLeft
*/
float width() const {
return fRight - fLeft;
}
/** Returns span on the y-axis. This does not check if Rect is sorted, or if
result fits in 32-bit float; result may be negative or infinity.
@return fBottom minus fTop
*/
float height() const {
return fBottom - fTop;
}
/** Returns average of left edge and right edge. Result does not change if Rect
is sorted. Result may overflow to infinity if Rect is far from the origin.
@return midpoint in x
*/
float centerX() const {
// don't use floatHalf(fLeft + fBottom) as that might overflow before the 0.5
return 0.5f * (fLeft) + 0.5f * (fRight);
}
/** Returns average of top edge and bottom edge. Result does not change if Rect
is sorted.
@return midpoint in y
*/
float centerY() const {
// don't use floatHalf(fTop + fBottom) as that might overflow before the 0.5
return 0.5f * (fTop) + 0.5f * (fBottom);
}
/** Sets Rect to (0, 0, 0, 0).
Many other rectangles are empty; if left is equal to or greater than right,
or if top is equal to or greater than bottom. Setting all members to zero
is a convenience, but does not designate a special empty rectangle.
*/
void setEmpty() {
*this = MakeEmpty();
}
/** Sets Rect to (left, top, right, bottom).
left and right are not sorted; left is not necessarily less than right.
top and bottom are not sorted; top is not necessarily less than bottom.
@param left stored in fLeft
@param top stored in fTop
@param right stored in fRight
@param bottom stored in fBottom
*/
void set(float left, float top, float right, float bottom) {
fLeft = left;
fTop = top;
fRight = right;
fBottom = bottom;
}
/** Sets Rect to (left, top, right, bottom).
left and right are not sorted; left is not necessarily less than right.
top and bottom are not sorted; top is not necessarily less than bottom.
@param left stored in fLeft
@param top stored in fTop
@param right stored in fRight
@param bottom stored in fBottom
*/
void setLTRB(float left, float top, float right, float bottom) {
this->set(left, top, right, bottom);
}
/** Sets Rect to (left, top, right, bottom).
All parameters are promoted from integer to scalar.
left and right are not sorted; left is not necessarily less than right.
top and bottom are not sorted; top is not necessarily less than bottom.
@param left promoted to float and stored in fLeft
@param top promoted to float and stored in fTop
@param right promoted to float and stored in fRight
@param bottom promoted to float and stored in fBottom
*/
void iset(int left, int top, int right, int bottom) {
fLeft = (float)(left);
fTop = (float)(top);
fRight = (float)(right);
fBottom = (float)(bottom);
}
/** Sets Rect to (0, 0, width, height).
width and height may be zero or negative. width and height are promoted from
integer to float, large values may lose precision.
@param width promoted to float and stored in fRight
@param height promoted to float and stored in fBottom
*/
void isetWH(int width, int height) {
fLeft = fTop = 0;
fRight = (float)(width);
fBottom = (float)(height);
}
/** Sets Rect to (x, y, x + width, y + height). Does not validate input;
width or height may be negative.
@param x stored in fLeft
@param y stored in fTop
@param width added to x and stored in fRight
@param height added to y and stored in fBottom
*/
void setXYWH(float x, float y, float width, float height) {
fLeft = x;
fTop = y;
fRight = x + width;
fBottom = y + height;
}
/** Sets Rect to (0, 0, width, height). Does not validate input;
width or height may be negative.
@param width stored in fRight
@param height stored in fBottom
*/
void setWH(float width, float height) {
fLeft = 0;
fTop = 0;
fRight = width;
fBottom = height;
}
/** Returns Rect offset by (dx, dy).
If dx is negative, Rect returned is moved to the left.
If dx is positive, Rect returned is moved to the right.
If dy is negative, Rect returned is moved upward.
If dy is positive, Rect returned is moved downward.
@param dx added to fLeft and fRight
@param dy added to fTop and fBottom
@return Rect offset on axes, with original width and height
*/
Rect makeOffset(float dx, float dy) const {
return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy);
}
/** Returns Rect, inset by (dx, dy).
If dx is negative, Rect returned is wider.
If dx is positive, Rect returned is narrower.
If dy is negative, Rect returned is taller.
If dy is positive, Rect returned is shorter.
@param dx added to fLeft and subtracted from fRight
@param dy added to fTop and subtracted from fBottom
@return Rect inset symmetrically left and right, top and bottom
*/
Rect makeInset(float dx, float dy) const {
return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy);
}
/** Returns Rect, outset by (dx, dy).
If dx is negative, Rect returned is narrower.
If dx is positive, Rect returned is wider.
If dy is negative, Rect returned is shorter.
If dy is positive, Rect returned is taller.
@param dx subtracted to fLeft and added from fRight
@param dy subtracted to fTop and added from fBottom
@return Rect outset symmetrically left and right, top and bottom
*/
Rect makeOutset(float dx, float dy) const {
return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy);
}
/** Offsets Rect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom.
If dx is negative, moves Rect to the left.
If dx is positive, moves Rect to the right.
If dy is negative, moves Rect upward.
If dy is positive, moves Rect downward.
@param dx offset added to fLeft and fRight
@param dy offset added to fTop and fBottom
*/
void offset(float dx, float dy) {
fLeft += dx;
fTop += dy;
fRight += dx;
fBottom += dy;
}
/** Offsets Rect so that fLeft equals newX, and fTop equals newY. width and height
are unchanged.
@param newX stored in fLeft, preserving width()
@param newY stored in fTop, preserving height()
*/
void offsetTo(float newX, float newY) {
fRight += newX - fLeft;
fBottom += newY - fTop;
fLeft = newX;
fTop = newY;
}
/** Insets Rect by (dx, dy).
If dx is positive, makes Rect narrower.
If dx is negative, makes Rect wider.
If dy is positive, makes Rect shorter.
If dy is negative, makes Rect taller.
@param dx added to fLeft and subtracted from fRight
@param dy added to fTop and subtracted from fBottom
*/
void inset(float dx, float dy) {
fLeft += dx;
fTop += dy;
fRight -= dx;
fBottom -= dy;
}
/** Outsets Rect by (dx, dy).
If dx is positive, makes Rect wider.
If dx is negative, makes Rect narrower.
If dy is positive, makes Rect taller.
If dy is negative, makes Rect shorter.
@param dx subtracted to fLeft and added from fRight
@param dy subtracted to fTop and added from fBottom
*/
void outset(float dx, float dy) {
this->inset(-dx, -dy);
}
private:
static bool Intersects(float al, float at, float ar, float ab, float bl, float bt, float br, float bb) {
float L = std::max(al, bl);
float R = std::min(ar, br);
float T = std::max(at, bt);
float B = std::min(ab, bb);
return L < R && T < B;
}
public:
/** Constructs Rect to intersect from (left, top, right, bottom). Does not sort
construction.
Returns true if Rect intersects construction.
Returns false if either construction or Rect is empty, or do not intersect.
@param left x-axis minimum of constructed Rect
@param top y-axis minimum of constructed Rect
@param right x-axis maximum of constructed Rect
@param bottom y-axis maximum of constructed Rect
@return true if construction and Rect have area in common
*/
bool intersects(float left, float top, float right, float bottom) const {
return Intersects(fLeft, fTop, fRight, fBottom, left, top, right, bottom);
}
/** Returns true if Rect intersects r.
Returns false if either r or Rect is empty, or do not intersect.
@param r Rect to intersect
@return true if r and Rect have area in common
*/
bool intersects(const Rect& r) const {
return Intersects(fLeft, fTop, fRight, fBottom, r.fLeft, r.fTop, r.fRight, r.fBottom);
}
/** Returns true if a intersects b.
Returns false if either a or b is empty, or do not intersect.
@param a Rect to intersect
@param b Rect to intersect
@return true if a and b have area in common
*/
static bool Intersects(const Rect& a, const Rect& b) {
return Intersects(a.fLeft, a.fTop, a.fRight, a.fBottom, b.fLeft, b.fTop, b.fRight, b.fBottom);
}
/** Sets Rect to the union of itself and r.
Asserts if r is empty and SK_DEBUG is defined.
If Rect is empty, sets Rect to r.
May produce incorrect results if r is empty.
@param r expansion Rect
*/
void joinNonEmptyArg(const Rect& r) {
MNN_ASSERT(!r.isEmpty());
// if we are empty, just assign
if (fLeft >= fRight || fTop >= fBottom) {
*this = r;
} else {
this->joinPossiblyEmptyRect(r);
}
}
/** Sets Rect to the union of itself and the construction.
May produce incorrect results if Rect or r is empty.
@param r expansion Rect
*/
void joinPossiblyEmptyRect(const Rect& r) {
fLeft = std::min(fLeft, r.left());
fTop = std::min(fTop, r.top());
fRight = std::max(fRight, r.right());
fBottom = std::max(fBottom, r.bottom());
}
/** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom.
Returns false if Rect is empty.
@param x test Point x-coordinate
@param y test Point y-coordinate
@return true if (x, y) is inside Rect
*/
bool contains(float x, float y) const {
return x >= fLeft && x < fRight && y >= fTop && y < fBottom;
}
/** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps
fTop and fBottom if fTop is greater than fBottom. Result may be empty;
and width() and height() will be zero or positive.
*/
void sort() {
using std::swap;
if (fLeft > fRight) {
swap(fLeft, fRight);
}
if (fTop > fBottom) {
swap(fTop, fBottom);
}
}
/** Returns Rect with fLeft and fRight swapped if fLeft is greater than fRight; and
with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty;
and width() and height() will be zero or positive.
@return sorted Rect
*/
Rect makeSorted() const {
return MakeLTRB(std::min(fLeft, fRight), std::min(fTop, fBottom), std::max(fLeft, fRight),
std::max(fTop, fBottom));
}
/** Returns pointer to first scalar in Rect, to treat it as an array with four
entries.
@return pointer to fLeft
*/
const float* asScalars() const {
return &fLeft;
}
};
} // namespace CV
} // namespace MNN
#endif
================================================
FILE: MNN/mnn/include/Tensor.hpp
================================================
//
// Tensor.hpp
// MNN
//
// Created by MNN on 2018/08/14.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef Tensor_hpp
#define Tensor_hpp
#include <vector>
#include "HalideRuntime.h"
#include "MNNDefine.h"
namespace MNN {
/**
* data container.
* data for host tensor is saved in `host` field. its memory is allocated malloc directly.
* data for device tensor is saved in `deviceId` field. its memory is allocated by session's backend.
* usually, device tensors are created by engine (like net, session).
* meanwhile, host tensors could be created by engine or user.
*/
class MNN_PUBLIC Tensor {
public:
struct InsideDescribe;
/** dimension type used to create tensor */
enum DimensionType {
/** for tensorflow net type. uses NHWC as data format. */
TENSORFLOW,
/** for caffe net type. uses NCHW as data format. */
CAFFE,
/** for caffe net type. uses NC4HW4 as data format. */
CAFFE_C4
};
/** handle type */
enum HandleDataType {
/** default handle type */
HANDLE_NONE = 0,
/** string handle type */
HANDLE_STRING = 1
};
public:
/**
* @brief create a tensor with dimension size and type without acquire memory for data.
* @param dimSize dimension size.
* @param type dimension type.
*/
Tensor(int dimSize = 4, DimensionType type = CAFFE);
/**
* @brief create a tensor with same shape as given tensor.
* @param tensor shape provider.
* @param type dimension type.
* @param allocMemory acquire memory for data or not.
* @warning tensor data won't be copied.
*/
Tensor(const Tensor* tensor, DimensionType type = CAFFE, bool allocMemory = true);
/** deinitializer */
~Tensor();
private:
// remove all assignment operator
Tensor(const Tensor& tensor) = delete;
Tensor(const Tensor&& tensor) = delete;
Tensor& operator=(const Tensor&) = delete;
Tensor& operator=(const Tensor&&) = delete;
public:
/**
* @brief create tensor with shape, data type and dimension type.
* @param shape tensor shape.
* @param type data type.
* @param dimType dimension type.
* @return created tensor.
* @warning memory for data won't be acquired. call backend's onAcquireBuffer to get memory ready.
*/
static Tensor* createDevice(const std::vector<int>& shape, halide_type_t type, DimensionType dimType = TENSORFLOW);
/**
* @brief create tensor with shape and dimension type. data type is represented by `T`.
* @param shape tensor shape.
* @param dimType dimension type.
* @return created tensor.
* @warning memory for data won't be acquired. call backend's onAcquireBuffer to get memory ready.
*/
template <typename T>
static Tensor* createDevice(const std::vector<int>& shape, DimensionType dimType = TENSORFLOW) {
return createDevice(shape, halide_type_of<T>(), dimType);
}
/**
* @brief create tensor with shape, data type, data and dimension type.
* @param shape tensor shape.
* @param type data type.
* @param data data to save.
* @param dimType dimension type.
* @return created tensor.
*/
static Tensor* create(const std::vector<int>& shape, halide_type_t type, void* data = NULL,
DimensionType dimType = TENSORFLOW);
/**
* @brief create tensor with shape, data and dimension type. data type is represented by `T`.
* @param shape tensor shape.
* @param data data to save.
* @param dimType dimension type.
* @return created tensor.
*/
template <typename T>
static Tensor* create(const std::vector<int>& shape, void* data = NULL, DimensionType dimType = TENSORFLOW) {
return create(shape, halide_type_of<T>(), data, dimType);
}
public:
/**
* @brief for DEVICE tensor, copy data from given host tensor.
* @param hostTensor host tensor, the data provider.
* @return true for DEVICE tensor, and false for HOST tensor.
*/
bool copyFromHostTensor(const Tensor* hostTensor);
/**
* @brief for DEVICE tensor, copy data to given host tensor.
* @param hostTensor host tensor, the data consumer.
* @return true for DEVICE tensor, and false for HOST tensor.
*/
bool copyToHostTensor(Tensor* hostTensor) const;
/**
* @brief create HOST tensor from DEVICE tensor, with or without data copying.
* @param deviceTensor given device tensor.
* @param copyData copy data or not.
* @return created host tensor.
*/
static Tensor* createHostTensorFromDevice(const Tensor* deviceTensor, bool copyData = true);
public:
const halide_buffer_t& buffer() const {
return mBuffer;
}
halide_buffer_t& buffer() {
return mBuffer;
}
/**
* @brief get dimension type.
* @return dimension type.
*/
DimensionType getDimensionType() const;
/**
* @brief handle data type. used when data type code is halide_type_handle.
* @return handle data type.
*/
HandleDataType getHandleDataType() const;
/**
* @brief set data type.
* @param type data type defined in 'Type_generated.h'.
*/
void setType(int type);
/**
* @brief get data type.
* @return data type.
*/
inline halide_type_t getType() const {
return mBuffer.type;
}
/**
* @brief visit host memory, data type is represented by `T`.
* @return data point in `T` type.
*/
template <typename T>
T* host() const {
return (T*)mBuffer.host;
}
/**
* @brief visit device memory.
* @return device data ID. what the ID means varies between backends.
*/
uint64_t deviceId() const {
return mBuffer.device;
}
public:
int dimensions() const {
return mBuffer.dimensions;
}
/**
* @brief get all dimensions' extent.
* @return dimensions' extent.
*/
std::vector<int> shape() const;
/**
* @brief calculate number of bytes needed to store data taking reordering flag into account.
* @return bytes needed to store data
*/
int size() const;
/**
* @brief calculate number of elements needed to store data taking reordering flag into account.
* @return elements needed to store data
*/
inline int elementSize() const {
return size() / mBuffer.type.bytes();
}
public:
inline int width() const {
if (getDimensionType() == TENSORFLOW) {
return mBuffer.dim[2].extent;
}
return mBuffer.dim[3].extent;
}
inline int height() const {
if (getDimensionType() == TENSORFLOW) {
return mBuffer.dim[1].extent;
}
return mBuffer.dim[2].extent;
}
inline int channel() const {
if (getDimensionType() == TENSORFLOW) {
return mBuffer.dim[3].extent;
}
return mBuffer.dim[1].extent;
}
inline int batch() const {
return mBuffer.dim[0].extent;
}
// visit dimension's extent & stride
inline int stride(int index) const {
return mBuffer.dim[index].stride;
}
inline int length(int index) const {
return mBuffer.dim[index].extent;
}
inline void setStride(int index, int stride) {
mBuffer.dim[index].stride = stride;
}
inline void setLength(int index, int length) {
mBuffer.dim[index].extent = length;
}
public:
/**
* @brief print tensor data. for DEBUG use only.
*/
void print() const;
private:
halide_buffer_t mBuffer;
struct InsideDescribe* mDescribe;
private:
friend class TensorUtils;
};
} // namespace MNN
#endif /* Tensor_hpp */
================================================
FILE: MNN/mnn/include/revertMNNModel.hpp
================================================
//
// revertMNNModel.hpp
// MNN
//
// Created by MNN on 2019/01/31.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef REVERTMNNMODEL_HPP
#define REVERTMNNMODEL_HPP
#include "mnn/MNN_generated.h"
class Revert {
public:
Revert(const char* originalModelFileName);
~Revert();
void* getBuffer() const;
const size_t getBufferSize() const;
void initialize();
static float getRandValue();
private:
Revert();
std::unique_ptr<MNN::NetT> mMNNNet;
size_t mBufferSize;
std::shared_ptr<uint8_t> mBuffer;
void randStart();
void packMNNNet();
};
#endif // REVERTMNNMODEL_HPP
================================================
FILE: MNN/python/README.md
================================================
# Python implemententation of [Ultra-Light-Fast-Generic-Face-Detector-1MB](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB) with [MNN](https://github.com/alibaba/MNN)
## How to use MNN in Python
### Install
#### Install Depencies
##### graphviz
for macOS:
```bash
brew install graphviz
```
for Linux:
```bash
apt-get install graphviz
```
#### Python Version Limitation
Python2.7, 3.5, 3.6, 3.7 are supported, but for Windows, python2.7 is not supported.
for macOS:
```bash
pip install -U MNN
```
for Linux:
As PyPi requires all wheels to be tagged with "ManyLinux", and old version pip can't get the "ManyLinux" Tagged wheel, thus you have to upgrade your pip to newer version in order to use "pip install"
```bash
pip install -U pip
pip install -U MNN
```
## Run
* Use FP32 model(version-RFB) and run in FP16 mode:
```bash
python ultraface_py_mnn.py --model_path ../model/version-RFB/RFB-320.mnn
```
* Use quantized INT8 model:
```bash
python ultraface_py_mnn.py --model_path ../model/version-RFB/RFB-320-quant-KL-5792.mnn
```
* We provide both converted MNN FP32 and **quantized INT8** models of version-slim-320 and version-RFB-320 in ./MNN/model . The xxx-quant-KL-xxx.mnn is quantified by the **KL** method and xxx-quant-ADMM-xxx.mnn is quantified by the **ADMM** method.
## PS
* Since MNN mainly accelerates model inference on mobile, so the INT8 quantified model will run slower on **PC** than FP32 model in CPU mode.
* If you want to run faster, try using the version-slim model ,using lower-resolution inputs like 160x120 /128x96 or using quantified models(On the mobile).
## Result

================================================
FILE: MNN/python/ultraface_py_mnn.py
================================================
#!/usr/bin/env/ python
# -*- coding: utf-8 -*-
"""
@author:linzai
@file: ultraface_py_mnn.py
@time: 2019-11-25
"""
from __future__ import print_function
import os
import argparse
import sys
import time
from math import ceil
import MNN
import cv2
import numpy as np
import torch
sys.path.append('../../')
import vision.utils.box_utils_numpy as box_utils
parser = argparse.ArgumentParser(description='run ultraface with MNN in py')
parser.add_argument('--model_path', default="../model/version-RFB/RFB-320.mnn", type=str, help='model path')
parser.add_argument('--input_size', default="320,240", type=str,
help='define network input size,format: width,height')
parser.add_argument('--threshold', default=0.7, type=float, help='score threshold')
parser.add_argument('--imgs_path', default="../imgs", type=str, help='imgs dir')
parser.add_argument('--results_path', default="results", type=str, help='results dir')
args = parser.parse_args()
image_mean = np.array([127, 127, 127])
image_std = 128.0
iou_threshold = 0.3
center_variance = 0.1
size_variance = 0.2
min_boxes = [[10, 16, 24], [32, 48], [64, 96], [128, 192, 256]]
strides = [8, 16, 32, 64]
def define_img_size(image_size):
shrinkage_list = []
feature_map_w_h_list = []
for size in image_size:
feature_map = [ceil(size / stride) for stride in strides]
feature_map_w_h_list.append(feature_map)
for i in range(0, len(image_size)):
shrinkage_list.append(strides)
priors = generate_priors(feature_map_w_h_list, shrinkage_list, image_size, min_boxes)
return priors
def generate_priors(feature_map_list, shrinkage_list, image_size, min_boxes, clamp=True):
priors = []
for index in range(0, len(feature_map_list[0])):
scale_w = image_size[0] / shrinkage_list[0][index]
scale_h = image_size[1] / shrinkage_list[1][index]
for j in range(0, feature_map_list[1][index]):
for i in range(0, feature_map_list[0][index]):
x_center = (i + 0.5) / scale_w
y_center = (j + 0.5) / scale_h
for min_box in min_boxes[index]:
w = min_box / image_size[0]
h = min_box / image_size[1]
priors.append([
x_center,
y_center,
w,
h
])
print("priors nums:{}".format(len(priors)))
priors = torch.tensor(priors)
if clamp:
torch.clamp(priors, 0.0, 1.0, out=priors)
return priors
def predict(width, height, confidences, boxes, prob_threshold, iou_threshold=0.3, top_k=-1):
boxes = boxes[0]
confidences = confidences[0]
picked_box_probs = []
picked_labels = []
for class_index in range(1, confidences.shape[1]):
probs = confidences[:, class_index]
mask = probs > prob_threshold
probs = probs[mask]
if probs.shape[0] == 0:
continue
subset_boxes = boxes[mask, :]
box_probs = np.concatenate([subset_boxes, probs.reshape(-1, 1)], axis=1)
box_probs = box_utils.hard_nms(box_probs,
iou_threshold=iou_threshold,
top_k=top_k,
)
picked_box_probs.append(box_probs)
picked_labels.extend([class_index] * box_probs.shape[0])
if not picked_box_probs:
return np.array([]), np.array([]), np.array([])
picked_box_probs = np.concatenate(picked_box_probs)
picked_box_probs[:, 0] *= width
picked_box_probs[:, 1] *= height
picked_box_probs[:, 2] *= width
picked_box_probs[:, 3] *= height
return picked_box_probs[:, :4].astype(np.int32), np.array(picked_labels), picked_box_probs[:, 4]
def inference():
input_size = [int(v.strip()) for v in args.input_size.split(",")]
priors = define_img_size(input_size)
result_path = args.results_path
imgs_path = args.imgs_path
if not os.path.exists(result_path):
os.makedirs(result_path)
listdir = os.listdir(imgs_path)
for file_path in listdir:
img_path = os.path.join(imgs_path, file_path)
image_ori = cv2.imread(img_path)
interpreter = MNN.Interpreter(args.model_path)
session = interpreter.createSession()
input_tensor = interpreter.getSessionInput(session)
image = cv2.cvtColor(image_ori, cv2.COLOR_BGR2RGB)
image = cv2.resize(image, tuple(input_size))
image = image.astype(float)
image = (image - image_mean) / image_std
image = image.transpose((2, 0, 1))
tmp_input = MNN.Tensor((1, 3, input_size[1], input_size[0]), MNN.Halide_Type_Float, image, MNN.Tensor_DimensionType_Caffe)
input_tensor.copyFrom(tmp_input)
time_time = time.time()
interpreter.runSession(session)
scores = interpreter.getSessionOutput(session, "scores").getData()
boxes = interpreter.getSessionOutput(session, "boxes").getData()
boxes = np.expand_dims(np.reshape(boxes, (-1, 4)), axis=0)
scores = np.expand_dims(np.reshape(scores, (-1, 2)), axis=0)
print("inference time: {} s".format(round(time.time() - time_time, 4)))
boxes = box_utils.convert_locations_to_boxes(boxes, priors, center_variance, size_variance)
boxes = box_utils.center_form_to_corner_form(boxes)
boxes, labels, probs = predict(image_ori.shape[1], image_ori.shape[0], scores, boxes, args.threshold)
for i in range(boxes.shape[0]):
box = boxes[i, :]
cv2.rectangle(image_ori, (box[0], box[1]), (box[2], box[3]), (0, 255, 0), 2)
cv2.imwrite(os.path.join(result_path, file_path), image_ori)
print("result_pic is written to {}".format(os.path.join(result_path, file_path)))
cv2.imshow("UltraFace_mnn_py", image_ori)
cv2.waitKey(-1)
cv2.destroyAllWindows()
if __name__ == "__main__":
inference()
================================================
FILE: MNN/src/UltraFace.cpp
================================================
// Created by Linzaer on 2019/11/15.
// Copyright © 2019 Linzaer. All rights reserved.
#define clip(x, y) (x < 0 ? 0 : (x > y ? y : x))
#include "UltraFace.hpp"
using namespace std;
UltraFace::UltraFace(const std::string &mnn_path,
int input_width, int input_length, int num_thread_,
float score_threshold_, float iou_threshold_, int topk_) {
num_thread = num_thread_;
score_threshold = score_threshold_;
iou_threshold = iou_threshold_;
in_w = input_width;
in_h = input_length;
w_h_list = {in_w, in_h};
for (auto size : w_h_list) {
std::vector<float> fm_item;
for (float stride : strides) {
fm_item.push_back(ceil(size / stride));
}
featuremap_size.push_back(fm_item);
}
for (auto size : w_h_list) {
shrinkage_size.push_back(strides);
}
/* generate prior anchors */
for (int index = 0; index < num_featuremap; index++) {
float scale_w = in_w / shrinkage_size[0][index];
float scale_h = in_h / shrinkage_size[1][index];
for (int j = 0; j < featuremap_size[1][index]; j++) {
for (int i = 0; i < featuremap_size[0][index]; i++) {
float x_center = (i + 0.5) / scale_w;
float y_center = (j + 0.5) / scale_h;
for (float k : min_boxes[index]) {
float w = k / in_w;
float h = k / in_h;
priors.push_back({clip(x_center, 1), clip(y_center, 1), clip(w, 1), clip(h, 1)});
}
}
}
}
/* generate prior anchors finished */
num_anchors = priors.size();
ultraface_interpreter = std::shared_ptr<MNN::Interpreter>(MNN::Interpreter::createFromFile(mnn_path.c_str()));
MNN::ScheduleConfig config;
config.numThread = num_thread;
MNN::BackendConfig backendConfig;
backendConfig.precision = (MNN::BackendConfig::PrecisionMode) 2;
config.backendConfig = &backendConfig;
ultraface_session = ultraface_interpreter->createSession(config);
input_tensor = ultraface_interpreter->getSessionInput(ultraface_session, nullptr);
}
UltraFace::~UltraFace() {
ultraface_interpreter->releaseModel();
ultraface_interpreter->releaseSession(ultraface_session);
}
int UltraFace::detect(cv::Mat &raw_image, std::vector<FaceInfo> &face_list) {
if (raw_image.empty()) {
std::cout << "image is empty ,please check!" << std::endl;
return -1;
}
image_h = raw_image.rows;
image_w = raw_image.cols;
cv::Mat image;
cv::resize(raw_image, image, cv::Size(in_w, in_h));
ultraface_interpreter->resizeTensor(input_tensor, {1, 3, in_h, in_w});
ultraface_interpreter->resizeSession(ultraface_session);
std::shared_ptr<MNN::CV::ImageProcess> pretreat(
MNN::CV::ImageProcess::create(MNN::CV::BGR, MNN::CV::RGB, mean_vals, 3,
norm_vals, 3));
pretreat->convert(image.data, in_w, in_h, image.step[0], input_tensor);
auto start = chrono::steady_clock::now();
// run network
ultraface_interpreter->runSession(ultraface_session);
// get output data
string scores = "scores";
string boxes = "boxes";
MNN::Tensor *tensor_scores = ultraface_interpreter->getSessionOutput(ultraface_session, scores.c_str());
MNN::Tensor *tensor_boxes = ultraface_interpreter->getSessionOutput(ultraface_session, boxes.c_str());
MNN::Tensor tensor_scores_host(tensor_scores, tensor_scores->getDimensionType());
tensor_scores->copyToHostTensor(&tensor_scores_host);
MNN::Tensor tensor_boxes_host(tensor_boxes, tensor_boxes->getDimensionType());
tensor_boxes->copyToHostTensor(&tensor_boxes_host);
std::vector<FaceInfo> bbox_collection;
auto end = chrono::steady_clock::now();
chrono::duration<double> elapsed = end - start;
cout << "inference time:" << elapsed.count() << " s" << endl;
generateBBox(bbox_collection, tensor_scores, tensor_boxes);
nms(bbox_collection, face_list);
return 0;
}
void UltraFace::generateBBox(std::vector<FaceInfo> &bbox_collection, MNN::Tensor *scores, MNN::Tensor *boxes) {
for (int i = 0; i < num_anchors; i++) {
if (scores->host<float>()[i * 2 + 1] > score_threshold) {
FaceInfo rects;
float x_center = boxes->host<float>()[i * 4] * center_variance * priors[i][2] + priors[i][0];
float y_center = boxes->host<float>()[i * 4 + 1] * center_variance * priors[i][3] + priors[i][1];
float w = exp(boxes->host<float>()[i * 4 + 2] * size_variance) * priors[i][2];
float h = exp(boxes->host<float>()[i * 4 + 3] * size_variance) * priors[i][3];
rects.x1 = clip(x_center - w / 2.0, 1) * image_w;
rects.y1 = clip(y_center - h / 2.0, 1) * image_h;
rects.x2 = clip(x_center + w / 2.0, 1) * image_w;
rects.y2 = clip(y_center + h / 2.0, 1) * image_h;
rects.score = clip(scores->host<float>()[i * 2 + 1], 1);
bbox_collection.push_back(rects);
}
}
}
void UltraFace::nms(std::vector<FaceInfo> &input, std::vector<FaceInfo> &output, int type) {
std::sort(input.begin(), input.end(), [](const FaceInfo &a, const FaceInfo &b) { return a.score > b.score; });
int box_num = input.size();
std::vector<int> merged(box_num, 0);
for (int i = 0; i < box_num; i++) {
if (merged[i])
continue;
std::vector<FaceInfo> buf;
buf.push_back(input[i]);
merged[i] = 1;
float h0 = input[i].y2 - input[i].y1 + 1;
float w0 = input[i].x2 - input[i].x1 + 1;
float area0 = h0 * w0;
for (int j = i + 1; j < box_num; j++) {
if (merged[j])
continue;
float inner_x0 = input[i].x1 > input[j].x1 ? input[i].x1 : input[j].x1;
float inner_y0 = input[i].y1 > input[j].y1 ? input[i].y1 : input[j].y1;
float inner_x1 = input[i].x2 < input[j].x2 ? input[i].x2 : input[j].x2;
float inner_y1 = input[i].y2 < input[j].y2 ? input[i].y2 : input[j].y2;
float inner_h = inner_y1 - inner_y0 + 1;
float inner_w = inner_x1 - inner_x0 + 1;
if (inner_h <= 0 || inner_w <= 0)
continue;
float inner_area = inner_h * inner_w;
float h1 = input[j].y2 - input[j].y1 + 1;
float w1 = input[j].x2 - input[j].x1 + 1;
float area1 = h1 * w1;
float score;
score = inner_area / (area0 + area1 - inner_area);
if (score > iou_threshold) {
merged[j] = 1;
buf.push_back(input[j]);
}
}
switch (type) {
case hard_nms: {
output.push_back(buf[0]);
break;
}
case blending_nms: {
float total = 0;
for (int i = 0; i < buf.size(); i++) {
total += exp(buf[i].score);
}
FaceInfo rects;
memset(&rects, 0, sizeof(rects));
for (int i = 0; i < buf.size(); i++) {
float rate = exp(buf[i].score) / total;
rects.x1 += buf[i].x1 * rate;
rects.y1 += buf[i].y1 * rate;
rects.x2 += buf[i].x2 * rate;
rects.y2 += buf[i].y2 * rate;
rects.score += buf[i].score * rate;
}
output.push_back(rects);
break;
}
default: {
printf("wrong type of nms.");
exit(-1);
}
}
}
}
================================================
FILE: MNN/src/UltraFace.hpp
================================================
// Created by Linzaer on 2019/11/15.
// Copyright © 2019 Linzaer. All rights reserved.
#ifndef UltraFace_hpp
#define UltraFace_hpp
#pragma once
#include "Interpreter.hpp"
#include "MNNDefine.h"
#include "Tensor.hpp"
#include "ImageProcess.hpp"
#include <opencv2/opencv.hpp>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <chrono>
#define num_featuremap 4
#define hard_nms 1
#define blending_nms 2 /* mix nms was been proposaled in paper blaze face, aims to minimize the temporal jitter*/
typedef struct FaceInfo {
float x1;
float y1;
float x2;
float y2;
float score;
} FaceInfo;
class UltraFace {
public:
UltraFace(const std::string &mnn_path,
int input_width, int input_length, int num_thread_ = 4, float score_threshold_ = 0.7, float iou_threshold_ = 0.3,
int topk_ = -1);
~UltraFace();
int detect(cv::Mat &img, std::vector<FaceInfo> &face_list);
private:
void generateBBox(std::vector<FaceInfo> &bbox_collection, MNN::Tensor *scores, MNN::Tensor *boxes);
void nms(std::vector<FaceInfo> &input, std::vector<FaceInfo> &output, int type = blending_nms);
private:
std::shared_ptr<MNN::Interpreter> ultraface_interpreter;
MNN::Session *ultraface_session = nullptr;
MNN::Tensor *input_tensor = nullptr;
int num_thread;
int image_w;
int image_h;
int in_w;
int in_h;
int num_anchors;
float score_threshold;
float iou_threshold;
const float mean_vals[3] = {127, 127, 127};
const float norm_vals[3] = {1.0 / 128, 1.0 / 128, 1.0 / 128};
const float center_variance = 0.1;
const float size_variance = 0.2;
const std::vector<std::vector<float>> min_boxes = {
{10.0f, 16.0f, 24.0f},
{32.0f, 48.0f},
{64.0f, 96.0f},
{128.0f, 192.0f, 256.0f}};
const std::vector<float> strides = {8.0, 16.0, 32.0, 64.0};
std::vector<std::vector<float>> featuremap_size;
std::vector<std::vector<float>> shrinkage_size;
std::vector<int> w_h_list;
std::vector<std::vector<float>> priors = {};
};
#endif /* UltraFace_hpp */
================================================
FILE: MNN/src/main.cpp
================================================
// Created by Linzaer on 2019/11/15.
// Copyright © 2019 Linzaer. All rights reserved.
#include "UltraFace.hpp"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
int main(int argc, char **argv) {
if (argc <= 2) {
fprintf(stderr, "Usage: %s <mnn .mnn> [image files...]\n", argv[0]);
return 1;
}
string mnn_path = argv[1];
UltraFace ultraface(mnn_path, 320, 240, 4, 0.65); // config model input
for (int i = 2; i < argc; i++) {
string image_file = argv[i];
cout << "Processing " << image_file << endl;
cv::Mat frame = cv::imread(image_file);
auto start = chrono::steady_clock::now();
vector<FaceInfo> face_info;
ultraface.detect(frame, face_info);
for (auto face : face_info) {
cv::Point pt1(face.x1, face.y1);
cv::Point pt2(face.x2, face.y2);
cv::rectangle(frame, pt1, pt2, cv::Scalar(0, 255, 0), 2);
}
auto end = chrono::steady_clock::now();
chrono::duration<double> elapsed = end - start;
cout << "all time: " << elapsed.count() << " s" << endl;
cv::imshow("UltraFace", frame);
cv::waitKey();
string result_name = "result" + to_string(i) + ".jpg";
cv::imwrite(result_name, frame);
}
return 0;
}
================================================
FILE: README.md
================================================
[English](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB ) | [中文简体](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/README_CN.md)
# Ultra-Light-Fast-Generic-Face-Detector-1MB
# Ultra-lightweight face detection model

This model is a lightweight facedetection model designed for edge computing devices.
- In terms of model size, the default FP32 precision (.pth) file size is **1.04~1.1MB**, and the inference framework int8 quantization size is about **300KB**.
- In terms of the calculation amount of the model, the input resolution of 320x240 is about **90~109 MFlops**.
- There are two versions of the model, version-slim (network backbone simplification,slightly faster) and version-RFB (with the modified RFB module, higher precision).
- Widerface training pre-training model with different input resolutions of 320x240 and 640x480 is provided to better work in different application scenarios.
- Support for onnx export for ease of migration and inference.
- [Provide NCNN C++ inference code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/ncnn).
- [Provide MNN C++ inference code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/MNN), [MNN Python inference code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/MNN/python), [FP32/INT8 quantized models](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/MNN/model).
- [Provide Caffe model](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/caffe/model) and [onnx2caffe conversion code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/caffe).
- [Caffe python inference code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/caffe/ultra_face_caffe_inference.py) and [OpencvDNN inference code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/caffe/ultra_face_opencvdnn_inference.py).
## Tested the environment that works
- Ubuntu16.04、Ubuntu18.04、Windows 10(for inference)
- Python3.6
- Pytorch1.2
- CUDA10.0 + CUDNN7.6
## Accuracy, speed, model size comparison
The training set is the VOC format data set generated by using the cleaned widerface labels provided by [Retinaface](https://github.com/deepinsight/insightface/blob/master/RetinaFace/README.md) in conjunction with the widerface data set (PS: the following test results were obtained by myself, and the results may be partially inconsistent).
### Widerface test
- Test accuracy in the WIDER FACE val set (single-scale input resolution: **320*240 or scaling by the maximum side length of 320**)
Model|Easy Set|Medium Set|Hard Set
------|--------|----------|--------
libfacedetection v1(caffe)|0.65 |0.5 |0.233
libfacedetection v2(caffe)|0.714 |0.585 |0.306
Retinaface-Mobilenet-0.25 (Mxnet) |0.745|0.553|0.232
version-slim|0.77 |0.671 |0.395
version-RFB|**0.787** |**0.698** |**0.438**
- Test accuracy in the WIDER FACE val set (single-scale input resolution: **VGA 640*480 or scaling by the maximum side length of 640** )
Model|Easy Set|Medium Set|Hard Set
------|--------|----------|--------
libfacedetection v1(caffe)|0.741 |0.683 |0.421
libfacedetection v2(caffe)|0.773 |0.718 |0.485
Retinaface-Mobilenet-0.25 (Mxnet) |**0.879**|0.807|0.481
version-slim|0.853 |0.819 |0.539
version-RFB|0.855 |**0.822** |**0.579**
> - This part mainly tests the effect of the test set under the medium and small resolutions.
> - RetinaFace-mnet (Retinaface-Mobilenet-0.25), from a great job [insightface](https://github.com/deepinsight/insightface), when testing this network, the original image is scaled by 320 or 640 as the maximum side length, so the face will not be deformed, and the rest of the networks will have a fixed size resize. At the same time, the result of the RetinaFace-mnet optimal 1600 single-scale val set was 0.887 (Easy) / 0.87 (Medium) / 0.791 (Hard).
### Terminal device inference speed
- Raspberry Pi 4B MNN Inference Latency **(unit: ms)** (ARM/A72x4/1.5GHz/input resolution: **320x240** /int8 quantization)
Model|1 core|2 core|3 core|4 core
------|--------|----------|--------|--------
libfacedetection v1|**28** |**16**|**12**|9.7
Official Retinaface-Mobilenet-0.25 (Mxnet) |46|25|18.5|15
version-slim|29 |**16** |**12**|**9.5**
version-RFB|35 |19.6 |14.8| 11
- iPhone 6s Plus MNN (version tag:0.2.1.5) Inference Latency ( input resolution : **320x240** )[Data comes from MNN official](https://www.yuque.com/mnn/en/demo_zoo#bXsRY)
Model|Inference Latency(ms)
------|--------
[slim-320](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/MNN/model/version-slim/slim-320.mnn) |6.33
[RFB-320](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/MNN/model/version-RFB/RFB-320.mnn)|7.8
- [Kendryte K210](https://kendryte.com/) NNCase Inference Latency (RISC-V/400MHz/input resolution: **320x240** /int8 quantization)[Data comes from NNCase](https://github.com/kendryte/nncase/tree/master/examples/fast_facedetect)
Model|Inference Latency(ms)
------|--------
[slim-320](https://github.com/kendryte/nncase/tree/master/examples/fast_facedetect/k210/kpu_fast_facedetect_example/slim-320.kmodel)|65.6
[RFB-320](https://github.com/kendryte/nncase/tree/master/examples/fast_facedetect/k210/kpu_fast_facedetect_example/RFB-320.kmodel)|164.8
### Model size comparison
- Comparison of several open source lightweight face detection models:
Model|model file size(MB)
------|--------
libfacedetection v1(caffe)| 2.58
libfacedetection v2(caffe)| 3.34
Official Retinaface-Mobilenet-0.25 (Mxnet) | 1.68
version-slim| **1.04**
version-RFB| **1.11**
## Generate VOC format training data set and training process
1. Download the wideface official website dataset or download the training set I provided and extract it into the ./data folder:
(1) The clean widerface data pack after filtering out the 10px*10px small face: [Baidu cloud disk (extraction code: cbiu)](https://pan.baidu.com/s/1MR0ZOKHUP_ArILjbAn03sw) 、[Google Drive](https://drive.google.com/open?id=1OBY-Pk5hkcVBX1dRBOeLI4e4OCvqJRnH )
(2) Complete widerface data compression package without filtering small faces: [Baidu cloud disk (extraction code: ievk)](https://pan.baidu.com/s/1faHNz9ZrtEmr_yw48GW7ZA)、[Google Drive](https://drive.google.com/open?id=1sbBrDRgctEkymIpCh1OZBrU5qBS-SnCP )
2. **(PS: If you download the filtered packets in (1) above, you don't need to perform this step)** Because the wideface has many small and unclear faces, which is not conducive to the convergence of efficient models, it needs to be filtered for training.By default,faces smaller than 10 pixels by 10 pixels will be filtered.
run ./data/wider_face_2_voc_add_landmark.py
```Python
python3 ./data/wider_face_2_voc_add_landmark.py
```
After the program is run and finished, the **wider_face_add_lm_10_10** folder will be generated in the ./data directory. The folder data and data package (1) are the same after decompression. The complete directory structure is as follows:
```Shell
data/
retinaface_labels/
test/
train/
val/
wider_face/
WIDER_test/
WIDER_train/
WIDER_val/
wider_face_add_lm_10_10/
Annotations/
ImageSets/
JPEGImages/
wider_face_2_voc_add_landmark.py
```
3. At this point, the VOC training set is ready. There are two scripts: **train-version-slim.sh** and **train-version-RFB.sh** in the root directory of the project. The former is used to train the **slim version** model, and the latter is used. Training **RFB version** model, the default parameters have been set, if the parameters need to be changed, please refer to the description of each training parameter in **./train.py**.
4. Run **train-version-slim.sh** **train-version-RFB.sh**
```Shell
sh train-version-slim.sh or sh train-version-RFB.sh
```
## Detecting image effects (input resolution: 640x480)



## PS
- If the actual production scene is medium-distance, large face, and small number of faces, it is recommended to use input size input_size: 320 (320x240) resolution for training, and use 320x240 ,160x120 or 128x96 image size input for inference, such as using the provided pre-training model **version-slim-320.pth** or **version-RFB-320.pth** .
- If the actual production scene is medium or long distance, medium or small face and large face number, it is recommended to adopt:
(1) Optimal: input size input_size: 640 (640x480) resolution training, and use the same or larger input size for inference, such as using the provided pre-training model **version-slim-640.pth** or **version-RFB-640.pth** for inference, lower False positives.
(2) Sub-optimal: input size input_size: 320 (320x240) resolution training, and use 480x360 or 640x480 size input for predictive reasoning, more sensitive to small faces, false positives will increase.
- The best results for each scene require adjustment of the input resolution to strike a balance between speed and accuracy.
- Excessive input resolution will enhance the recall rate of small faces, but it will also increase the false positive rate of large and close-range faces, and the speed of inference will increase exponentially.
- Too small input resolution will significantly speed up the inference, but it will greatly reduce the recall rate of small faces.
- The input resolution of the production scene should be as consistent as possible with the input resolution of the model training, and the up and down floating should not be too large.
## TODO LIST
- Add some test data
## Completed list
- [Widerface test code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/widerface_evaluate)
- [NCNN C++ inference code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/ncnn) ([vealocia](https://github.com/vealocia))
- [MNN C++ inference code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/MNN), [MNN Python inference code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/MNN/python)
- [Caffe model](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/caffe/model) and [onnx2caffe conversion code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/caffe)
- [Caffe python inference code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/caffe/ultra_face_caffe_inference.py) and [OpencvDNN inference code](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/caffe/ultra_face_opencvdnn_inference.py)
## Third-party related projects
- [NNCase C++ inference code](https://github.com/kendryte/nncase/tree/master/examples/fast_facedetect)
- [UltraFaceDotNet (C#)](https://github.com/takuya-takeuchi/UltraFaceDotNet)
- [faceDetect-ios](https://github.com/Ian778/faceDetect-ios)
- [Android-FaceDetection-UltraNet-MNN](https://github.com/jackweiwang/Android-FaceDetection-UltraNet-MNN)
- [Ultra-Tensorflow-Model-Converter](https://github.com/jason9075/Ultra-Light-Fast-Generic-Face-Detector_Tensorflow-Model-Converter)
- [UltraFace TNN C++ Demo](https://github.com/DefTruth/lite.ai.toolkit/blob/main/lite/tnn/cv/tnn_ultraface.cpp)
## Reference
- [pytorch-ssd](https://github.com/qfgaohao/pytorch-ssd)
- [libfacedetection](https://github.com/ShiqiYu/libfacedetection/)
- [RFBNet](https://github.com/ruinmessi/RFBNet)
- [RFSong-779](https://github.com/songwsx/RFSong-779)
- [Retinaface](https://github.com/deepinsight/insightface/blob/master/RetinaFace/README.md)
================================================
FILE: README_CN.md
================================================
[English](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB) | [中文简体](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/README_CN.md )
# Ultra-Light-Fast-Generic-Face-Detector-1MB
# 轻量级人脸检测模型

该模型是针对边缘计算设备设计的轻量人脸检测模型。
- 在模型大小上,默认FP32精度下(.pth)文件大小为 **1.04~1.1MB**,推理框架int8量化后大小为 **300KB** 左右。
- 在模型计算量上,320x240的输入分辨率下 **90~109 MFlops**左右。
- 模型有两个版本,version-slim(主干精简速度略快),version-RFB(加入了修改后的RFB模块,精度更高)。
- 提供320x240、640x480不同输入分辨率下使用widerface训练的预训练模型,更好的工作于不同的应用场景。
- 支持onnx导出。
- [提供NCNN C++推理代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/ncnn)。
- [提供MNN C++推理代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/MNN)、[MNN Python推理代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/MNN/python)、[FP32/INT8量化后模型](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/MNN/model)。
- [提供转换后的Caffe model](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/caffe/model) 和 [onnx2caffe 转换代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/caffe)。
- [Caffe python 推理代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/caffe/ultra_face_caffe_inference.py) 和 [OpencvDNN推理代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/caffe/ultra_face_opencvdnn_inference.py)。
## 测试过正常的运行环境
- Ubuntu16.04、Ubuntu18.04、Windows 10(inference)
- Python3.6
- Pytorch1.2
- CUDA10.0 + CUDNN7.6
## 精度、速度、模型大小比较
训练集是使用[Retinaface](https://github.com/deepinsight/insightface/blob/master/RetinaFace/README.md )提供的清理过的widerface标签配合widerface数据集生成VOC训练集(PS:以下测试结果为本人测试,结果可能有部分出入)。
### Widerface测试
- 在WIDER FACE val集测试精度(单尺度输入分辨率:**320*240 或按最大边长320等比缩放**)
模型|Easy Set|Medium Set|Hard Set
------|--------|----------|--------
libfacedetection v1(caffe)|0.65 |0.5 |0.233
libfacedetection v2(caffe)|0.714 |0.585 |0.306
Retinaface-Mobilenet-0.25 (Mxnet) |0.745|0.553|0.232
version-slim|0.77 |0.671 |0.395
version-RFB|**0.787** |**0.698** |**0.438**
- 在WIDER FACE val集测试精度(单尺度输入分辨率:**VGA 640*480 或按最大边长640等比缩放** )
模型|Easy Set|Medium Set|Hard Set
------|--------|----------|--------
libfacedetection v1(caffe)|0.741 |0.683 |0.421
libfacedetection v2(caffe)|0.773 |0.718 |0.485
Retinaface-Mobilenet-0.25 (Mxnet) |**0.879**|0.807|0.481
version-slim|0.853 |0.819 |0.539
version-RFB|0.855 |**0.822** |**0.579**
> - 该部分主要是测试模型在中小分辨率下的测试集效果。
> - RetinaFace-mnet(Retinaface-Mobilenet-0.25),来自于很棒的工作[insightface](https://github.com/deepinsight/insightface),测试该网络时是将原图按最大边长320或者640等比缩放,所以人脸不会形变,其余网络采用固定尺寸resize。同时RetinaFace-mnet最优1600单尺度val测试集结果为0.887(Easy)/0.87(Medium)/0.791(Hard)。
### 终端设备推理速度
- 树莓派4B MNN推理测试耗时 **(单位:ms)**(ARM/A72x4/1.5GHz/输入分辨率 : **320x240** /int8 量化 )
模型|1核|2核|3核|4核
------|--------|----------|--------|--------
libfacedetection v1|**28** |**16**|**12**|9.7
官方 Retinaface-Mobilenet-0.25 (Mxnet) |46|25|18.5|15
version-slim|29 |**16** |**12**|**9.5**
version-RFB|35 |19.6 |14.8| 11
- iPhone 6s Plus MNN (版本Tag:0.2.1.5) 推理测试耗时(输入分辨率 : **320x240** )[数据来自MNN官方](https://www.yuque.com/mnn/en/demo_zoo#bXsRY)
模型|耗时(ms)
------|--------
[slim-320](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/MNN/model/version-slim/slim-320.mnn) |6.33
[RFB-320](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/MNN/model/version-RFB/RFB-320.mnn)|7.8
- [Kendryte K210](https://kendryte.com/) NNCase 推理测试耗时 (RISC-V/400MHz/输入分辨率 : **320x240** /int8 量化) [数据来自NNCase](https://github.com/kendryte/nncase/tree/master/examples/fast_facedetect)
Model|Inference Latency(ms)
------|--------
[slim-320](https://github.com/kendryte/nncase/tree/master/examples/fast_facedetect/k210/kpu_fast_facedetect_example/slim-320.kmodel)|65.6
[RFB-320](https://github.com/kendryte/nncase/tree/master/examples/fast_facedetect/k210/kpu_fast_facedetect_example/RFB-320.kmodel)|164.8
### 模型大小比较
- 若干开源轻量级人脸检测模型大小比较 :
模型|模型文件大小(MB)
------|--------
libfacedetection v1(caffe)| 2.58
libfacedetection v2(caffe)| 3.34
官方 Retinaface-Mobilenet-0.25 (Mxnet) | 1.68
version-slim| **1.04**
version-RFB| **1.11**
## 生成VOC格式训练数据集以及训练流程
1. 下载widerface官网数据集或者下载我提供的训练集解压放入./data文件夹内:
(1)过滤掉10px*10px 小人脸后的干净widerface数据压缩包 :[百度云盘 (提取码:cbiu)](https://pan.baidu.com/s/1MR0ZOKHUP_ArILjbAn03sw ) 、[Google Drive](https://drive.google.com/open?id=1OBY-Pk5hkcVBX1dRBOeLI4e4OCvqJRnH )
(2)未过滤小人脸的完整widerface数据压缩包 :[百度云盘 (提取码:ievk)](https://pan.baidu.com/s/1faHNz9ZrtEmr_yw48GW7ZA ) 、[Google Drive](https://drive.google.com/open?id=1sbBrDRgctEkymIpCh1OZBrU5qBS-SnCP )
2. **(PS:如果下载的是过滤后的上述(1)中的数据包,则不需要执行这步)** 由于widerface存在很多极小的不清楚的人脸,不太利于高效模型的收敛,所以需要过滤训练,默认过滤人脸大小10像素x10像素以下的人脸。
运行./data/wider_face_2_voc_add_landmark.py
```Python
python3 ./data/wider_face_2_voc_add_landmark.py
```
程序运行和完毕后会在./data目录下生成 **wider_face_add_lm_10_10**文件夹,该文件夹数据和数据包(1)解压后相同,完整目录结构如下:
```Shell
data/
retinaface_labels/
test/
train/
val/
wider_face/
WIDER_test/
WIDER_train/
WIDER_val/
wider_face_add_lm_10_10/
Annotations/
ImageSets/
JPEGImages/
wider_face_2_voc_add_landmark.py
```
3. 至此VOC训练集准备完毕,项目根目录下分别有 **train-version-slim.sh** 和 **train-version-RFB.sh** 两个脚本,前者用于训练**slim版本**模型,后者用于训练**RFB版本**模型,默认参数已设置好,参数如需微调请参考 **./train.py** 中关于各训练超参数的说明。
4. 运行**train-version-slim.sh** 或 **train-version-RFB.sh**即可
```Shell
sh train-version-slim.sh 或者 sh train-version-RFB.sh
```
## 检测图片效果(输入分辨率:640x480)



## PS
- 若生产实际场景为中近距离、人脸大、人脸数少,则建议采用输入尺寸input_size:320(320x240)分辨率训练,并采用 320x240/160x120/128x96 图片大小输入进行预测推理,如使用提供的预训练模型 **version-slim-320.pth** 或者 **version-RFB-320.pth** 进行推理。
- 若生产实际场景为中远距离、人脸中小、人脸数多,则建议采用:
(1)最优:输入尺寸input_size:640(640x480)分辨率训练,并采用同等或更大输入尺寸进行预测推理,如使用提供的预训练模型 **version-slim-640.pth** 或者 **version-RFB-640.pth** 进行推理,更低的误报。
(2)次优:输入尺寸input_size:320(320x240)分辨率训练,并采用480x360或640x480大小输入进行预测推理,对于小人脸更敏感,误报会增加。
- 各个场景的最佳效果需要调整输入分辨率从而在速度和精度中间取得平衡。
- 过大的输入分辨率虽然会增强小人脸的召回率,但是也会提高大、近距离人脸的误报率,而且推理速度延迟成倍增加。
- 过小的输入分辨率虽然会明显加快推理速度,但是会大幅降低小人脸的召回率。
- 生产场景的输入分辨率尽量与模型训练时的输入分辨率保持一致,上下浮动不宜过大。
## TODO LIST
- 完善测试数据
## 已完成功能清单
- [Widerface测试代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/widerface_evaluate)
- [NCNN C++推理代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/ncnn) ([vealocia](https://github.com/vealocia))
- [MNN C++推理代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/MNN)、[MNN Python推理代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/MNN/python)
- [Caffe model](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/caffe/model) 和 [onnx2caffe 转换代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/caffe)
- [Caffe python 推理代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/caffe/ultra_face_caffe_inference.py) 和 [OpencvDNN推理代码](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/blob/master/caffe/ultra_face_opencvdnn_inference.py)
## 第三方相关工程
- [NNCase C++推理代码](https://github.com/kendryte/nncase/tree/master/examples/fast_facedetect)
- [UltraFaceDotNet (C#)](https://github.com/takuya-takeuchi/UltraFaceDotNet)
- [faceDetect-ios](https://github.com/Ian778/faceDetect-ios)
- [Android-FaceDetection-UltraNet-MNN](https://github.com/jackweiwang/Android-FaceDetection-UltraNet-MNN)
- [Ultra-Tensorflow-Model-Converter](https://github.com/jason9075/Ultra-Light-Fast-Generic-Face-Detector_Tensorflow-Model-Converter)
- [UltraFace TNN C++ Demo](https://github.com/DefTruth/lite.ai.toolkit/blob/main/lite/tnn/cv/tnn_ultraface.cpp)
## Reference
- [pytorch-ssd](https://github.com/qfgaohao/pytorch-ssd)
- [libfacedetection](https://github.com/ShiqiYu/libfacedetection/)
- [RFBNet](https://github.com/ruinmessi/RFBNet)
- [RFSong-779](https://github.com/songwsx/RFSong-779)
- [Retinaface](https://github.com/deepinsight/insightface/blob/master/RetinaFace/README.md)
================================================
FILE: caffe/MyCaffe.py
================================================
from collections import OrderedDict, Counter
from caffe.proto import caffe_pb2
from google import protobuf
import six
def param_name_dict():
"""Find out the correspondence between layer names and parameter names."""
layer = caffe_pb2.LayerParameter()
# get all parameter names (typically underscore case) and corresponding
# type names (typically camel case), which contain the layer names
# (note that not all parameters correspond to layers, but we'll ignore that)
param_names = [f.name for f in layer.DESCRIPTOR.fields if f.name.endswith('_param')]
param_type_names = [type(getattr(layer, s)).__name__ for s in param_names]
# strip the final '_param' or 'Parameter'
param_names = [s[:-len('_param')] for s in param_names]
param_type_names = [s[:-len('Parameter')] for s in param_type_names]
return dict(zip(param_type_names, param_names))
def assign_proto(proto, name, val):
"""Assign a Python object to a protobuf message, based on the Python
type (in recursive fashion). Lists become repeated fields/messages, dicts
become messages, and other types are assigned directly. For convenience,
repeated fields whose values are not lists are converted to single-element
lists; e.g., `my_repeated_int_field=3` is converted to
`my_repeated_int_field=[3]`."""
is_repeated_field = hasattr(getattr(proto, name), 'extend')
if is_repeated_field and not isinstance(val, list):
val = [val]
if isinstance(val, list):
if isinstance(val[0], dict):
for item in val:
proto_item = getattr(proto, name).add()
for k, v in six.iteritems(item):
assign_proto(proto_item, k, v)
else:
getattr(proto, name).extend(val)
elif isinstance(val, dict):
for k, v in six.iteritems(val):
assign_proto(getattr(proto, name), k, v)
else:
setattr(proto, name, val)
class Function(object):
"""A Function specifies a layer, its parameters, and its inputs (which
are Tops from other layers)."""
def __init__(self, type_name, layer_name, inputs,outputs, **params):
self.type_name = type_name
self.inputs = inputs
self.outputs = outputs
self.params = params
self.layer_name = layer_name
self.ntop = self.params.get('ntop', 1)
# use del to make sure kwargs are not double-processed as layer params
if 'ntop' in self.params:
del self.params['ntop']
self.in_place = self.params.get('in_place', False)
if 'in_place' in self.params:
del self.params['in_place']
# self.tops = tuple(Top(self, n) for n in range(self.ntop))l
def _get_name(self, names, autonames):
if self not in names and self.ntop > 0:
names[self] = self._get_top_name(self.tops[0], names, autonames)
elif self not in names:
autonames[self.type_name] += 1
names[self] = self.type_name + str(autonames[self.type_name])
return names[self]
def _get_top_name(self, top, names, autonames):
if top not in names:
autonames[top.fn.type_name] += 1
names[top] = top.fn.type_name + str(autonames[top.fn.type_name])
return names[top]
def _to_proto(self):
bottom_names = []
for inp in self.inputs:
# inp._to_proto(layers, names, autonames)
bottom_names.append(inp)
layer = caffe_pb2.LayerParameter()
layer.type = self.type_name
layer.bottom.extend(bottom_names)
if self.in_place:
layer.top.extend(layer.bottom)
else:
for top in self.outputs:
layer.top.append(top)
layer.name = self.layer_name
# print(self.type_name + "...")
for k, v in six.iteritems(self.params):
# special case to handle generic *params
# print("generating "+k+"...")
if k.endswith('param'):
assign_proto(layer, k, v)
else:
try:
assign_proto(getattr(layer,
_param_names[self.type_name] + '_param'), k, v)
except (AttributeError, KeyError):
assign_proto(layer, k, v)
return layer
class Layers(object):
"""A Layers object is a pseudo-module which generates functions that specify
layers; e.g., Layers().Convolution(bottom, kernel_size=3) will produce a Top
specifying a 3x3 convolution applied to bottom."""
def __getattr__(self, name):
def layer_fn(*args, **kwargs):
fn = Function(name, args, kwargs)
return fn
return layer_fn
_param_names = param_name_dict()
================================================
FILE: caffe/README.md
================================================
## I added several operator(Transpose/Permute/Softmax) conversion support based on [onnx2caffe](https://github.com/MTlab/onnx2caffe).
# Convert pytorch to Caffe by ONNX
This tool converts [pytorch](https://github.com/pytorch/pytorch) model to [Caffe](https://github.com/BVLC/caffe) model by [ONNX](https://github.com/onnx/onnx)
only use for inference
### Dependencies
* caffe (with python support)
* pytorch 0.4+ (optional if you only want to convert onnx)
* onnx
### Current support operation
* Conv
* ConvTranspose
* BatchNormalization
* MaxPool
* AveragePool
* Relu
* Sigmoid
* Dropout
* Gemm (InnerProduct only)
* Add
* Mul
* Reshape
* Upsample
* Concat
* Flatten
* Transpose/Permute (new)
* Softmax (new)
## PS
* You need to use [onnx-simplifier](https://github.com/daquexian/onnx-simplifier) to simplify onnx model and then run convertCaffe.py to convert it into caffe model.
* You need to install [ssd-caffe](https://github.com/weiliu89/caffe/tree/ssd) and pycaffe of ssd-caffe.
================================================
FILE: caffe/convertCaffe.py
================================================
from __future__ import print_function
import sys
import caffe
from caffe.proto import caffe_pb2
import onnx
caffe.set_mode_cpu()
sys.path.append('../')
from onnx2caffe._transformers import ConvAddFuser, ConstantsToInitializers
from onnx2caffe._graph import Graph
import onnx2caffe._operators as cvt
import onnx2caffe._weightloader as wlr
from onnx2caffe._error_utils import ErrorHandling
from onnx import shape_inference
transformers = [
ConstantsToInitializers(),
ConvAddFuser(),
]
def convertToCaffe(graph, prototxt_save_path, caffe_model_save_path):
exist_edges = []
layers = []
exist_nodes = []
err = ErrorHandling()
for i in graph.inputs:
edge_name = i[0]
input_layer = cvt.make_input(i)
layers.append(input_layer)
exist_edges.append(i[0])
graph.channel_dims[edge_name] = graph.shape_dict[edge_name][1]
for id, node in enumerate(graph.nodes):
node_name = node.name
op_type = node.op_type
inputs = node.inputs
inputs_tensor = node.input_tensors
input_non_exist_flag = False
for inp in inputs:
if inp not in exist_edges and inp not in inputs_tensor:
input_non_exist_flag = True
break
if input_non_exist_flag:
continue
if op_type not in cvt._ONNX_NODE_REGISTRY:
err.unsupported_op(node)
continue
converter_fn = cvt._ONNX_NODE_REGISTRY[op_type]
layer = converter_fn(node, graph, err)
if type(layer) == tuple:
for l in layer:
layers.append(l)
else:
layers.append(layer)
outs = node.outputs
for out in outs:
exist_edges.append(out)
net = caffe_pb2.NetParameter()
for id, layer in enumerate(layers):
layers[id] = layer._to_proto()
net.layer.extend(layers)
with open(prototxt_save_path, 'w') as f:
print(net, file=f)
caffe.set_mode_cpu()
deploy = prototxt_save_path
net = caffe.Net(deploy,
caffe.TEST)
for id, node in enumerate(graph.nodes):
node_name = node.name
op_type = node.op_type
inputs = node.inputs
inputs_tensor = node.input_tensors
input_non_exist_flag = False
if op_type not in wlr._ONNX_NODE_REGISTRY:
err.unsupported_op(node)
continue
converter_fn = wlr._ONNX_NODE_REGISTRY[op_type]
converter_fn(net, node, graph, err)
net.save(caffe_model_save_path)
return net
def getGraph(onnx_path):
model = onnx.load(onnx_path)
model = shape_inference.infer_shapes(model)
model_graph = model.graph
graph = Graph.from_onnx(model_graph)
graph = graph.transformed(transformers)
graph.channel_dims = {}
return graph
if __name__ == "__main__":
onnx_path = "../models/onnx/version-RFB-320_simplified.onnx"
prototxt_path = "./RFB-320.prototxt"
caffemodel_path = "./RFB-320.caffemodel"
graph = getGraph(onnx_path)
convertToCaffe(graph, prototxt_path, caffemodel_path)
================================================
FILE: caffe/model/RFB-320/RFB-320.prototxt
================================================
layer {
name: "input"
type: "Input"
top: "input"
input_param {
shape {
dim: 1
dim: 3
dim: 240
dim: 320
}
}
}
layer {
name: "245"
type: "Convolution"
bottom: "input"
top: "245"
convolution_param {
num_output: 16
bias_term: true
group: 1
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 2
stride_w: 2
dilation: 1
}
}
layer {
name: "247"
type: "ReLU"
bottom: "245"
top: "247"
}
layer {
name: "248"
type: "Convolution"
bottom: "247"
top: "248"
convolution_param {
num_output: 16
bias_term: true
group: 16
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "250"
type: "ReLU"
bottom: "248"
top: "250"
}
layer {
name: "251"
type: "Convolution"
bottom: "250"
top: "251"
convolution_param {
num_output: 32
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "253"
type: "ReLU"
bottom: "251"
top: "253"
}
layer {
name: "254"
type: "Convolution"
bottom: "253"
top: "254"
convolution_param {
num_output: 32
bias_term: true
group: 32
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 2
stride_w: 2
dilation: 1
}
}
layer {
name: "256"
type: "ReLU"
bottom: "254"
top: "256"
}
layer {
name: "257"
type: "Convolution"
bottom: "256"
top: "257"
convolution_param {
num_output: 32
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "259"
type: "ReLU"
bottom: "257"
top: "259"
}
layer {
name: "260"
type: "Convolution"
bottom: "259"
top: "260"
convolution_param {
num_output: 32
bias_term: true
group: 32
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "262"
type: "ReLU"
bottom: "260"
top: "262"
}
layer {
name: "263"
type: "Convolution"
bottom: "262"
top: "263"
convolution_param {
num_output: 32
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "265"
type: "ReLU"
bottom: "263"
top: "265"
}
layer {
name: "266"
type: "Convolution"
bottom: "265"
top: "266"
convolution_param {
num_output: 32
bias_term: true
group: 32
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 2
stride_w: 2
dilation: 1
}
}
layer {
name: "268"
type: "ReLU"
bottom: "266"
top: "268"
}
layer {
name: "269"
type: "Convolution"
bottom: "268"
top: "269"
convolution_param {
num_output: 64
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "271"
type: "ReLU"
bottom: "269"
top: "271"
}
layer {
name: "272"
type: "Convolution"
bottom: "271"
top: "272"
convolution_param {
num_output: 64
bias_term: true
group: 64
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "274"
type: "ReLU"
bottom: "272"
top: "274"
}
layer {
name: "275"
type: "Convolution"
bottom: "274"
top: "275"
convolution_param {
num_output: 64
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "277"
type: "ReLU"
bottom: "275"
top: "277"
}
layer {
name: "278"
type: "Convolution"
bottom: "277"
top: "278"
convolution_param {
num_output: 64
bias_term: true
group: 64
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "280"
type: "ReLU"
bottom: "278"
top: "280"
}
layer {
name: "281"
type: "Convolution"
bottom: "280"
top: "281"
convolution_param {
num_output: 64
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "283"
type: "ReLU"
bottom: "281"
top: "283"
}
layer {
name: "284"
type: "Convolution"
bottom: "283"
top: "284"
convolution_param {
num_output: 8
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "286"
type: "Convolution"
bottom: "284"
top: "286"
convolution_param {
num_output: 16
bias_term: true
group: 1
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "288"
type: "ReLU"
bottom: "286"
top: "288"
}
layer {
name: "289"
type: "Convolution"
bottom: "288"
top: "289"
convolution_param {
num_output: 16
bias_term: true
group: 1
pad_h: 2
pad_w: 2
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 2
}
}
layer {
name: "291"
type: "Convolution"
bottom: "283"
top: "291"
convolution_param {
num_output: 8
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "293"
type: "Convolution"
bottom: "291"
top: "293"
convolution_param {
num_output: 16
bias_term: true
group: 1
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "295"
type: "ReLU"
bottom: "293"
top: "295"
}
layer {
name: "296"
type: "Convolution"
bottom: "295"
top: "296"
convolution_param {
num_output: 16
bias_term: true
group: 1
pad_h: 3
pad_w: 3
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 3
}
}
layer {
name: "298"
type: "Convolution"
bottom: "283"
top: "298"
convolution_param {
num_output: 8
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "300"
type: "Convolution"
bottom: "298"
top: "300"
convolution_param {
num_output: 12
bias_term: true
group: 1
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "302"
type: "ReLU"
bottom: "300"
top: "302"
}
layer {
name: "303"
type: "Convolution"
bottom: "302"
top: "303"
convolution_param {
num_output: 16
bias_term: true
group: 1
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "305"
type: "ReLU"
bottom: "303"
top: "305"
}
layer {
name: "306"
type: "Convolution"
bottom: "305"
top: "306"
convolution_param {
num_output: 16
bias_term: true
group: 1
pad_h: 5
pad_w: 5
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 5
}
}
layer {
name: "308"
type: "Concat"
bottom: "289"
bottom: "296"
bottom: "306"
top: "308"
concat_param {
axis: 1
}
}
layer {
name: "309"
type: "Convolution"
bottom: "308"
top: "309"
convolution_param {
num_output: 64
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "311"
type: "Convolution"
bottom: "283"
top: "311"
convolution_param {
num_output: 64
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "313"
type: "Eltwise"
bottom: "309"
bottom: "311"
top: "313"
eltwise_param {
operation: SUM
}
}
layer {
name: "314"
type: "ReLU"
bottom: "313"
top: "314"
}
layer {
name: "315"
type: "Convolution"
bottom: "314"
top: "315"
convolution_param {
num_output: 64
bias_term: true
group: 64
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "316"
type: "ReLU"
bottom: "315"
top: "316"
}
layer {
name: "317"
type: "Convolution"
bottom: "316"
top: "317"
convolution_param {
num_output: 6
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "318"
type: "Permute"
bottom: "317"
top: "318"
permute_param {
order: 0
order: 2
order: 3
order: 1
}
}
layer {
name: "328"
type: "Reshape"
bottom: "318"
top: "328"
reshape_param {
shape {
dim: 1
dim: -1
dim: 2
}
}
}
layer {
name: "329"
type: "Convolution"
bottom: "314"
top: "329"
convolution_param {
num_output: 64
bias_term: true
group: 64
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "330"
type: "ReLU"
bottom: "329"
top: "330"
}
layer {
name: "331"
type: "Convolution"
bottom: "330"
top: "331"
convolution_param {
num_output: 12
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "332"
type: "Permute"
bottom: "331"
top: "332"
permute_param {
order: 0
order: 2
order: 3
order: 1
}
}
layer {
name: "342"
type: "Reshape"
bottom: "332"
top: "342"
reshape_param {
shape {
dim: 1
dim: -1
dim: 4
}
}
}
layer {
name: "343"
type: "Convolution"
bottom: "314"
top: "343"
convolution_param {
num_output: 64
bias_term: true
group: 64
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 2
stride_w: 2
dilation: 1
}
}
layer {
name: "345"
type: "ReLU"
bottom: "343"
top: "345"
}
layer {
name: "346"
type: "Convolution"
bottom: "345"
top: "346"
convolution_param {
num_output: 128
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "348"
type: "ReLU"
bottom: "346"
top: "348"
}
layer {
name: "349"
type: "Convolution"
bottom: "348"
top: "349"
convolution_param {
num_output: 128
bias_term: true
group: 128
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "351"
type: "ReLU"
bottom: "349"
top: "351"
}
layer {
name: "352"
type: "Convolution"
bottom: "351"
top: "352"
convolution_param {
num_output: 128
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "354"
type: "ReLU"
bottom: "352"
top: "354"
}
layer {
name: "355"
type: "Convolution"
bottom: "354"
top: "355"
convolution_param {
num_output: 128
bias_term: true
group: 128
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "357"
type: "ReLU"
bottom: "355"
top: "357"
}
layer {
name: "358"
type: "Convolution"
bottom: "357"
top: "358"
convolution_param {
num_output: 128
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "360"
type: "ReLU"
bottom: "358"
top: "360"
}
layer {
name: "361"
type: "Convolution"
bottom: "360"
top: "361"
convolution_param {
num_output: 128
bias_term: true
group: 128
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "362"
type: "ReLU"
bottom: "361"
top: "362"
}
layer {
name: "363"
type: "Convolution"
bottom: "362"
top: "363"
convolution_param {
num_output: 4
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "364"
type: "Permute"
bottom: "363"
top: "364"
permute_param {
order: 0
order: 2
order: 3
order: 1
}
}
layer {
name: "374"
type: "Reshape"
bottom: "364"
top: "374"
reshape_param {
shape {
dim: 1
dim: -1
dim: 2
}
}
}
layer {
name: "375"
type: "Convolution"
bottom: "360"
top: "375"
convolution_param {
num_output: 128
bias_term: true
group: 128
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "376"
type: "ReLU"
bottom: "375"
top: "376"
}
layer {
name: "377"
type: "Convolution"
bottom: "376"
top: "377"
convolution_param {
num_output: 8
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "378"
type: "Permute"
bottom: "377"
top: "378"
permute_param {
order: 0
order: 2
order: 3
order: 1
}
}
layer {
name: "388"
type: "Reshape"
bottom: "378"
top: "388"
reshape_param {
shape {
dim: 1
dim: -1
dim: 4
}
}
}
layer {
name: "389"
type: "Convolution"
bottom: "360"
top: "389"
convolution_param {
num_output: 128
bias_term: true
group: 128
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 2
stride_w: 2
dilation: 1
}
}
layer {
name: "391"
type: "ReLU"
bottom: "389"
top: "391"
}
layer {
name: "392"
type: "Convolution"
bottom: "391"
top: "392"
convolution_param {
num_output: 256
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "394"
type: "ReLU"
bottom: "392"
top: "394"
}
layer {
name: "395"
type: "Convolution"
bottom: "394"
top: "395"
convolution_param {
num_output: 256
bias_term: true
group: 256
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "397"
type: "ReLU"
bottom: "395"
top: "397"
}
layer {
name: "398"
type: "Convolution"
bottom: "397"
top: "398"
convolution_param {
num_output: 256
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "400"
type: "ReLU"
bottom: "398"
top: "400"
}
layer {
name: "401"
type: "Convolution"
bottom: "400"
top: "401"
convolution_param {
num_output: 256
bias_term: true
group: 256
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "402"
type: "ReLU"
bottom: "401"
top: "402"
}
layer {
name: "403"
type: "Convolution"
bottom: "402"
top: "403"
convolution_param {
num_output: 4
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "404"
type: "Permute"
bottom: "403"
top: "404"
permute_param {
order: 0
order: 2
order: 3
order: 1
}
}
layer {
name: "414"
type: "Reshape"
bottom: "404"
top: "414"
reshape_param {
shape {
dim: 1
dim: -1
dim: 2
}
}
}
layer {
name: "415"
type: "Convolution"
bottom: "400"
top: "415"
convolution_param {
num_output: 256
bias_term: true
group: 256
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "416"
type: "ReLU"
bottom: "415"
top: "416"
}
layer {
name: "417"
type: "Convolution"
bottom: "416"
top: "417"
convolution_param {
num_output: 8
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "418"
type: "Permute"
bottom: "417"
top: "418"
permute_param {
order: 0
order: 2
order: 3
order: 1
}
}
layer {
name: "428"
type: "Reshape"
bottom: "418"
top: "428"
reshape_param {
shape {
dim: 1
dim: -1
dim: 4
}
}
}
layer {
name: "429"
type: "Convolution"
bottom: "400"
top: "429"
convolution_param {
num_output: 64
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "430"
type: "ReLU"
bottom: "429"
top: "430"
}
layer {
name: "431"
type: "Convolution"
bottom: "430"
top: "431"
convolution_param {
num_output: 64
bias_term: true
group: 64
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 2
stride_w: 2
dilation: 1
}
}
layer {
name: "432"
type: "ReLU"
bottom: "431"
top: "432"
}
layer {
name: "433"
type: "Convolution"
bottom: "432"
top: "433"
convolution_param {
num_output: 256
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "434"
type: "ReLU"
bottom: "433"
top: "434"
}
layer {
name: "435"
type: "Convolution"
bottom: "434"
top: "435"
convolution_param {
num_output: 6
bias_term: true
group: 1
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "436"
type: "Permute"
bottom: "435"
top: "436"
permute_param {
order: 0
order: 2
order: 3
order: 1
}
}
layer {
name: "446"
type: "Reshape"
bottom: "436"
top: "446"
reshape_param {
shape {
dim: 1
dim: -1
dim: 2
}
}
}
layer {
name: "447"
type: "Convolution"
bottom: "434"
top: "447"
convolution_param {
num_output: 12
bias_term: true
group: 1
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "448"
type: "Permute"
bottom: "447"
top: "448"
permute_param {
order: 0
order: 2
order: 3
order: 1
}
}
layer {
name: "458"
type: "Reshape"
bottom: "448"
top: "458"
reshape_param {
shape {
dim: 1
dim: -1
dim: 4
}
}
}
layer {
name: "459"
type: "Concat"
bottom: "328"
bottom: "374"
bottom: "414"
bottom: "446"
top: "459"
concat_param {
axis: 1
}
}
layer {
name: "boxes"
type: "Concat"
bottom: "342"
bottom: "388"
bottom: "428"
bottom: "458"
top: "boxes"
concat_param {
axis: 1
}
}
layer {
name: "scores"
type: "Softmax"
bottom: "459"
top: "scores"
softmax_param {
axis: 2
}
}
================================================
FILE: caffe/model/Slim-320/slim-320.prototxt
================================================
layer {
name: "input"
type: "Input"
top: "input"
input_param {
shape {
dim: 1
dim: 3
dim: 240
dim: 320
}
}
}
layer {
name: "185"
type: "Convolution"
bottom: "input"
top: "185"
convolution_param {
num_output: 16
bias_term: true
group: 1
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 2
stride_w: 2
dilation: 1
}
}
layer {
name: "187"
type: "ReLU"
bottom: "185"
top: "187"
}
layer {
name: "188"
type: "Convolution"
bottom: "187"
top: "188"
convolution_param {
num_output: 16
bias_term: true
group: 16
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "190"
type: "ReLU"
bottom: "188"
top: "190"
}
layer {
name: "191"
type: "Convolution"
bottom: "190"
top: "191"
convolution_param {
num_output: 32
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "193"
type: "ReLU"
bottom: "191"
top: "193"
}
layer {
name: "194"
type: "Convolution"
bottom: "193"
top: "194"
convolution_param {
num_output: 32
bias_term: true
group: 32
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 2
stride_w: 2
dilation: 1
}
}
layer {
name: "196"
type: "ReLU"
bottom: "194"
top: "196"
}
layer {
name: "197"
type: "Convolution"
bottom: "196"
top: "197"
convolution_param {
num_output: 32
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "199"
type: "ReLU"
bottom: "197"
top: "199"
}
layer {
name: "200"
type: "Convolution"
bottom: "199"
top: "200"
convolution_param {
num_output: 32
bias_term: true
group: 32
pad_h: 1
pad_w: 1
kernel_h: 3
kernel_w: 3
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "202"
type: "ReLU"
bottom: "200"
top: "202"
}
layer {
name: "203"
type: "Convolution"
bottom: "202"
top: "203"
convolution_param {
num_output: 32
bias_term: true
group: 1
pad_h: 0
pad_w: 0
kernel_h: 1
kernel_w: 1
stride_h: 1
stride_w: 1
dilation: 1
}
}
layer {
name: "205"
type: "ReLU"
bottom: "203"
top: "205"
}
layer {
name: "206"
type: "Convolution"
bo
gitextract_rj4enlci/
├── .gitignore
├── .gitmodules
├── LICENSE
├── MNN/
│ ├── CMakeLists.txt
│ ├── README.md
│ ├── mnn/
│ │ └── include/
│ │ ├── AutoTime.hpp
│ │ ├── Backend.hpp
│ │ ├── ErrorCode.hpp
│ │ ├── HalideRuntime.h
│ │ ├── ImageProcess.hpp
│ │ ├── Interpreter.hpp
│ │ ├── MNNDefine.h
│ │ ├── MNNForwardType.h
│ │ ├── MNNSharedContext.h
│ │ ├── Matrix.h
│ │ ├── NonCopyable.hpp
│ │ ├── Rect.h
│ │ ├── Tensor.hpp
│ │ └── revertMNNModel.hpp
│ ├── model/
│ │ ├── version-RFB/
│ │ │ ├── RFB-320-quant-ADMM-32.mnn
│ │ │ ├── RFB-320-quant-KL-5792.mnn
│ │ │ └── RFB-320.mnn
│ │ └── version-slim/
│ │ ├── slim-320-quant-ADMM-50.mnn
│ │ └── slim-320.mnn
│ ├── python/
│ │ ├── README.md
│ │ └── ultraface_py_mnn.py
│ └── src/
│ ├── UltraFace.cpp
│ ├── UltraFace.hpp
│ └── main.cpp
├── README.md
├── README_CN.md
├── caffe/
│ ├── MyCaffe.py
│ ├── README.md
│ ├── convertCaffe.py
│ ├── model/
│ │ ├── RFB-320/
│ │ │ ├── RFB-320.caffemodel
│ │ │ └── RFB-320.prototxt
│ │ └── Slim-320/
│ │ ├── slim-320.caffemodel
│ │ └── slim-320.prototxt
│ ├── onnx2caffe/
│ │ ├── __init__.py
│ │ ├── _error_utils.py
│ │ ├── _graph.py
│ │ ├── _operators.py
│ │ ├── _transformers.py
│ │ └── _weightloader.py
│ ├── ultra_face_caffe_inference.py
│ └── ultra_face_opencvdnn_inference.py
├── cal_flops.py
├── check_gt_box.py
├── convert_to_onnx.py
├── data/
│ ├── retinaface_labels/
│ │ ├── test/
│ │ │ └── label.txt
│ │ ├── train/
│ │ │ └── label.txt
│ │ └── val/
│ │ └── label.txt
│ └── wider_face_2_voc_add_landmark.py
├── detect_imgs.py
├── detect_imgs_onnx.py
├── masked_face/
│ ├── README.md
│ ├── detect_imgs.py
│ ├── mafa2voc.py
│ ├── pretrained/
│ │ ├── RFB-1280-masked_face-v2.onnx
│ │ ├── RFB-320-masked_face-v2.pth
│ │ ├── RFB-640-masked_face-v2.onnx
│ │ └── RFB-640-masked_face-v2.pth
│ └── voc-model-labels.txt
├── models/
│ ├── onnx/
│ │ ├── version-RFB-320.onnx
│ │ ├── version-RFB-320_simplified.onnx
│ │ ├── version-RFB-320_without_postprocessing.onnx
│ │ ├── version-RFB-640.onnx
│ │ ├── version-slim-320.onnx
│ │ ├── version-slim-320_simplified.onnx
│ │ └── version-slim-320_without_postprocessing.onnx
│ ├── pretrained/
│ │ ├── version-RFB-320.pth
│ │ ├── version-RFB-640.pth
│ │ ├── version-slim-320.pth
│ │ └── version-slim-640.pth
│ ├── readme
│ └── voc-model-labels.txt
├── ncnn/
│ ├── .clang-format
│ ├── CMakeLists.txt
│ ├── README.md
│ ├── data/
│ │ ├── version-RFB/
│ │ │ └── RFB-320.param
│ │ └── version-slim/
│ │ └── slim_320.param
│ └── src/
│ ├── UltraFace.cpp
│ ├── UltraFace.hpp
│ └── main.cpp
├── opencv_dnn/
│ ├── cv_dnn_ultraface.cpp
│ └── cv_dnn_ultraface.h
├── paddle/
│ ├── train-version-RFB.sh
│ ├── train-version-slim.sh
│ ├── train.py
│ └── vision/
│ ├── __init__.py
│ ├── datasets/
│ │ ├── __init__.py
│ │ └── voc_dataset.py
│ ├── nn/
│ │ ├── __init__.py
│ │ ├── mb_tiny.py
│ │ ├── mb_tiny_RFB.py
│ │ └── multibox_loss.py
│ ├── ssd/
│ │ ├── __init__.py
│ │ ├── config/
│ │ │ ├── __init__.py
│ │ │ └── fd_config.py
│ │ ├── data_preprocessing.py
│ │ ├── mb_tiny_RFB_fd.py
│ │ ├── mb_tiny_fd.py
│ │ ├── predictor.py
│ │ └── ssd.py
│ ├── transforms/
│ │ ├── __init__.py
│ │ └── transforms.py
│ └── utils/
│ ├── __init__.py
│ ├── box_utils.py
│ ├── box_utils_numpy.py
│ └── misc.py
├── requirements.txt
├── run_video_face_detect.py
├── run_video_face_detect_onnx.py
├── tf/
│ ├── README.md
│ ├── backend/
│ │ ├── op.py
│ │ └── utils.py
│ ├── convert_tensorflow.py
│ ├── det_image.py
│ ├── export_models/
│ │ ├── RFB/
│ │ │ ├── saved_model.pb
│ │ │ └── variables/
│ │ │ ├── variables.data-00000-of-00001
│ │ │ └── variables.index
│ │ └── slim/
│ │ ├── saved_model.pb
│ │ └── variables/
│ │ ├── variables.data-00000-of-00001
│ │ └── variables.index
│ ├── mapping_tables/
│ │ ├── rfb_320.json
│ │ └── slim_320.json
│ └── model/
│ ├── rfb_320.py
│ └── slim_320.py
├── tflite/
│ ├── README.md
│ ├── TFLiteFaceDetector.py
│ ├── inference_test.py
│ ├── model/
│ │ ├── tflite_RFB_320_without_postprocessing.py
│ │ └── tflite_slim_320_without_postprocessing.py
│ └── pretrained/
│ ├── version-RFB-320_without_postprocessing.tflite
│ └── version-slim-320_without_postprocessing.tflite
├── train-version-RFB.sh
├── train-version-slim.sh
├── train.py
├── vision/
│ ├── __init__.py
│ ├── datasets/
│ │ ├── __init__.py
│ │ └── voc_dataset.py
│ ├── nn/
│ │ ├── __init__.py
│ │ ├── mb_tiny.py
│ │ ├── mb_tiny_RFB.py
│ │ └── multibox_loss.py
│ ├── ssd/
│ │ ├── __init__.py
│ │ ├── config/
│ │ │ ├── __init__.py
│ │ │ └── fd_config.py
│ │ ├── data_preprocessing.py
│ │ ├── mb_tiny_RFB_fd.py
│ │ ├── mb_tiny_fd.py
│ │ ├── predictor.py
│ │ └── ssd.py
│ ├── transforms/
│ │ ├── __init__.py
│ │ └── transforms.py
│ └── utils/
│ ├── __init__.py
│ ├── box_utils.py
│ ├── box_utils_numpy.py
│ └── misc.py
└── widerface_evaluate/
├── README.md
├── box_overlaps.pyx
├── evaluation.py
├── evaluation_on_widerface.py
├── ground_truth/
│ ├── wider_easy_val.mat
│ ├── wider_face_val.mat
│ ├── wider_hard_val.mat
│ └── wider_medium_val.mat
└── setup.py
SYMBOL INDEX (569 symbols across 73 files)
FILE: MNN/mnn/include/AutoTime.hpp
type MNN (line 16) | namespace MNN {
function AutoTime (line 19) | class MNN_PUBLIC AutoTime {
FILE: MNN/mnn/include/Backend.hpp
type MNN (line 21) | namespace MNN {
type Op (line 23) | struct Op
type GpuLibrary (line 24) | struct GpuLibrary
class Execution (line 25) | class Execution
class Backend (line 28) | class Backend : public NonCopyable {
type Info (line 31) | struct Info {
type Mode (line 38) | enum Mode {
type StorageType (line 49) | enum StorageType {
method Backend (line 78) | Backend(MNNForwardType type) : mType(type) {
method onMeasure (line 95) | virtual std::pair<float, bool> onMeasure(const std::vector<Tensor*>&...
method onResizeBegin (line 113) | virtual void onResizeBegin() {
method onResizeEnd (line 119) | virtual void onResizeEnd() {
method onWaitFinish (line 135) | virtual bool onWaitFinish() {
method onLoadLibrary (line 143) | virtual bool onLoadLibrary(const GpuLibrary* library) {
method onAllocateBuffer (line 168) | virtual bool onAllocateBuffer() {
method MNNForwardType (line 190) | inline MNNForwardType type() const {
class BackendCreator (line 199) | class BackendCreator {
method onValid (line 219) | virtual bool onValid(Backend::Info& info) const {
method BackendCreator (line 227) | BackendCreator() = default;
FILE: MNN/mnn/include/ErrorCode.hpp
type MNN (line 12) | namespace MNN {
type ErrorCode (line 13) | enum ErrorCode {
FILE: MNN/mnn/include/HalideRuntime.h
type halide_buffer_t (line 52) | struct halide_buffer_t
type halide_type_code_t (line 59) | typedef enum halide_type_code_t
type halide_type_t (line 82) | struct halide_type_t {
type halide_device_interface_impl_t (line 127) | struct halide_device_interface_impl_t
type halide_device_interface_t (line 143) | struct halide_device_interface_t {
type halide_dimension_t (line 167) | typedef struct halide_dimension_t {
type halide_buffer_flags (line 195) | typedef enum {halide_buffer_flag_host_dirty = 1,
type halide_buffer_t (line 203) | typedef struct halide_buffer_t {
function halide_type_t (line 242) | halide_type_t halide_type_of() {
FILE: MNN/mnn/include/ImageProcess.hpp
type MNN (line 16) | namespace MNN {
type CV (line 17) | namespace CV {
type ImageFormat (line 18) | enum ImageFormat {
type Filter (line 27) | enum Filter { NEAREST = 0, BILINEAR = 1, BICUBIC = 2 }
type Wrap (line 29) | enum Wrap { CLAMP_TO_EDGE = 0, ZERO = 1, REPEAT = 2 }
function ImageProcess (line 38) | class MNN_PUBLIC ImageProcess {
FILE: MNN/mnn/include/Interpreter.hpp
type MNN (line 19) | namespace MNN {
type ScheduleConfig (line 22) | struct ScheduleConfig {
type Path (line 31) | struct Path {
type Mode (line 35) | enum Mode {
class Session (line 66) | class Session
type Content (line 67) | struct Content
class Tensor (line 68) | class Tensor
class Backend (line 69) | class Backend
function OperatorInfo (line 71) | class MNN_PUBLIC OperatorInfo {
function Interpreter (line 94) | class MNN_PUBLIC Interpreter {
FILE: MNN/mnn/include/MNNForwardType.h
type MNNForwardType (line 14) | typedef enum {
function namespace (line 46) | namespace MNN {
FILE: MNN/mnn/include/MNNSharedContext.h
function VK_DEFINE_HANDLE (line 19) | VK_DEFINE_HANDLE(VkInstance)
FILE: MNN/mnn/include/Matrix.h
function namespace (line 31) | namespace MNN {
FILE: MNN/mnn/include/NonCopyable.hpp
type MNN (line 12) | namespace MNN {
class NonCopyable (line 14) | class NonCopyable {
method NonCopyable (line 16) | NonCopyable() = default;
method NonCopyable (line 17) | NonCopyable(const NonCopyable&) = delete;
method NonCopyable (line 18) | NonCopyable(const NonCopyable&&) = delete;
method NonCopyable (line 19) | NonCopyable& operator=(const NonCopyable&) = delete;
method NonCopyable (line 20) | NonCopyable& operator=(const NonCopyable&&) = delete;
FILE: MNN/mnn/include/Rect.h
type Point (line 37) | struct Point {
function Rect (line 54) | struct MNN_PUBLIC Rect {
FILE: MNN/mnn/include/Tensor.hpp
type MNN (line 16) | namespace MNN {
function Tensor (line 25) | class MNN_PUBLIC Tensor {
function elementSize (line 215) | inline int elementSize() const {
function height (line 227) | inline int height() const {
function channel (line 233) | inline int channel() const {
function batch (line 239) | inline int batch() const {
function stride (line 244) | inline int stride(int index) const {
function length (line 247) | inline int length(int index) const {
function setStride (line 250) | inline void setStride(int index, int stride) {
function setLength (line 253) | inline void setLength(int index, int length) {
type InsideDescribe (line 265) | struct InsideDescribe
FILE: MNN/mnn/include/revertMNNModel.hpp
class Revert (line 14) | class Revert {
FILE: MNN/python/ultraface_py_mnn.py
function define_img_size (line 42) | def define_img_size(image_size):
function generate_priors (line 55) | def generate_priors(feature_map_list, shrinkage_list, image_size, min_bo...
function predict (line 81) | def predict(width, height, confidences, boxes, prob_threshold, iou_thres...
function inference (line 110) | def inference():
FILE: MNN/src/UltraFace.hpp
type FaceInfo (line 25) | struct FaceInfo {
class UltraFace (line 34) | class UltraFace {
FILE: MNN/src/main.cpp
function main (line 10) | int main(int argc, char **argv) {
FILE: caffe/MyCaffe.py
function param_name_dict (line 7) | def param_name_dict():
function assign_proto (line 21) | def assign_proto(proto, name, val):
class Function (line 46) | class Function(object):
method __init__ (line 50) | def __init__(self, type_name, layer_name, inputs,outputs, **params):
method _get_name (line 65) | def _get_name(self, names, autonames):
method _get_top_name (line 73) | def _get_top_name(self, top, names, autonames):
method _to_proto (line 79) | def _to_proto(self):
class Layers (line 110) | class Layers(object):
method __getattr__ (line 115) | def __getattr__(self, name):
FILE: caffe/convertCaffe.py
function convertToCaffe (line 25) | def convertToCaffe(graph, prototxt_save_path, caffe_model_save_path):
function getGraph (line 94) | def getGraph(onnx_path):
FILE: caffe/onnx2caffe/_error_utils.py
class ErrorHandling (line 8) | class ErrorHandling(object):
method __init__ (line 13) | def __init__(self,
method unsupported_op (line 24) | def unsupported_op(self,
method unsupported_op_configuration (line 40) | def unsupported_op_configuration(self,
method missing_initializer (line 49) | def missing_initializer(self,
FILE: caffe/onnx2caffe/_graph.py
class Transformer (line 12) | class Transformer(Protocol):
method __call__ (line 13) | def __call__(self, graph): # type: (Graph) -> Graph
function _input_from_onnx_input (line 20) | def _input_from_onnx_input(input): # type: (ValueInfoProto) -> EdgeInfo
function _convertAttributeProto (line 27) | def _convertAttributeProto(onnx_arg): # type: (AttributeProto) -> Attri...
class Attributes (line 51) | class Attributes(Dict[Text, Any]):
method from_onnx (line 53) | def from_onnx(args): # type: (Iterable[AttributeProto]) -> Attributes
class Node (line 60) | class Node(object):
method __init__ (line 61) | def __init__(self,
method add_parent (line 79) | def add_parent(self, parent_node): # type: (Node) -> None
method add_child (line 85) | def add_child(self, child_node): # type: (Node) -> None
method get_only_parent (line 91) | def get_only_parent(self): # type: () -> Node
method from_onnx (line 98) | def from_onnx(node): # type: (NodeProto) -> Node
class Graph (line 108) | class Graph(object):
method __init__ (line 109) | def __init__(self,
method transformed (line 138) | def transformed(self, transformers): # type: (Iterable[Transformer]) ...
method has_edge_name (line 144) | def has_edge_name(self, name): # type: (Text) -> bool
method get_unique_edge_name (line 159) | def get_unique_edge_name(self, name): # type: (Text) -> Text
method from_onnx (line 168) | def from_onnx(graph): # type: (GraphProto) -> Graph
FILE: caffe/onnx2caffe/_operators.py
function _compare (line 12) | def _compare(a, b, encoding="utf8"): # type: (Text, Text, Text) -> bool
function make_input (line 20) | def make_input(input):
function _convert_conv (line 30) | def _convert_conv(node, graph, err):
function _convert_relu (line 66) | def _convert_relu(node, graph, err):
function _convert_sigmoid (line 84) | def _convert_sigmoid(node, graph, err):
function _convert_BatchNorm (line 102) | def _convert_BatchNorm(node, graph, err):
function _convert_Add (line 126) | def _convert_Add(node, graph, err):
function _convert_Mul (line 153) | def _convert_Mul(node, graph, err):
function _convert_Reshape (line 179) | def _convert_Reshape(node, graph, err):
function _convert_Flatten (line 205) | def _convert_Flatten(node, graph, err):
function _convert_Permute (line 219) | def _convert_Permute(node, graph, err):
function _convert_Softmax (line 234) | def _convert_Softmax(node, graph, err):
function _convert_pool (line 244) | def _convert_pool(node, graph, err):
function _convert_dropout (line 270) | def _convert_dropout(node, graph, err):
function _convert_gemm (line 280) | def _convert_gemm(node, graph, err):
function _convert_upsample (line 314) | def _convert_upsample(node, graph, err):
function _convert_concat (line 354) | def _convert_concat(node, graph, err):
function _convert_conv_transpose (line 372) | def _convert_conv_transpose(node, graph, err):
FILE: caffe/onnx2caffe/_transformers.py
class NodesFuser (line 14) | class NodesFuser(object):
method __init__ (line 18) | def __init__(self,
method __call__ (line 25) | def __call__(self, graph): # type: (Graph) -> Graph
method is_eligible (line 78) | def is_eligible(self, graph, nodes): # type: (Graph, Sequence[Node]) ...
method merge (line 82) | def merge(self, graph, nodes): # type: (Graph, Sequence[Node]) -> Seq...
class ConvAddFuser (line 88) | class ConvAddFuser(NodesFuser):
method __init__ (line 92) | def __init__(self): # type: () -> None
method is_eligible (line 95) | def is_eligible(self, graph, nodes): # type: (Graph, Sequence[Node]) ...
method merge (line 122) | def merge(self, graph, nodes): # type: (Graph, Sequence[Node]) -> Seq...
class BNBroadcastedMulFuser (line 143) | class BNBroadcastedMulFuser(NodesFuser):
method __init__ (line 147) | def __init__(self): # type: () -> None
method is_eligible (line 150) | def is_eligible(self, graph, nodes): # type: (Graph, Sequence[Node]) ...
method merge (line 172) | def merge(self, graph, nodes): # type: (Graph, Sequence[Node]) -> Seq...
class BNBroadcastedAddFuser (line 185) | class BNBroadcastedAddFuser(NodesFuser):
method __init__ (line 189) | def __init__(self): # type: () -> None
method is_eligible (line 192) | def is_eligible(self, graph, nodes): # type: (Graph, Sequence[Node]) ...
method merge (line 214) | def merge(self, graph, nodes): # type: (Graph, Sequence[Node]) -> Seq...
class DropoutRemover (line 225) | class DropoutRemover(NodesFuser):
method __init__ (line 229) | def __init__(self): # type: () -> None
method is_eligible (line 232) | def is_eligible(self, graph, nodes): # type: (Graph, Sequence[Node]) ...
method merge (line 236) | def merge(self, graph, nodes): # type: (Graph, Sequence[Node]) -> Seq...
class ReshapeInitTensorFuser (line 244) | class ReshapeInitTensorFuser(object):
method __call__ (line 250) | def __call__(self, graph): # type: (Graph) -> Graph
class OutputRenamer (line 300) | class OutputRenamer(object):
method __init__ (line 304) | def __init__(self,
method __call__ (line 310) | def __call__(self, graph): # type: (Graph) -> Graph
class PixelShuffleFuser (line 331) | class PixelShuffleFuser(NodesFuser):
method __init__ (line 336) | def __init__(self): # type: () -> None
method is_eligible (line 340) | def is_eligible(self, graph, nodes): # type: (Graph, Sequence[Node]) ...
method get_unique_edge_name (line 382) | def get_unique_edge_name(self, graph, name): # type: (Graph, Text) ->...
method merge (line 386) | def merge(self, graph, nodes): # type: (Graph, Sequence[Node]) -> Seq...
class AddModelInputsOutputs (line 450) | class AddModelInputsOutputs(object):
method __call__ (line 454) | def __call__(self, graph): # type: (Graph) -> Graph
class ConstantsToInitializers (line 476) | class ConstantsToInitializers(object):
method __call__ (line 480) | def __call__(self, graph): # type: (Graph) -> Graph
class ImageScalerRemover (line 494) | class ImageScalerRemover(object):
method __call__ (line 499) | def __call__(self, graph): # type: (Graph) -> Graph
FILE: caffe/onnx2caffe/_weightloader.py
function _convert_conv (line 10) | def _convert_conv(net, node, graph, err):
function _convert_relu (line 34) | def _convert_relu(net, node, graph, err):
function _convert_sigmoid (line 38) | def _convert_sigmoid(net, node, graph, err):
function _convert_BatchNorm (line 42) | def _convert_BatchNorm(net, node, graph, err):
function _convert_Add (line 58) | def _convert_Add(net, node, graph, err):
function _convert_Mul (line 62) | def _convert_Mul(net, node, graph, err):
function _convert_Reshape (line 66) | def _convert_Reshape(net, node, graph, err):
function _convert_Flatten (line 70) | def _convert_Flatten(net, node, graph, err):
function _convert_pool (line 74) | def _convert_pool(net, node, graph, err):
function _convert_dropout (line 78) | def _convert_dropout(net, node, graph, err):
function _convert_Permute (line 82) | def _convert_Permute(net, node, graph, err):
function _convert_Softmax (line 86) | def _convert_Softmax(net, node, graph, err):
function _convert_gemm (line 90) | def _convert_gemm(net, node, graph, err):
function _convert_upsample (line 112) | def _convert_upsample(net, node, graph, err):
function _convert_concat (line 122) | def _convert_concat(net, node, graph, err):
function _convert_conv_transpose (line 126) | def _convert_conv_transpose(net, node, graph, err):
FILE: caffe/ultra_face_caffe_inference.py
function define_img_size (line 34) | def define_img_size(image_size):
function generate_priors (line 47) | def generate_priors(feature_map_list, shrinkage_list, image_size, min_bo...
function hard_nms (line 70) | def hard_nms(box_scores, iou_threshold, top_k=-1, candidate_size=200):
function area_of (line 92) | def area_of(left_top, right_bottom):
function iou_of (line 97) | def iou_of(boxes0, boxes1, eps=1e-5):
function predict (line 107) | def predict(width, height, confidences, boxes, prob_threshold, iou_thres...
function convert_locations_to_boxes (line 136) | def convert_locations_to_boxes(locations, priors, center_variance,
function center_form_to_corner_form (line 146) | def center_form_to_corner_form(locations):
function inference (line 151) | def inference():
FILE: caffe/ultra_face_opencvdnn_inference.py
function define_img_size (line 30) | def define_img_size(image_size):
function generate_priors (line 43) | def generate_priors(feature_map_list, shrinkage_list, image_size, min_bo...
function hard_nms (line 66) | def hard_nms(box_scores, iou_threshold, top_k=-1, candidate_size=200):
function area_of (line 88) | def area_of(left_top, right_bottom):
function iou_of (line 93) | def iou_of(boxes0, boxes1, eps=1e-5):
function predict (line 103) | def predict(width, height, confidences, boxes, prob_threshold, iou_thres...
function convert_locations_to_boxes (line 132) | def convert_locations_to_boxes(locations, priors, center_variance,
function center_form_to_corner_form (line 142) | def center_form_to_corner_form(locations):
function inference (line 147) | def inference():
FILE: data/wider_face_2_voc_add_landmark.py
function convertimgset (line 22) | def convertimgset(img_set="train"):
function method_name (line 129) | def method_name(bboxes, filename, saveimg, vocannotationdir, lms, img_set):
function generatetxt (line 273) | def generatetxt(img_set="train"):
function generatevocsets (line 290) | def generatevocsets(img_set="train"):
function convertdataset (line 311) | def convertdataset():
FILE: detect_imgs_onnx.py
function predict (line 17) | def predict(width, height, confidences, boxes, prob_threshold, iou_thres...
FILE: masked_face/mafa2voc.py
function expand_box (line 27) | def expand_box(square_box, scale_ratio=1.2):
function fit_by_shifting (line 38) | def fit_by_shifting(box, rows, cols):
function get_minimal_box (line 64) | def get_minimal_box(points):
function points_in_box (line 76) | def points_in_box(points, box):
function box_in_image (line 85) | def box_in_image(box, image):
function box_is_valid (line 92) | def box_is_valid(image, points, box):
function fit_by_shrinking (line 108) | def fit_by_shrinking(box, rows, cols):
function fit_box (line 152) | def fit_box(box, image: object, points: object):
function load_labels (line 185) | def load_labels(label_file, is_train):
function parse_labels (line 209) | def parse_labels(raw_labels, is_train=True):
function draw_face (line 296) | def draw_face(image, labels, color=(0, 255, 0)):
function draw_mask (line 302) | def draw_mask(image, labels, color=(0, 0, 255)):
function export_face (line 312) | def export_face(image, labels, export_file, occ_types=[1, 2, 3], min_siz...
function write_voc_style_ann (line 359) | def write_voc_style_ann(labels, img_file_name, num_human_occ):
FILE: ncnn/src/UltraFace.hpp
type FaceInfo (line 25) | struct FaceInfo {
class UltraFace (line 35) | class UltraFace {
FILE: ncnn/src/main.cpp
function main (line 13) | int main(int argc, char **argv) {
FILE: opencv_dnn/cv_dnn_ultraface.h
type FaceInfo (line 16) | typedef struct FaceInfo {
function class (line 26) | class UltraFace {
FILE: paddle/train.py
function lr_poly (line 122) | def lr_poly(base_lr, iter):
function adjust_learning_rate (line 135) | def adjust_learning_rate(optimizer, i_iter):
function train (line 141) | def train(loader, net, criterion, optimizer, debug_steps=100, epoch=-1):
function test (line 177) | def test(loader, net, criterion):
FILE: paddle/vision/datasets/voc_dataset.py
class VOCDataset (line 10) | class VOCDataset(Dataset):
method __init__ (line 11) | def __init__(self, root, transform=None, target_transform=None, is_tes...
method __getitem__ (line 52) | def __getitem__(self, index):
method get_image (line 65) | def get_image(self, index):
method get_annotation (line 72) | def get_annotation(self, index):
method __len__ (line 76) | def __len__(self):
method _read_image_ids (line 80) | def _read_image_ids(image_sets_file):
method _get_annotation (line 87) | def _get_annotation(self, image_id):
method _read_image (line 114) | def _read_image(self, image_id):
FILE: paddle/vision/nn/mb_tiny.py
class Mb_Tiny (line 5) | class Mb_Tiny(nn.Layer):
method __init__ (line 7) | def __init__(self, num_classes=2):
method forward (line 46) | def forward(self, x):
FILE: paddle/vision/nn/mb_tiny_RFB.py
class BasicConv (line 6) | class BasicConv(nn.Layer):
method __init__ (line 8) | def __init__(self, in_planes, out_planes, kernel_size, stride=1, paddi...
method forward (line 20) | def forward(self, x):
class BasicRFB (line 29) | class BasicRFB(nn.Layer):
method __init__ (line 31) | def __init__(self, in_planes, out_planes, stride=1, scale=0.1, map_red...
method forward (line 58) | def forward(self, x):
class Mb_Tiny_RFB (line 72) | class Mb_Tiny_RFB(nn.Layer):
method __init__ (line 74) | def __init__(self, num_classes=2):
method forward (line 113) | def forward(self, x):
FILE: paddle/vision/nn/multibox_loss.py
class MultiboxLoss (line 9) | class MultiboxLoss(nn.Layer):
method __init__ (line 10) | def __init__(self, priors, neg_pos_ratio, center_variance, size_varian...
method forward (line 22) | def forward(self, confidence, predicted_locations, labels, gt_locations):
FILE: paddle/vision/ssd/config/fd_config.py
function define_img_size (line 18) | def define_img_size(size):
FILE: paddle/vision/ssd/data_preprocessing.py
class TrainAugmentation (line 4) | class TrainAugmentation:
method __init__ (line 5) | def __init__(self, size, mean=0, std=1.0):
method __call__ (line 25) | def __call__(self, img, boxes, labels):
class TestTransform (line 36) | class TestTransform:
method __init__ (line 37) | def __init__(self, size, mean=0.0, std=1.0):
method __call__ (line 46) | def __call__(self, image, boxes, labels):
class PredictionTransform (line 50) | class PredictionTransform:
method __init__ (line 51) | def __init__(self, size, mean=0.0, std=1.0):
method __call__ (line 59) | def __call__(self, image):
FILE: paddle/vision/ssd/mb_tiny_RFB_fd.py
function SeperableConv2d (line 9) | def SeperableConv2d(in_channels, out_channels, kernel_size=1, stride=1, ...
function create_Mb_Tiny_RFB_fd (line 20) | def create_Mb_Tiny_RFB_fd(num_classes, is_test=False, device="cuda"):
function create_Mb_Tiny_RFB_fd_predictor (line 56) | def create_Mb_Tiny_RFB_fd_predictor(net, candidate_size=200, nms_method=...
FILE: paddle/vision/ssd/mb_tiny_fd.py
function SeperableConv2d (line 9) | def SeperableConv2d(in_channels, out_channels, kernel_size=1, stride=1, ...
function create_mb_tiny_fd (line 20) | def create_mb_tiny_fd(num_classes, is_test=False, device="cuda"):
function create_mb_tiny_fd_predictor (line 56) | def create_mb_tiny_fd_predictor(net, candidate_size=200, nms_method=None...
FILE: paddle/vision/ssd/predictor.py
class Predictor (line 8) | class Predictor:
method __init__ (line 9) | def __init__(self, net, size, mean=0.0, std=1.0, nms_method=None,
method predict (line 29) | def predict(self, image, top_k=-1, prob_threshold=None):
FILE: paddle/vision/ssd/ssd.py
class SSD (line 14) | class SSD(nn.Layer):
method __init__ (line 15) | def __init__(self, num_classes: int, base_net: nn.LayerList, source_la...
method forward (line 42) | def forward(self, x: paddle.Tensor) -> Tuple[paddle.Tensor, paddle.Ten...
method compute_header (line 103) | def compute_header(self, i, x):
method init_from_base_net (line 114) | def init_from_base_net(self, model):
method init_from_pretrained_ssd (line 121) | def init_from_pretrained_ssd(self, model):
method init (line 130) | def init(self):
method load (line 137) | def load(self, model):
method save (line 140) | def save(self, model_path):
class MatchPrior (line 144) | class MatchPrior(object):
method __init__ (line 145) | def __init__(self, center_form_priors, center_variance, size_variance,...
method __call__ (line 152) | def __call__(self, gt_boxes, gt_labels):
function _xavier_init_ (line 160) | def _xavier_init_(m: nn.Layer):
FILE: paddle/vision/transforms/transforms.py
function intersect (line 13) | def intersect(box_a, box_b):
function jaccard_numpy (line 20) | def jaccard_numpy(box_a, box_b):
function object_converage_numpy (line 40) | def object_converage_numpy(box_a, box_b):
class Compose (line 59) | class Compose(object):
method __init__ (line 70) | def __init__(self, transforms):
method __call__ (line 73) | def __call__(self, img, boxes=None, labels=None):
class Lambda (line 79) | class Lambda(object):
method __init__ (line 82) | def __init__(self, lambd):
method __call__ (line 86) | def __call__(self, img, boxes=None, labels=None):
class ConvertFromInts (line 90) | class ConvertFromInts(object):
method __call__ (line 91) | def __call__(self, image, boxes=None, labels=None):
class SubtractMeans (line 95) | class SubtractMeans(object):
method __init__ (line 96) | def __init__(self, mean):
method __call__ (line 99) | def __call__(self, image, boxes=None, labels=None):
class imgprocess (line 105) | class imgprocess(object):
method __init__ (line 106) | def __init__(self, std):
method __call__ (line 109) | def __call__(self, image, boxes=None, labels=None):
class ToAbsoluteCoords (line 115) | class ToAbsoluteCoords(object):
method __call__ (line 116) | def __call__(self, image, boxes=None, labels=None):
class ToPercentCoords (line 126) | class ToPercentCoords(object):
method __call__ (line 127) | def __call__(self, image, boxes=None, labels=None):
class Resize (line 137) | class Resize(object):
method __init__ (line 138) | def __init__(self, size=(300, 300)):
method __call__ (line 141) | def __call__(self, image, boxes=None, labels=None):
class RandomSaturation (line 147) | class RandomSaturation(object):
method __init__ (line 148) | def __init__(self, lower=0.5, upper=1.5):
method __call__ (line 154) | def __call__(self, image, boxes=None, labels=None):
class RandomHue (line 161) | class RandomHue(object):
method __init__ (line 162) | def __init__(self, delta=18.0):
method __call__ (line 166) | def __call__(self, image, boxes=None, labels=None):
class RandomLightingNoise (line 174) | class RandomLightingNoise(object):
method __init__ (line 175) | def __init__(self):
method __call__ (line 180) | def __call__(self, image, boxes=None, labels=None):
class ConvertColor (line 188) | class ConvertColor(object):
method __init__ (line 189) | def __init__(self, current, transform):
method __call__ (line 193) | def __call__(self, image, boxes=None, labels=None):
class RandomContrast (line 209) | class RandomContrast(object):
method __init__ (line 210) | def __init__(self, lower=0.5, upper=1.5):
method __call__ (line 217) | def __call__(self, image, boxes=None, labels=None):
class RandomBrightness (line 224) | class RandomBrightness(object):
method __init__ (line 225) | def __init__(self, delta=32):
method __call__ (line 230) | def __call__(self, image, boxes=None, labels=None):
class ToCV2Image (line 237) | class ToCV2Image(object):
method __call__ (line 238) | def __call__(self, tensor, boxes=None, labels=None):
class ToTensor (line 242) | class ToTensor(object):
method __call__ (line 243) | def __call__(self, cvimage, boxes=None, labels=None):
class RandomSampleCrop (line 247) | class RandomSampleCrop(object):
method __init__ (line 261) | def __init__(self):
method __call__ (line 274) | def __call__(self, image, boxes=None, labels=None):
class RandomSampleCrop_v2 (line 352) | class RandomSampleCrop_v2(object):
method __init__ (line 366) | def __init__(self):
method __call__ (line 379) | def __call__(self, image, boxes=None, labels=None):
class Expand (line 456) | class Expand(object):
method __init__ (line 457) | def __init__(self, mean):
method __call__ (line 460) | def __call__(self, image, boxes, labels):
class RandomMirror (line 484) | class RandomMirror(object):
method __call__ (line 485) | def __call__(self, image, boxes, classes):
class SwapChannels (line 494) | class SwapChannels(object):
method __init__ (line 502) | def __init__(self, swaps):
method __call__ (line 505) | def __call__(self, image):
class PhotometricDistort (line 520) | class PhotometricDistort(object):
method __init__ (line 521) | def __init__(self):
method __call__ (line 533) | def __call__(self, image, boxes, labels):
FILE: paddle/vision/utils/box_utils.py
function generate_priors (line 6) | def generate_priors(feature_map_list, shrinkage_list, image_size, min_bo...
function convert_locations_to_boxes (line 27) | def convert_locations_to_boxes(locations, priors, center_variance, size_...
function convert_boxes_to_locations (line 52) | def convert_boxes_to_locations(center_form_boxes, center_form_priors, ce...
function area_of (line 62) | def area_of(left_top, right_bottom) -> paddle.Tensor:
function iou_of (line 76) | def iou_of(boxes0, boxes1, eps=1e-5):
function assign_priors (line 102) | def assign_priors(gt_boxes, gt_labels, corner_form_priors,
function hard_negative_mining (line 134) | def hard_negative_mining(loss, labels, neg_pos_ratio):
function center_form_to_corner_form (line 158) | def center_form_to_corner_form(locations):
function corner_form_to_center_form (line 163) | def corner_form_to_center_form(boxes):
function hard_nms (line 168) | def hard_nms(box_scores, iou_threshold, top_k=-1, candidate_size=200):
function nms (line 201) | def nms(box_scores, nms_method=None, score_threshold=None, iou_threshold...
function soft_nms (line 209) | def soft_nms(box_scores, score_threshold, sigma=0.5, top_k=-1):
FILE: paddle/vision/utils/box_utils_numpy.py
function convert_locations_to_boxes (line 4) | def convert_locations_to_boxes(locations, priors, center_variance, size_...
function convert_boxes_to_locations (line 29) | def convert_boxes_to_locations(center_form_boxes, center_form_priors, ce...
function area_of (line 39) | def area_of(left_top, right_bottom):
function iou_of (line 53) | def iou_of(boxes0, boxes1, eps=1e-5):
function center_form_to_corner_form (line 72) | def center_form_to_corner_form(locations):
function corner_form_to_center_form (line 77) | def corner_form_to_center_form(boxes):
function hard_nms (line 84) | def hard_nms(box_scores, iou_threshold, top_k=-1, candidate_size=200):
FILE: paddle/vision/utils/misc.py
function str2bool (line 6) | def str2bool(s):
class Timer (line 10) | class Timer:
method __init__ (line 11) | def __init__(self):
method start (line 14) | def start(self, key="default"):
method end (line 17) | def end(self, key="default"):
function save_checkpoint (line 25) | def save_checkpoint(epoch, net_state_dict, optimizer_state_dict, best_sc...
function load_checkpoint (line 35) | def load_checkpoint(checkpoint_path):
function freeze_net_layers (line 39) | def freeze_net_layers(net):
function store_labels (line 44) | def store_labels(path, labels):
FILE: run_video_face_detect_onnx.py
function predict (line 16) | def predict(width, height, confidences, boxes, prob_threshold, iou_thres...
FILE: tf/backend/op.py
function basic_conv (line 4) | def basic_conv(x, out_ch, kernel_size, stride=(1, 1), padding=0, dilatio...
function basic_rfb (line 24) | def basic_rfb(x, in_ch, out_ch, stride=1, scale=0.1, map_reduce=8, visio...
function separable_conv (line 60) | def separable_conv(x, out_ch, kernel_size, stride, padding, prefix='sepa...
function conv_bn (line 73) | def conv_bn(x, out_ch, stride, padding=1, prefix='conv_bn'):
function conv_dw (line 86) | def conv_dw(x, out_ch, stride, padding=1, prefix='conv_dw'):
FILE: tf/backend/utils.py
function post_processing (line 8) | def post_processing(reg_list, cls_list, num_classes, image_size, feature...
function decode_regression (line 44) | def decode_regression(reg, image_size, feature_map_w_h_list, min_boxes,
function load_weight (line 80) | def load_weight(model, torch_path, mapping_table_path):
FILE: tf/convert_tensorflow.py
function main (line 16) | def main():
FILE: tf/det_image.py
function main (line 18) | def main():
FILE: tf/model/rfb_320.py
function create_rfb_net (line 18) | def create_rfb_net(input_shape, base_channel, num_classes):
FILE: tf/model/slim_320.py
function create_slim_net (line 18) | def create_slim_net(input_shape, base_channel, num_classes):
FILE: tflite/TFLiteFaceDetector.py
class UltraLightFaceDetecion (line 7) | class UltraLightFaceDetecion():
method __init__ (line 8) | def __init__(self, filepath, input_size=(320, 240), conf_threshold=0.6,
method _generate_anchors (line 43) | def _generate_anchors(self):
method _pre_processing (line 68) | def _pre_processing(self, img):
method inference (line 76) | def inference(self, img):
method _post_processing (line 94) | def _post_processing(self, boxes, scores):
method _decode_regression (line 109) | def _decode_regression(self, reg):
FILE: tflite/inference_test.py
function image_inference (line 18) | def image_inference(image_path, model_path, color=(125, 255, 0)):
function video_inference (line 36) | def video_inference(video, model_path, color=(125, 255, 0)):
FILE: tflite/model/tflite_RFB_320_without_postprocessing.py
function basic_conv (line 7) | def basic_conv(x, out_ch, kernel_size, stride=(1, 1), padding=0, dilatio...
function basic_rfb (line 27) | def basic_rfb(x, in_ch, out_ch, stride=1, scale=0.1, map_reduce=8, visio...
function separable_conv (line 63) | def separable_conv(x, out_ch, kernel_size, stride, padding, prefix='sepa...
function conv_bn (line 76) | def conv_bn(x, out_ch, stride, padding=1, prefix='conv_bn'):
function conv_dw (line 89) | def conv_dw(x, out_ch, stride, padding=1, prefix='conv_dw'):
function create_rfb_net (line 104) | def create_rfb_net(input_shape, base_channel, num_classes):
FILE: tflite/model/tflite_slim_320_without_postprocessing.py
function create_slim_net (line 8) | def create_slim_net(input_shape, base_channel, num_classes):
FILE: train.py
function lr_poly (line 121) | def lr_poly(base_lr, iter):
function adjust_learning_rate (line 125) | def adjust_learning_rate(optimizer, i_iter):
function train (line 131) | def train(loader, net, criterion, optimizer, device, debug_steps=100, ep...
function test (line 170) | def test(loader, net, criterion, device):
FILE: vision/datasets/voc_dataset.py
class VOCDataset (line 10) | class VOCDataset:
method __init__ (line 12) | def __init__(self, root, transform=None, target_transform=None, is_tes...
method __getitem__ (line 53) | def __getitem__(self, index):
method get_image (line 66) | def get_image(self, index):
method get_annotation (line 73) | def get_annotation(self, index):
method __len__ (line 77) | def __len__(self):
method _read_image_ids (line 81) | def _read_image_ids(image_sets_file):
method _get_annotation (line 88) | def _get_annotation(self, image_id):
method _read_image (line 115) | def _read_image(self, image_id):
FILE: vision/nn/mb_tiny.py
class Mb_Tiny (line 5) | class Mb_Tiny(nn.Module):
method __init__ (line 7) | def __init__(self, num_classes=2):
method forward (line 46) | def forward(self, x):
FILE: vision/nn/mb_tiny_RFB.py
class BasicConv (line 6) | class BasicConv(nn.Module):
method __init__ (line 8) | def __init__(self, in_planes, out_planes, kernel_size, stride=1, paddi...
method forward (line 20) | def forward(self, x):
class BasicRFB (line 29) | class BasicRFB(nn.Module):
method __init__ (line 31) | def __init__(self, in_planes, out_planes, stride=1, scale=0.1, map_red...
method forward (line 58) | def forward(self, x):
class Mb_Tiny_RFB (line 72) | class Mb_Tiny_RFB(nn.Module):
method __init__ (line 74) | def __init__(self, num_classes=2):
method forward (line 113) | def forward(self, x):
FILE: vision/nn/multibox_loss.py
class MultiboxLoss (line 8) | class MultiboxLoss(nn.Module):
method __init__ (line 9) | def __init__(self, priors, neg_pos_ratio,
method forward (line 23) | def forward(self, confidence, predicted_locations, labels, gt_locations):
FILE: vision/ssd/config/fd_config.py
function define_img_size (line 18) | def define_img_size(size):
FILE: vision/ssd/data_preprocessing.py
class TrainAugmentation (line 4) | class TrainAugmentation:
method __init__ (line 5) | def __init__(self, size, mean=0, std=1.0):
method __call__ (line 25) | def __call__(self, img, boxes, labels):
class TestTransform (line 36) | class TestTransform:
method __init__ (line 37) | def __init__(self, size, mean=0.0, std=1.0):
method __call__ (line 46) | def __call__(self, image, boxes, labels):
class PredictionTransform (line 50) | class PredictionTransform:
method __init__ (line 51) | def __init__(self, size, mean=0.0, std=1.0):
method __call__ (line 59) | def __call__(self, image):
FILE: vision/ssd/mb_tiny_RFB_fd.py
function SeperableConv2d (line 9) | def SeperableConv2d(in_channels, out_channels, kernel_size=1, stride=1, ...
function create_Mb_Tiny_RFB_fd (line 20) | def create_Mb_Tiny_RFB_fd(num_classes, is_test=False, device="cuda"):
function create_Mb_Tiny_RFB_fd_predictor (line 56) | def create_Mb_Tiny_RFB_fd_predictor(net, candidate_size=200, nms_method=...
FILE: vision/ssd/mb_tiny_fd.py
function SeperableConv2d (line 9) | def SeperableConv2d(in_channels, out_channels, kernel_size=1, stride=1, ...
function create_mb_tiny_fd (line 20) | def create_mb_tiny_fd(num_classes, is_test=False, device="cuda"):
function create_mb_tiny_fd_predictor (line 56) | def create_mb_tiny_fd_predictor(net, candidate_size=200, nms_method=None...
FILE: vision/ssd/predictor.py
class Predictor (line 8) | class Predictor:
method __init__ (line 9) | def __init__(self, net, size, mean=0.0, std=1.0, nms_method=None,
method predict (line 29) | def predict(self, image, top_k=-1, prob_threshold=None):
FILE: vision/ssd/ssd.py
class SSD (line 14) | class SSD(nn.Module):
method __init__ (line 15) | def __init__(self, num_classes: int, base_net: nn.ModuleList, source_l...
method forward (line 42) | def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
method compute_header (line 103) | def compute_header(self, i, x):
method init_from_base_net (line 114) | def init_from_base_net(self, model):
method init_from_pretrained_ssd (line 121) | def init_from_pretrained_ssd(self, model):
method init (line 130) | def init(self):
method load (line 137) | def load(self, model):
method save (line 140) | def save(self, model_path):
class MatchPrior (line 144) | class MatchPrior(object):
method __init__ (line 145) | def __init__(self, center_form_priors, center_variance, size_variance,...
method __call__ (line 152) | def __call__(self, gt_boxes, gt_labels):
function _xavier_init_ (line 164) | def _xavier_init_(m: nn.Module):
FILE: vision/transforms/transforms.py
function intersect (line 13) | def intersect(box_a, box_b):
function jaccard_numpy (line 20) | def jaccard_numpy(box_a, box_b):
function object_converage_numpy (line 40) | def object_converage_numpy(box_a, box_b):
class Compose (line 59) | class Compose(object):
method __init__ (line 70) | def __init__(self, transforms):
method __call__ (line 73) | def __call__(self, img, boxes=None, labels=None):
class Lambda (line 79) | class Lambda(object):
method __init__ (line 82) | def __init__(self, lambd):
method __call__ (line 86) | def __call__(self, img, boxes=None, labels=None):
class ConvertFromInts (line 90) | class ConvertFromInts(object):
method __call__ (line 91) | def __call__(self, image, boxes=None, labels=None):
class SubtractMeans (line 95) | class SubtractMeans(object):
method __init__ (line 96) | def __init__(self, mean):
method __call__ (line 99) | def __call__(self, image, boxes=None, labels=None):
class imgprocess (line 105) | class imgprocess(object):
method __init__ (line 106) | def __init__(self, std):
method __call__ (line 109) | def __call__(self, image, boxes=None, labels=None):
class ToAbsoluteCoords (line 115) | class ToAbsoluteCoords(object):
method __call__ (line 116) | def __call__(self, image, boxes=None, labels=None):
class ToPercentCoords (line 126) | class ToPercentCoords(object):
method __call__ (line 127) | def __call__(self, image, boxes=None, labels=None):
class Resize (line 137) | class Resize(object):
method __init__ (line 138) | def __init__(self, size=(300, 300)):
method __call__ (line 141) | def __call__(self, image, boxes=None, labels=None):
class RandomSaturation (line 147) | class RandomSaturation(object):
method __init__ (line 148) | def __init__(self, lower=0.5, upper=1.5):
method __call__ (line 154) | def __call__(self, image, boxes=None, labels=None):
class RandomHue (line 161) | class RandomHue(object):
method __init__ (line 162) | def __init__(self, delta=18.0):
method __call__ (line 166) | def __call__(self, image, boxes=None, labels=None):
class RandomLightingNoise (line 174) | class RandomLightingNoise(object):
method __init__ (line 175) | def __init__(self):
method __call__ (line 180) | def __call__(self, image, boxes=None, labels=None):
class ConvertColor (line 188) | class ConvertColor(object):
method __init__ (line 189) | def __init__(self, current, transform):
method __call__ (line 193) | def __call__(self, image, boxes=None, labels=None):
class RandomContrast (line 209) | class RandomContrast(object):
method __init__ (line 210) | def __init__(self, lower=0.5, upper=1.5):
method __call__ (line 217) | def __call__(self, image, boxes=None, labels=None):
class RandomBrightness (line 224) | class RandomBrightness(object):
method __init__ (line 225) | def __init__(self, delta=32):
method __call__ (line 230) | def __call__(self, image, boxes=None, labels=None):
class ToCV2Image (line 237) | class ToCV2Image(object):
method __call__ (line 238) | def __call__(self, tensor, boxes=None, labels=None):
class ToTensor (line 242) | class ToTensor(object):
method __call__ (line 243) | def __call__(self, cvimage, boxes=None, labels=None):
class RandomSampleCrop (line 247) | class RandomSampleCrop(object):
method __init__ (line 261) | def __init__(self):
method __call__ (line 274) | def __call__(self, image, boxes=None, labels=None):
class RandomSampleCrop_v2 (line 352) | class RandomSampleCrop_v2(object):
method __init__ (line 366) | def __init__(self):
method __call__ (line 379) | def __call__(self, image, boxes=None, labels=None):
class Expand (line 456) | class Expand(object):
method __init__ (line 457) | def __init__(self, mean):
method __call__ (line 460) | def __call__(self, image, boxes, labels):
class RandomMirror (line 484) | class RandomMirror(object):
method __call__ (line 485) | def __call__(self, image, boxes, classes):
class SwapChannels (line 494) | class SwapChannels(object):
method __init__ (line 502) | def __init__(self, swaps):
method __call__ (line 505) | def __call__(self, image):
class PhotometricDistort (line 520) | class PhotometricDistort(object):
method __init__ (line 521) | def __init__(self):
method __call__ (line 533) | def __call__(self, image, boxes, labels):
FILE: vision/utils/box_utils.py
function generate_priors (line 6) | def generate_priors(feature_map_list, shrinkage_list, image_size, min_bo...
function convert_locations_to_boxes (line 32) | def convert_locations_to_boxes(locations, priors, center_variance,
function convert_boxes_to_locations (line 58) | def convert_boxes_to_locations(center_form_boxes, center_form_priors, ce...
function area_of (line 68) | def area_of(left_top, right_bottom) -> torch.Tensor:
function iou_of (line 82) | def iou_of(boxes0, boxes1, eps=1e-5):
function assign_priors (line 101) | def assign_priors(gt_boxes, gt_labels, corner_form_priors,
function hard_negative_mining (line 131) | def hard_negative_mining(loss, labels, neg_pos_ratio):
function center_form_to_corner_form (line 156) | def center_form_to_corner_form(locations):
function corner_form_to_center_form (line 161) | def corner_form_to_center_form(boxes):
function hard_nms (line 168) | def hard_nms(box_scores, iou_threshold, top_k=-1, candidate_size=200):
function nms (line 201) | def nms(box_scores, nms_method=None, score_threshold=None, iou_threshold...
function soft_nms (line 209) | def soft_nms(box_scores, score_threshold, sigma=0.5, top_k=-1):
FILE: vision/utils/box_utils_numpy.py
function convert_locations_to_boxes (line 4) | def convert_locations_to_boxes(locations, priors, center_variance,
function convert_boxes_to_locations (line 30) | def convert_boxes_to_locations(center_form_boxes, center_form_priors, ce...
function area_of (line 40) | def area_of(left_top, right_bottom):
function iou_of (line 54) | def iou_of(boxes0, boxes1, eps=1e-5):
function center_form_to_corner_form (line 73) | def center_form_to_corner_form(locations):
function corner_form_to_center_form (line 78) | def corner_form_to_center_form(boxes):
function hard_nms (line 85) | def hard_nms(box_scores, iou_threshold, top_k=-1, candidate_size=200):
FILE: vision/utils/misc.py
function str2bool (line 6) | def str2bool(s):
class Timer (line 10) | class Timer:
method __init__ (line 11) | def __init__(self):
method start (line 14) | def start(self, key="default"):
method end (line 17) | def end(self, key="default"):
function save_checkpoint (line 25) | def save_checkpoint(epoch, net_state_dict, optimizer_state_dict, best_sc...
function load_checkpoint (line 35) | def load_checkpoint(checkpoint_path):
function freeze_net_layers (line 39) | def freeze_net_layers(net):
function store_labels (line 44) | def store_labels(path, labels):
FILE: widerface_evaluate/evaluation.py
function get_gt_boxes (line 17) | def get_gt_boxes(gt_dir):
function get_gt_boxes_from_txt (line 36) | def get_gt_boxes_from_txt(gt_path, cache_dir):
function read_pred_file (line 81) | def read_pred_file(filepath):
function get_preds (line 103) | def get_preds(pred_dir):
function norm_score (line 120) | def norm_score(pred):
function image_eval (line 145) | def image_eval(pred, gt, ignore, iou_thresh):
function img_pr_info (line 181) | def img_pr_info(thresh_num, pred_info, proposal_list, pred_recall):
function dataset_pr_info (line 198) | def dataset_pr_info(thresh_num, pr_curve, count_face):
function voc_ap (line 206) | def voc_ap(rec, prec):
function evaluation (line 226) | def evaluation(pred, gt_path, iou_thresh=0.5):
Condensed preview — 168 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,332K chars).
[
{
"path": ".gitignore",
"chars": 209,
"preview": ".idea\ndata/wider_face_add_lm_10_10\n\n__pycache__/\n*.py[cod]\n*$py.class\n\ndetect_imgs_results\ndetect_imgs_results_onnx\nwide"
},
{
"path": ".gitmodules",
"chars": 99,
"preview": "[submodule \"ncnn/3rdparty/ncnn\"]\n\tpath = ncnn/3rdparty/ncnn\n\turl = https://github.com/Tencent/ncnn\n"
},
{
"path": "LICENSE",
"chars": 1063,
"preview": "MIT License\n\nCopyright (c) 2019 linzai\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
},
{
"path": "MNN/CMakeLists.txt",
"chars": 321,
"preview": "cmake_minimum_required(VERSION 3.10)\nproject(Ultra-face-mnn)\n\nset(CMAKE_CXX_STANDARD 11)\n\nfind_package(OpenCV REQUIRED)\n"
},
{
"path": "MNN/README.md",
"chars": 2829,
"preview": "# C++ implemententation of [Ultra-Light-Fast-Generic-Face-Detector-1MB](https://github.com/Linzaer/Ultra-Light-Fast-Gene"
},
{
"path": "MNN/mnn/include/AutoTime.hpp",
"chars": 823,
"preview": "//\n// AutoTime.hpp\n// MNN\n//\n// Created by MNN on 2018/07/27.\n// Copyright © 2018, Alibaba Group Holding Limited\n//\n"
},
{
"path": "MNN/mnn/include/Backend.hpp",
"chars": 6776,
"preview": "//\n// Backend.hpp\n// MNN\n//\n// Created by MNN on 2018/07/06.\n// Copyright © 2018, Alibaba Group Holding Limited\n//\n\n"
},
{
"path": "MNN/mnn/include/ErrorCode.hpp",
"chars": 618,
"preview": "//\n// ErrorCode.hpp\n// MNN\n//\n// Created by MNN on 2018/09/18.\n// Copyright © 2018, Alibaba Group Holding Limited\n//"
},
{
"path": "MNN/mnn/include/HalideRuntime.h",
"chars": 11395,
"preview": "#ifndef HALIDE_HALIDERUNTIME_H\n#define HALIDE_HALIDERUNTIME_H\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdbool"
},
{
"path": "MNN/mnn/include/ImageProcess.hpp",
"chars": 4503,
"preview": "//\n// ImageProcess.hpp\n// MNN\n//\n// Created by MNN on 2018/09/19.\n// Copyright © 2018, Alibaba Group Holding Limited"
},
{
"path": "MNN/mnn/include/Interpreter.hpp",
"chars": 8418,
"preview": "//\n// Interpreter.hpp\n// MNN\n//\n// Created by MNN on 2018/07/23.\n// Copyright © 2018, Alibaba Group Holding Limited\n"
},
{
"path": "MNN/mnn/include/MNNDefine.h",
"chars": 2208,
"preview": "//\n// MNNDefine.h\n// MNN\n//\n// Created by MNN on 2018/08/09.\n// Copyright © 2018, Alibaba Group Holding Limited\n//\n\n"
},
{
"path": "MNN/mnn/include/MNNForwardType.h",
"chars": 1554,
"preview": "//\n// MNNForwardType.h\n// MNN\n//\n// Created by MNN on 2019/01/19.\n// Copyright © 2018, Alibaba Group Holding Limited"
},
{
"path": "MNN/mnn/include/MNNSharedContext.h",
"chars": 700,
"preview": "//\n// MNNSharedContext.h\n// MNN\n//\n// Created by MNN on 2018/10/11.\n// Copyright © 2018, Alibaba Group Holding Limit"
},
{
"path": "MNN/mnn/include/Matrix.h",
"chars": 55939,
"preview": "/*\n * Copyright 2006 The Android Open Source Project\n *\n * Use of this source code is governed by a BSD-style license th"
},
{
"path": "MNN/mnn/include/NonCopyable.hpp",
"chars": 585,
"preview": "//\n// NonCopyable.hpp\n// MNN\n//\n// Created by MNN on 2018/09/19.\n// Copyright © 2018, Alibaba Group Holding Limited\n"
},
{
"path": "MNN/mnn/include/Rect.h",
"chars": 18894,
"preview": "//\n// Rect.h\n// MNN\n//\n// Modified by jiangxiaotang on 2018/09/19.\n// Copyright © 2018, Alibaba Group Holding Limite"
},
{
"path": "MNN/mnn/include/Tensor.hpp",
"chars": 7880,
"preview": "//\n// Tensor.hpp\n// MNN\n//\n// Created by MNN on 2018/08/14.\n// Copyright © 2018, Alibaba Group Holding Limited\n//\n\n#"
},
{
"path": "MNN/mnn/include/revertMNNModel.hpp",
"chars": 628,
"preview": "//\n// revertMNNModel.hpp\n// MNN\n//\n// Created by MNN on 2019/01/31.\n// Copyright © 2018, Alibaba Group Holding Limit"
},
{
"path": "MNN/python/README.md",
"chars": 1732,
"preview": "# Python implemententation of [Ultra-Light-Fast-Generic-Face-Detector-1MB](https://github.com/Linzaer/Ultra-Light-Fast-G"
},
{
"path": "MNN/python/ultraface_py_mnn.py",
"chars": 5990,
"preview": "#!/usr/bin/env/ python\n# -*- coding: utf-8 -*-\n\"\"\" \n@author:linzai \n@file: ultraface_py_mnn.py \n@time: 2019-11-25 \n\"\"\"\nf"
},
{
"path": "MNN/src/UltraFace.cpp",
"chars": 7755,
"preview": "// Created by Linzaer on 2019/11/15.\n// Copyright © 2019 Linzaer. All rights reserved.\n\n#define clip(x, y) (x < 0 ? 0 "
},
{
"path": "MNN/src/UltraFace.hpp",
"chars": 2174,
"preview": "// Created by Linzaer on 2019/11/15.\n// Copyright © 2019 Linzaer. All rights reserved.\n\n#ifndef UltraFace_hpp\n#define "
},
{
"path": "MNN/src/main.cpp",
"chars": 1327,
"preview": "// Created by Linzaer on 2019/11/15.\n// Copyright © 2019 Linzaer. All rights reserved.\n\n#include \"UltraFace.hpp\"\n#incl"
},
{
"path": "README.md",
"chars": 12263,
"preview": "[English](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB ) | [中文简体](https://github.com/Linzaer/Ul"
},
{
"path": "README_CN.md",
"chars": 8697,
"preview": "[English](https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB) | [中文简体](https://github.com/Linzaer/Ult"
},
{
"path": "caffe/MyCaffe.py",
"chars": 4773,
"preview": "from collections import OrderedDict, Counter\n\nfrom caffe.proto import caffe_pb2\nfrom google import protobuf\nimport six\n\n"
},
{
"path": "caffe/README.md",
"chars": 993,
"preview": "## I added several operator(Transpose/Permute/Softmax) conversion support based on [onnx2caffe](https://github.com/MTlab"
},
{
"path": "caffe/convertCaffe.py",
"chars": 3107,
"preview": "from __future__ import print_function\n\nimport sys\n\nimport caffe\nfrom caffe.proto import caffe_pb2\nimport onnx\n\ncaffe.set"
},
{
"path": "caffe/model/RFB-320/RFB-320.prototxt",
"chars": 19217,
"preview": "layer {\n name: \"input\"\n type: \"Input\"\n top: \"input\"\n input_param {\n shape {\n dim: 1\n dim: 3\n dim: "
},
{
"path": "caffe/model/Slim-320/slim-320.prototxt",
"chars": 16164,
"preview": "layer {\n name: \"input\"\n type: \"Input\"\n top: \"input\"\n input_param {\n shape {\n dim: 1\n dim: 3\n dim: "
},
{
"path": "caffe/onnx2caffe/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "caffe/onnx2caffe/_error_utils.py",
"chars": 2026,
"preview": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\n\nfrom typin"
},
{
"path": "caffe/onnx2caffe/_graph.py",
"chars": 8233,
"preview": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __futu"
},
{
"path": "caffe/onnx2caffe/_operators.py",
"chars": 16005,
"preview": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __futu"
},
{
"path": "caffe/onnx2caffe/_transformers.py",
"chars": 19340,
"preview": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __futu"
},
{
"path": "caffe/onnx2caffe/_weightloader.py",
"chars": 5269,
"preview": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __futu"
},
{
"path": "caffe/ultra_face_caffe_inference.py",
"chars": 7589,
"preview": "# coding=utf-8\nimport argparse\nimport os\nimport time\nfrom math import ceil\n\nimport caffe\nimport cv2\nimport numpy as np\n\n"
},
{
"path": "caffe/ultra_face_opencvdnn_inference.py",
"chars": 7433,
"preview": "# coding=utf-8\nimport argparse\nimport os\nimport time\nfrom math import ceil\n\nimport cv2\nimport numpy as np\nfrom cv2 impor"
},
{
"path": "cal_flops.py",
"chars": 855,
"preview": "\"\"\"\nOutput model complexity\n\"\"\"\nimport time\n\nimport torch\nfrom torchstat import stat\nfrom torchsummary import summary\n\nf"
},
{
"path": "check_gt_box.py",
"chars": 2224,
"preview": "\"\"\"\nThis code is used to check the data size distribution in the dataset.\n\"\"\"\nimport xml.etree.ElementTree as ET\nfrom ma"
},
{
"path": "convert_to_onnx.py",
"chars": 1523,
"preview": "\"\"\"\nThis code is used to convert the pytorch model into an onnx format model.\n\"\"\"\nimport sys\n\nimport torch.onnx\n\nfrom vi"
},
{
"path": "data/retinaface_labels/test/label.txt",
"chars": 909921,
"preview": "# 0--Parade/0_Parade_marchingband_1_737.jpg\n# 0--Parade/0_Parade_marchingband_1_494.jpg\n# 0--Parade/0_Parade_Parade_0_33"
},
{
"path": "data/retinaface_labels/val/label.txt",
"chars": 713974,
"preview": "# 0--Parade/0_Parade_marchingband_1_465.jpg\n345 211 4 4\n331 126 3 3\n250 126 3 4\n221 128 4 5\n427 116 3 4\n393 79 3 4\n373 1"
},
{
"path": "data/wider_face_2_voc_add_landmark.py",
"chars": 12649,
"preview": "#!/usr/bin/python\n# -*- coding: UTF-8 -*-\nimport os\nimport shutil\nfrom xml.dom.minidom import Document\n\nimport cv2\n\nroot"
},
{
"path": "detect_imgs.py",
"chars": 3256,
"preview": "\"\"\"\nThis code is used to batch detect images in a folder.\n\"\"\"\nimport argparse\nimport os\nimport sys\n\nimport cv2\n\nfrom vis"
},
{
"path": "detect_imgs_onnx.py",
"chars": 3494,
"preview": "\"\"\"\nThis code uses the onnx model to detect faces from live video or cameras.\n\"\"\"\nimport os\nimport time\n\nimport cv2\nimpo"
},
{
"path": "masked_face/README.md",
"chars": 4586,
"preview": "# Masked Face Detection \n\n\n\nset(CMAKE_CXX_FLAGS \"-Wall\")\nset(CMAKE_CXX_FLAGS_RELEASE \"-O2 -DNDEBUG\")\nset(CMAKE"
},
{
"path": "ncnn/README.md",
"chars": 2510,
"preview": "# C++ implemententation of [Ultra-Light-Fast-Generic-Face-Detector-1MB](https://github.com/Linzaer/Ultra-Light-Fast-Gene"
},
{
"path": "ncnn/data/version-RFB/RFB-320.param",
"chars": 10237,
"preview": "7767517\n116 126\nInput input 0 1 input\nConvolution 245 1 1 input "
},
{
"path": "ncnn/data/version-slim/slim_320.param",
"chars": 8220,
"preview": "7767517\n100 107\nInput input 0 1 input\nConvolution 185 1 1 input "
},
{
"path": "ncnn/src/UltraFace.cpp",
"chars": 6425,
"preview": "//\n// UltraFace.cpp\n// UltraFaceTest\n//\n// Created by vealocia on 2019/10/17.\n// Copyright © 2019 vealocia. All righ"
},
{
"path": "ncnn/src/UltraFace.hpp",
"chars": 2053,
"preview": "//\n// UltraFace.hpp\n// UltraFaceTest\n//\n// Created by vealocia on 2019/10/17.\n// Copyright © 2019 vealocia. All righ"
},
{
"path": "ncnn/src/main.cpp",
"chars": 1319,
"preview": "//\n// main.cpp\n// UltraFaceTest\n//\n// Created by vealocia on 2019/10/17.\n// Copyright © 2019 vealocia. All rights re"
},
{
"path": "opencv_dnn/cv_dnn_ultraface.cpp",
"chars": 5295,
"preview": "#include \"stdafx.h\"\n#include \"cv_dnn_ultraface.h\"\n\n#define clip(x, y) (x < 0 ? 0 : (x > y ? y : x))\n\nUltraFace::UltraFac"
},
{
"path": "opencv_dnn/cv_dnn_ultraface.h",
"chars": 1747,
"preview": "#ifndef UltraFace_hpp\n#define UltraFace_hpp\n\n#pragma once\n\n#include <algorithm>\n#include <iostream>\n#include <string>\n#i"
},
{
"path": "paddle/train-version-RFB.sh",
"chars": 552,
"preview": "#!/usr/bin/env bash\nmodel_root_path=\"./models/train-version-RFB\"\nlog_dir=\"$model_root_path/logs\"\nlog=\"$log_dir/log\"\nmkdi"
},
{
"path": "paddle/train-version-slim.sh",
"chars": 554,
"preview": "#!/usr/bin/env bash\nmodel_root_path=\"./models/train-version-slim\"\nlog_dir=\"$model_root_path/logs\"\nlog=\"$log_dir/log\"\nmkd"
},
{
"path": "paddle/train.py",
"chars": 16085,
"preview": "\"\"\"\nThis code is the main training code.\n\"\"\"\nimport argparse\nimport itertools\nimport logging\nimport os\nimport sys\n\nimpor"
},
{
"path": "paddle/vision/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "paddle/vision/datasets/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "paddle/vision/datasets/voc_dataset.py",
"chars": 4524,
"preview": "import logging\nimport os\nimport pathlib\nimport xml.etree.ElementTree as ET\n\nimport cv2\nimport numpy as np\nfrom paddle.io"
},
{
"path": "paddle/vision/nn/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "paddle/vision/nn/mb_tiny.py",
"chars": 1950,
"preview": "import paddle.nn as nn\nimport paddle.nn.functional as F\n\n\nclass Mb_Tiny(nn.Layer):\n\n def __init__(self, num_classes=2"
},
{
"path": "paddle/vision/nn/mb_tiny_RFB.py",
"chars": 5268,
"preview": "import paddle\nimport paddle.nn as nn\nimport paddle.nn.functional as F\n\n\nclass BasicConv(nn.Layer):\n\n def __init__(sel"
},
{
"path": "paddle/vision/nn/multibox_loss.py",
"chars": 2552,
"preview": "import paddle\nimport paddle.nn as nn\nimport paddle.nn.functional as F\n\nfrom ..utils import box_utils\n\n\n# class MultiboxL"
},
{
"path": "paddle/vision/ssd/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "paddle/vision/ssd/config/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "paddle/vision/ssd/config/fd_config.py",
"chars": 1619,
"preview": "import numpy as np\n\nfrom vision.utils.box_utils import generate_priors\n\nimage_mean_test = image_mean = np.array([127, 12"
},
{
"path": "paddle/vision/ssd/data_preprocessing.py",
"chars": 1749,
"preview": "from ..transforms.transforms import *\n\n\nclass TrainAugmentation:\n def __init__(self, size, mean=0, std=1.0):\n "
},
{
"path": "paddle/vision/ssd/mb_tiny_RFB_fd.py",
"chars": 2943,
"preview": "from paddle.nn import Conv2D, Sequential, LayerList, ReLU\n\nfrom vision.nn.mb_tiny_RFB import Mb_Tiny_RFB\nfrom vision.ssd"
},
{
"path": "paddle/vision/ssd/mb_tiny_fd.py",
"chars": 2923,
"preview": "from paddle.nn import Conv2D, Sequential, LayerList, ReLU\n\nfrom vision.nn.mb_tiny import Mb_Tiny\nfrom vision.ssd.config "
},
{
"path": "paddle/vision/ssd/predictor.py",
"chars": 2962,
"preview": "import paddle\n\nfrom ..utils import box_utils\nfrom .data_preprocessing import PredictionTransform\nfrom ..utils.misc impor"
},
{
"path": "paddle/vision/ssd/ssd.py",
"chars": 6540,
"preview": "from collections import namedtuple\nfrom typing import List, Tuple\n\nimport numpy as np\nimport paddle\nimport paddle.nn as "
},
{
"path": "paddle/vision/transforms/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "paddle/vision/transforms/transforms.py",
"chars": 18241,
"preview": "# from https://github.com/amdegroot/ssd.pytorch\n\n\nimport types\n\nimport cv2\nimport numpy as np\nimport paddle\nfrom numpy i"
},
{
"path": "paddle/vision/utils/__init__.py",
"chars": 20,
"preview": "from .misc import *\n"
},
{
"path": "paddle/vision/utils/box_utils.py",
"chars": 9948,
"preview": "import math\nimport numpy as np\nimport paddle\n\n\ndef generate_priors(feature_map_list, shrinkage_list, image_size, min_box"
},
{
"path": "paddle/vision/utils/box_utils_numpy.py",
"chars": 4478,
"preview": "import numpy as np\n\n\ndef convert_locations_to_boxes(locations, priors, center_variance, size_variance):\n \"\"\"Convert r"
},
{
"path": "paddle/vision/utils/misc.py",
"chars": 1127,
"preview": "import datetime\n\nimport paddle\n\n\ndef str2bool(s):\n return s.lower() in ('true', '1')\n\n\nclass Timer:\n def __init__("
},
{
"path": "requirements.txt",
"chars": 103,
"preview": "numpy\ntorch\nopencv_python\ntorchvision\ntyping\ntorchstat\ntorchsummary\nptflops\nmatplotlib\nonnx\nonnxruntime"
},
{
"path": "run_video_face_detect.py",
"chars": 3724,
"preview": "\"\"\"\nThis code uses the pytorch model to detect faces from live video or camera.\n\"\"\"\nimport argparse\nimport sys\nimport cv"
},
{
"path": "run_video_face_detect_onnx.py",
"chars": 3542,
"preview": "\"\"\"\nThis code uses the onnx model to detect faces from live video or cameras.\n\"\"\"\nimport time\n\nimport cv2\nimport numpy a"
},
{
"path": "tf/README.md",
"chars": 683,
"preview": "# Tensorflow implementation of Ultra-Light-Fast-Generic-Face-Detector-1MB with converter\n\nYou can use this script to con"
},
{
"path": "tf/backend/op.py",
"chars": 4809,
"preview": "import tensorflow as tf\n\n\ndef basic_conv(x, out_ch, kernel_size, stride=(1, 1), padding=0, dilation=1, relu=True,\n "
},
{
"path": "tf/backend/utils.py",
"chars": 5190,
"preview": "import json\n\nimport numpy as np\nimport tensorflow as tf\nimport torch\n\n\ndef post_processing(reg_list, cls_list, num_class"
},
{
"path": "tf/convert_tensorflow.py",
"chars": 1196,
"preview": "import argparse\nimport sys\n\nfrom tf.backend.utils import load_weight\nfrom tf.model.rfb_320 import create_rfb_net\nfrom tf"
},
{
"path": "tf/det_image.py",
"chars": 1454,
"preview": "import argparse\nimport sys\n\nimport cv2\nimport tensorflow as tf\nimport numpy as np\n\nparser = argparse.ArgumentParser(\n "
},
{
"path": "tf/mapping_tables/rfb_320.json",
"chars": 12953,
"preview": "[\n {\n \"name\": \"basenet.0.0_conv\",\n \"weight\": [\n \"base_net.0.0.weight\"\n ]\n },\n {\n \"name\": \"basenet.0."
},
{
"path": "tf/mapping_tables/slim_320.json",
"chars": 9318,
"preview": "[\n {\n \"name\": \"basenet.0.0_conv\",\n \"weight\": [\n \"base_net.0.0.weight\"\n ]\n },\n {\n \"name\": \"basenet.0."
},
{
"path": "tf/model/rfb_320.py",
"chars": 3465,
"preview": "import tensorflow as tf\n\nfrom tf.backend.op import conv_bn, conv_dw, basic_rfb, separable_conv\nfrom tf.backend.utils imp"
},
{
"path": "tf/model/slim_320.py",
"chars": 3424,
"preview": "import tensorflow as tf\n\nfrom tf.backend.op import conv_bn, conv_dw, separable_conv\nfrom tf.backend.utils import post_pr"
},
{
"path": "tflite/README.md",
"chars": 1751,
"preview": "# TFLite implementation of Ultra-Light-Fast-Generic-Face-Detector-1MB\n\nTFLite model is suitable for edge computing devic"
},
{
"path": "tflite/TFLiteFaceDetector.py",
"chars": 4477,
"preview": "from functools import partial\nimport cv2\nimport tensorflow as tf\nimport numpy as np\n\n\nclass UltraLightFaceDetecion():\n "
},
{
"path": "tflite/inference_test.py",
"chars": 2021,
"preview": "import argparse\nimport cv2\nimport time\n\nfrom TFLiteFaceDetector import UltraLightFaceDetecion\n\n\nparser = argparse.Argume"
},
{
"path": "tflite/model/tflite_RFB_320_without_postprocessing.py",
"chars": 8042,
"preview": "import tensorflow as tf\n\nimport sys\nsys.path.append(\"../tf\")\nfrom backend.op import conv_bn, conv_dw, basic_rfb, separab"
},
{
"path": "tflite/model/tflite_slim_320_without_postprocessing.py",
"chars": 3298,
"preview": "import tensorflow as tf\n\nimport sys\nsys.path.append(\"../tf\")\nfrom backend.op import conv_bn, conv_dw, separable_conv\n\n\nd"
},
{
"path": "train-version-RFB.sh",
"chars": 552,
"preview": "#!/usr/bin/env bash\nmodel_root_path=\"./models/train-version-RFB\"\nlog_dir=\"$model_root_path/logs\"\nlog=\"$log_dir/log\"\nmkdi"
},
{
"path": "train-version-slim.sh",
"chars": 554,
"preview": "#!/usr/bin/env bash\nmodel_root_path=\"./models/train-version-slim\"\nlog_dir=\"$model_root_path/logs\"\nlog=\"$log_dir/log\"\nmkd"
},
{
"path": "train.py",
"chars": 16574,
"preview": "\"\"\"\nThis code is the main training code.\n\"\"\"\nimport argparse\nimport itertools\nimport logging\nimport os\nimport sys\n\nimpor"
},
{
"path": "vision/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "vision/datasets/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "vision/datasets/voc_dataset.py",
"chars": 4462,
"preview": "import logging\nimport os\nimport pathlib\nimport xml.etree.ElementTree as ET\n\nimport cv2\nimport numpy as np\n\n\nclass VOCDat"
},
{
"path": "vision/nn/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "vision/nn/mb_tiny.py",
"chars": 1973,
"preview": "import torch.nn as nn\nimport torch.nn.functional as F\n\n\nclass Mb_Tiny(nn.Module):\n\n def __init__(self, num_classes=2)"
},
{
"path": "vision/nn/mb_tiny_RFB.py",
"chars": 5248,
"preview": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\n\nclass BasicConv(nn.Module):\n\n def __init__(self,"
},
{
"path": "vision/nn/multibox_loss.py",
"chars": 2030,
"preview": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nfrom ..utils import box_utils\n\n\nclass MultiboxLoss(n"
},
{
"path": "vision/ssd/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "vision/ssd/config/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "vision/ssd/config/fd_config.py",
"chars": 1619,
"preview": "import numpy as np\n\nfrom vision.utils.box_utils import generate_priors\n\nimage_mean_test = image_mean = np.array([127, 12"
},
{
"path": "vision/ssd/data_preprocessing.py",
"chars": 1749,
"preview": "from ..transforms.transforms import *\n\n\nclass TrainAugmentation:\n def __init__(self, size, mean=0, std=1.0):\n "
},
{
"path": "vision/ssd/mb_tiny_RFB_fd.py",
"chars": 2946,
"preview": "from torch.nn import Conv2d, Sequential, ModuleList, ReLU\n\nfrom vision.nn.mb_tiny_RFB import Mb_Tiny_RFB\nfrom vision.ssd"
},
{
"path": "vision/ssd/mb_tiny_fd.py",
"chars": 2926,
"preview": "from torch.nn import Conv2d, Sequential, ModuleList, ReLU\n\nfrom vision.nn.mb_tiny import Mb_Tiny\nfrom vision.ssd.config "
},
{
"path": "vision/ssd/predictor.py",
"chars": 2927,
"preview": "import torch\n\nfrom ..utils import box_utils\nfrom .data_preprocessing import PredictionTransform\nfrom ..utils.misc import"
},
{
"path": "vision/ssd/ssd.py",
"chars": 6712,
"preview": "from collections import namedtuple\nfrom typing import List, Tuple\n\nimport numpy as np\nimport torch\nimport torch.nn as nn"
},
{
"path": "vision/transforms/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "vision/transforms/transforms.py",
"chars": 18205,
"preview": "# from https://github.com/amdegroot/ssd.pytorch\n\n\nimport types\n\nimport cv2\nimport numpy as np\nimport torch\nfrom numpy im"
},
{
"path": "vision/utils/__init__.py",
"chars": 20,
"preview": "from .misc import *\n"
},
{
"path": "vision/utils/box_utils.py",
"chars": 9279,
"preview": "import math\n\nimport torch\n\n\ndef generate_priors(feature_map_list, shrinkage_list, image_size, min_boxes, clamp=True) -> "
},
{
"path": "vision/utils/box_utils_numpy.py",
"chars": 4509,
"preview": "import numpy as np\n\n\ndef convert_locations_to_boxes(locations, priors, center_variance,\n s"
},
{
"path": "vision/utils/misc.py",
"chars": 1124,
"preview": "import datetime\n\nimport torch\n\n\ndef str2bool(s):\n return s.lower() in ('true', '1')\n\n\nclass Timer:\n def __init__(s"
},
{
"path": "widerface_evaluate/README.md",
"chars": 552,
"preview": "# WiderFace-Evaluation\nPython Evaluation Code for [Wider Face Dataset](http://mmlab.ie.cuhk.edu.hk/projects/WIDERFace/)\n"
},
{
"path": "widerface_evaluate/box_overlaps.pyx",
"chars": 1755,
"preview": "# --------------------------------------------------------\n# Fast R-CNN\n# Copyright (c) 2015 Microsoft\n# Licensed under "
},
{
"path": "widerface_evaluate/evaluation.py",
"chars": 8991,
"preview": "\"\"\"\nWiderFace evaluation code\nauthor: wondervictor\nmail: tianhengcheng@gmail.com\ncopyright@wondervictor\n\"\"\"\n\nimport os\ni"
},
{
"path": "widerface_evaluate/evaluation_on_widerface.py",
"chars": 3236,
"preview": "#!/usr/bin/ python3\n# -*- coding: utf-8 -*-\n# @Time : 2019-10-17\n# @Author : vealocia\n# @FileName: evaluation_on_wid"
},
{
"path": "widerface_evaluate/setup.py",
"chars": 328,
"preview": "\"\"\"\nWiderFace evaluation code\nauthor: wondervictor\nmail: tianhengcheng@gmail.com\ncopyright@wondervictor\n\"\"\"\n\nfrom distut"
}
]
// ... and 35 more files (download for full content)
About this extraction
This page contains the full source code of the Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 168 files (18.5 MB), approximately 567.3k tokens, and a symbol index with 569 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.