diff --git a/easyPR-doc/algorithm.md b/easyPR-doc/algorithm.md
new file mode 100644
index 00000000..8fa945e6
--- /dev/null
+++ b/easyPR-doc/algorithm.md
@@ -0,0 +1,4 @@
+ - NMS(非极大值抑制)
+ - 选取邻近区域中得分最高的矩形块,以区分多个矩形重叠的情况
+ - SVM(支持向量机)
+ -
diff --git a/easyPR-doc/classDemo.md b/easyPR-doc/classDemo.md
new file mode 100644
index 00000000..9bcd3898
--- /dev/null
+++ b/easyPR-doc/classDemo.md
@@ -0,0 +1,9 @@
+### Class
+
+#### Properties
+
+#### Functions
+
+***
+
+***
diff --git a/easyPR-doc/core/chars_identify.md b/easyPR-doc/core/chars_identify.md
new file mode 100644
index 00000000..a5d4e2e9
--- /dev/null
+++ b/easyPR-doc/core/chars_identify.md
@@ -0,0 +1,34 @@
+### Class CharsIdentify
+
+#### Properties
+ - (private:)
+ - [`annCallback extractFeature`](#extractFeature)
+ - [`static CharsIdentify* instance_`](#instance_)
+ - [`cv::Ptr ann_`](#ann_)
+ - [`cv::Ptr annChinese_`](#annChinese_)
+ - [`cv::Ptr annGray_`](#annGray_)
+ - [`std::shared_ptr kv_`](#kv_)
+
+#### Functions
+ - (public:)
+ - [`static CharsIdentify* instance()`](#instance)
+ - [`int classify(cv::Mat f, float& maxVal, bool isChinses = false, bool isAlphabet = false)`](#classify1)
+ - [`void classify(cv::Mat featureRows, std::vector& out_maxIndexs,std::vector& out_maxVals, std::vector isChineseVec)`](#classify2)
+ - [`void classify(std::vector& charVec)`](#classify3)
+ - [`void classifyChinese(std::vector& charVec)`](#classifyChinese)
+ - [`void classifyChineseGray(std::vector& charVec)`](#classifyChineseGray)
+ - [`std::pair identify(cv::Mat input, bool isChinese = false, bool isAlphabet = false)`](#identify1)
+ - [`int identify(std::vector inputs, std::vector>& outputs,std::vector isChineseVec)`](#identify2)
+ - [`std::pair identifyChinese(cv::Mat input, float& result, bool& isChinese)`](#identifyChinese)
+ - [`std::pair identifyChineseGray(cv::Mat input, float& result, bool& isChinese)`](#identifyChineseGray)
+ - [`bool isCharacter(cv::Mat input, std::string& label, float& maxVal, bool isChinese = false)`](#isCharacter)
+ - [`void LoadModel(std::string path)`](#LoadModel)
+ - [`void LoadChineseModel(std::string path)`](#LoadChineseModel)
+ - [`void LoadGrayChANN(std::string path)`](#LoadGrayChANN)
+ - [`void LoadChineseMapping(std::string path)`](#LoadChineseMapping)
+ - (private:)
+ - [`CharsIdentify()`](#CharsIdentify)
+
+***
+
+***
diff --git a/easyPR-doc/core/feature.md b/easyPR-doc/core/feature.md
new file mode 100644
index 00000000..d51fd9ce
--- /dev/null
+++ b/easyPR-doc/core/feature.md
@@ -0,0 +1,85 @@
+### feature
+
+#### Functions
+ - [`cv::Mat getHistogram(cv::Mat in)`](#getHistogram)
+ - [`typedef void (*svmCallback)(const cv::Mat& image, cv::Mat& features)`](#svmCallback)
+ - [`typedef void (*annCallback)(const cv::Mat& image, cv::Mat& features)`](#annCallback)
+ - [`void getGrayPlusProject(const cv::Mat& grayChar, cv::Mat& features)`](#getGrayPlusProject)
+ - [`void getHistogramFeatures(const cv::Mat& image, cv::Mat& features)`](#getHistogramFeatures)
+ - [`void getSIFTFeatures(const cv::Mat& image, cv::Mat& features)`](#getSIFTFeatures)
+ - [`void getHOGFeatures(const cv::Mat& image, cv::Mat& features)`](#getHOGFeatures)
+ - [`void getHSVHistFeatures(const cv::Mat& image, cv::Mat& features)`](#getHSVHistFeatures)
+ - [`void getLBPFeatures(const cv::Mat& image, cv::Mat& features)`](#getLBPFeatures)
+ - [`void getColorFeatures(const cv::Mat& src, cv::Mat& features)`](#getColorFeatures)
+ - [`void getHistomPlusColoFeatures(const cv::Mat& image, cv::Mat& features)`](#getHistomPlusColoFeatures)
+ - [`cv::Mat charFeatures(cv::Mat in, int sizeData)`](#charFeatures)
+ - [`cv::Mat charFeatures2(cv::Mat in, int sizeData)`](#charFeatures2)
+ - [`void getLBPplusHistFeatures(const cv::Mat& image, cv::Mat& features)`](#getLBPplusHistFeatures)
+ - [`void getGrayCharFeatures(const cv::Mat& grayChar, cv::Mat& features)`](#getGrayCharFeatures)
+ - [`void getGrayPlusLBP(const Mat& grayChar, Mat& features)`](#getGrayPlusLBP)
+
+***
+
+#### cv::Mat getHistogram(cv::Mat in)
+ - 获得车牌的特征数
+
+
+#### typedef void (*svmCallback)(const cv::Mat& image, cv::Mat& features)
+ - EasyPR的getFeatures回调函数
+ - 用于从车牌的image生成svm的训练特征features
+
+
+#### typedef void (*annCallback)(const cv::Mat& image, cv::Mat& features)
+ - EasyPR的getFeatures回调函数
+ - convert from images to features used by gray char ann
+
+
+#### void getGrayPlusProject(const cv::Mat& grayChar, cv::Mat& features)
+ - gray and project feature
+
+
+#### void getHistogramFeatures(const cv::Mat& image, cv::Mat& features)
+ - EasyPR的getFeatures回调函数
+ - 本函数是获取垂直和水平的直方图图值
+
+
+#### void getSIFTFeatures(const cv::Mat& image, cv::Mat& features)
+ - 本函数是获取SIFT特征子
+
+
+#### void getHOGFeatures(const cv::Mat& image, cv::Mat& features)
+ - 本函数是获取HOG特征子
+
+
+#### void getHSVHistFeatures(const cv::Mat& image, cv::Mat& features)
+ - 本函数是获取HSV空间量化的直方图特征子
+
+
+#### void getLBPFeatures(const cv::Mat& image, cv::Mat& features)
+ - LBP feature
+
+
+#### void getColorFeatures(const cv::Mat& src, cv::Mat& features)
+ - color feature
+
+
+#### void getHistomPlusColoFeatures(const cv::Mat& image, cv::Mat& features)
+ - color feature and histom
+
+
+#### cv::Mat charFeatures(cv::Mat in, int sizeData)
+ - get character feature
+
+
+#### cv::Mat charFeatures2(cv::Mat in, int sizeData)
+ - get character feature
+
+
+#### void getLBPplusHistFeatures(const cv::Mat& image, cv::Mat& features)
+ - LBP feature + Histom feature
+
+
+#### void getGrayCharFeatures(const cv::Mat& grayChar, cv::Mat& features)
+
+
+#### void getGrayPlusLBP(const Mat& grayChar, Mat& features)
diff --git a/easyPR-doc/core/plate.md b/easyPR-doc/core/plate.md
new file mode 100644
index 00000000..6a13154a
--- /dev/null
+++ b/easyPR-doc/core/plate.md
@@ -0,0 +1,16 @@
+### Class
+
+#### Properties
+ - (private:)
+ - [`Mat m_plateMat`](#m_plateMat)
+ - [`RotatedRect m_platePos`](#m_platePos)
+ - [`double m_score`](#m_score)
+
+#### Functions
+
+***
+
+####double m_score
+ - 保存了`SVM`后的分数,越大证明越可能是车牌
+
+***
diff --git a/easyPR-doc/core/plate_detect.md b/easyPR-doc/core/plate_detect.md
new file mode 100644
index 00000000..a789f78c
--- /dev/null
+++ b/easyPR-doc/core/plate_detect.md
@@ -0,0 +1,29 @@
+### Class CPlateDetect
+
+#### Properties
+ - (priavte:)
+ - [`int m_maxPlates`](#m_maxPlates)
+ - [`CPlateLocate* m_plateLocate`](#m_plateLocate)
+ - [`int m_type`](#m_type)
+ - [`static std::string m_pathSvm`](#m_pathSvm)
+ - [`bool m_showDetect`](#m_showDetect)
+
+#### Functions
+ - (public:)
+ - [`int plateDetect(Mat src, s td::vector &resultVec, int type,bool showDetectArea, int img_index = 0)`](#plateDetect1)
+ - [`int plateDetect(Mat src, std::vector &resultVec, int img_index = 0)`](#plateDetect2)
+ - [`void LoadSVM(std::string s)`](#LoadSVM)
+
+***
+
+#### int m_maxPlates(`get|set`)
+
+
+#### CPlateLocate* m_plateLocate
+ - 用于车牌定位的对象,完成了所有车牌定位的操作
+
+
+#### m_type(`set`)
+ -
+
+***
diff --git a/easyPR-doc/core/plate_judge.md b/easyPR-doc/core/plate_judge.md
new file mode 100644
index 00000000..bd24c327
--- /dev/null
+++ b/easyPR-doc/core/plate_judge.md
@@ -0,0 +1,71 @@
+### Class PlateJudge
+
+#### Properties
+ - (private:)
+ - [`static PlateJudge* instance_`](#instance_)
+ - [`svmCallback extractFeature`](#extractFeature)
+ - [`cv::Ptr svm_`](#svm_)
+
+#### Functions
+ - (public:)
+ - [`static PlateJudge* instance()`](#instance)
+ - [`void LoadModel(std::string path)`](#LoadModel)
+ - [`int plateJudgeUsingNMS(const std::vector&, std::vector&, int maxPlates = 5)`](#plateJudgeUsingNMS)
+ - [`int plateSetScore(CPlate& plate)`](#plateSetScore)
+ - [`int plateJudge(const Mat& plateMat)`](#plateJudge1)
+ - [`int plateJudge(const std::vector &inVec,std::vector &resultVec)`](#plateJudge2)
+ - [`int plateJudge(const std::vector &inVec,std::vector &resultVec)`](#plateJudge3)
+ - [`void NMS(std::vector &inVec, std::vector &resultVec, double overlap)`](#NMS)
+ - [`int PlateJudge::plateJudgeUsingNMS(const std::vector &inVec, std::vector &resultVec, int maxPlates)`](#plateJudgeUsingNMS)
+ - (private:)
+ - [`PlateJudge()`](#PlateJudge)
+
+***
+
+#### static PlateJudge* instance_
+ - 静态变量`instance_`,用于单例模式
+
+***
+
+#### static PlateJudge* instance()
+ - 单例模式初始化方法,当`instance_`为`nullptr`时,初始化一个`PlateJudge`
+ - 返回`instance_`
+
+
+#### PlateJudge()
+ - 加载`svm`的模型,在`config.h`中配置模型路径
+ - 可选择是否使用`LBP`模型,因为暂时没有这个模型,所以使用的是`Hist`
+
+
+#### void LoadModel(std::string path)
+ - 输入参数为路径`path`
+ - 如果`path`与默认`kDefaultSvmPath`路径不同,则加载`path`下的模型,如果相同,那么加载的模型和`kDefaultSvmPath`路径下的相同
+
+
+#### int plateSetScore(CPlate& plate)
+ - 这个函数通过`SVM`为输入的`CPlate`计算分数,小于0且越小为车牌的可能性越大
+ - 方法判定`score`大于`0.5`的`CPlate`为不是车牌
+ - 返回值为`0`表示是车牌,返回值为`-1`表示不是车牌
+
+
+#### int plateJudge(const Mat& plateMat)
+ - 调用`plateSetScore`得到`0/-1`并返回,`0`代表是车牌,`1`表示不是车牌
+
+
+#### int plateJudge(const std::vector &inVec,std::vector &resultVec)
+ - 输入为`Mat`的集合`inVec`,代表了需要判断的`Mat`的集合
+ - 输出为`resultVec`,代表了所有可能是车牌的集合
+ - `return 0`
+
+
+#### int plateJudge(const std::vector &inVec,std::vector &resultVec)
+ - 输入为`CPlate`的集合`inVec`,代表了需要判断的`CPlate`的集合
+ - 输出为`resultVec`,代表了所有可能是车牌的集合
+ - 和`int plateJudge(const std::vector &inVec,std::vector &resultVec)`不同的是,在这个方法中会进行一次矩形的缩小再判断
+ - `return 0`
+
+
+#### void NMS(std::vector &inVec, std::vector &resultVec, double overlap)
+
+
+#### int PlateJudge::plateJudgeUsingNMS(const std::vector &inVec, std::vector &resultVec, int maxPlates)
diff --git a/easyPR-doc/core/plate_locate.md b/easyPR-doc/core/plate_locate.md
new file mode 100644
index 00000000..b4109812
--- /dev/null
+++ b/easyPR-doc/core/plate_locate.md
@@ -0,0 +1,198 @@
+### Class CPlateLocate
+
+#### Properties
+ - (protected:)
+ - [`int m_GaussianBlurSize`](#m_GaussianBlurSize)
+ - [`int m_MorphSizeWidth`](#m_MorphSizeWidth)
+ - [`int m_MorphSizeHeight`](#m_MorphSizeHeight)
+ - [`float m_error`](#m_error)
+ - [`float m_aspect`](#m_aspect)
+ - [`int m_verifyMin`](#m_verifyMin)
+ - [`int m_verifyMax`](#m_verifyMax)
+ - [`int m_angle`](#m_angle)
+ - [`bool m_debug`](#m_debug)
+
+#### Functions
+ - (public:)
+ - [`bool CPlateLocate::verifySizes(RotatedRect mr)`](#verifySizes)
+ - [`int CPlateLocate::mserSearch(const Mat &src,vector &out,vector>& out_plateVec, bool usePlateMser, vector>& out_plateRRect,int img_index, bool showDebug)`](#mserSearch)
+ - [`void CPlateLocate::setLifemode(bool param)`](#setLifemode)
+ - [`int CPlateLocate::colorSearch(const Mat &src, const Color r, Mat &out,vector &outRects)`](#colorSearch)
+ - [`int CPlateLocate::sobelFrtSearch(const Mat &src,vector> &outRects)`](#sobelFrtSearch)
+ - [`int CPlateLocate::sobelOper(const Mat &in, Mat &out, int blurSize, int morphW, int morphH)`](#sobelOper)
+ - [`int CPlateLocate::deskew(const Mat &src, const Mat &src_b,vector &inRects,vector &outPlates, bool useDeteleArea, Color color)`](#deskew)
+ - [`bool CPlateLocate::isdeflection(const Mat &in, const double angle,double &slope)`](#isdeflection)
+ - [`bool CPlateLocate::rotation(Mat &in, Mat &out, const Size rect_size, const Point2f center, const double angle)`](#rotation)
+ - [`int CPlateLocate::plateColorLocate(Mat src, vector &candPlates,int index)`](#plateColorLocate)
+ - [`int CPlateLocate::plateMserLocate(Mat src, vector &candPlates, int img_index)`](#plateMserLocate)
+ - [`int CPlateLocate::sobelOperT(const Mat &in, Mat &out, int blurSize, int morphW,int morphH)`](#sobelOperT)
+ - [`int CPlateLocate::plateSobelLocate(Mat src, vector &candPlates,int index)`](#plateSobelLocate)
+ - [`int plateLocate(Mat, std::vector&, int = 0)`](#plateLocate1)
+ - [`int plateLocate(Mat, std::vector&, int = 0)`](#plateLocate2)
+
+***
+
+#### int m_GaussianBlurSize(`get|set`)
+ - 高斯模糊所用的变量
+
+
+#### int m_MorphSizeWidth(`get|set`)
+ - 选定闭操作时的宽度
+
+
+#### int m_MorphSizeHeight(`get|set`)
+ - 选定闭操作时的长度
+
+
+#### float m_error(`get|set`)
+ - 允许的误差比
+
+
+#### float m_aspect(`get|set`)
+ - 车牌的长宽比
+
+
+#### int m_verifyMin(`set`)
+ - 筛选长宽比时的最小比例
+
+
+#### int m_verifyMax(`set`)
+ - 筛选长宽比时的最大比例
+
+
+#### int m_angle(`set`)
+ - 角度判断所用变量,正负超过这个角度的筛选出来的矩形都会被舍弃
+
+
+#### bool m_debug(`get|set`)
+ - 是否开启调试模式,0关闭,非0开启
+
+***
+
+#### bool CPlateLocate::verifySizes(RotatedRect mr)
+ - 输入旋转矩阵`mr`
+ - 函数内部设置了车牌的长宽比,通过长宽比来确定是不是车牌区域
+ - 如果是,就返回true,否则就返回false
+
+
+#### mserSearch(const Mat &src,vector &out,vector>& out_plateVec, bool usePlateMser, vector>& out_plateRRect,int img_index, bool showDebug)
+ - MSER区域提取原理:对图像取阈值在[0,255]之间的灰度化,当选取区域大小最为稳定的区域
+ - mser in opencv
+ - 该函数对输入图像进行了`MSER`区域提取并输出
+
+
+#### void CPlateLocate::setLifemode(bool param)
+ - 如果有`param`传入,对`GaussianBlurSize`等一系列参数进行设置
+ - 如果没有参数传入,就采用默认的参数
+
+
+#### int CPlateLocate::colorSearch(const Mat &src, const Color r, Mat &out,vector &outRects)
+ - 此函数的作用是:对于输入的图片`src`和颜色`r`,对`src`进行`r`的颜色匹配
+ - 匹配流程为(省略具体参数)
+ - `colorMatch`:灰度化
+ - `threshold`:二值化
+ - `getStructuringElement`:规定`10x2`的`kernel`
+ - `morphologyEx`:针对`kernel`进行闭操作(先erode再dilate)
+ - `findContours`:闭操作完寻找轮廓以确定(蓝牌或黄牌)的区域
+ - `out`里存储的是二值化结果,`outRects`里存储的是寻找到的区域
+ - 调用`verifySizes`筛选出符合长宽比的区域
+ - `return 0`
+
+
+#### int CPlateLocate::sobelFrtSearch(const Mat &src,vector> &outRects)
+ - 输入:
+ - 原始图片`Mat &src`
+ - 输出集合`vector> &outRects`
+ - 执行过程
+ - `sobelOper`:对图像进行预处理
+ - `verifySizes`:对处理完的矩形集合进行筛选
+ - 存储到outRects中
+
+
+#### int CPlateLocate::sobelOper(const Mat &in, Mat &out, int blurSize, int morphW, int morphH)
+ - 输入
+ - 原始图片`Mat &in`
+ - 输出图片`Mat &out`
+ - 滤波窗口大小`blurSize`
+ - 闭操作`kernel`的宽度`morphW`
+ - 闭操作`kernel`的长度`morphH`
+ - 函数流程(省略具体参数):
+ - `GaussianBlur`:高斯滤波
+ - `cvtColor`:灰度化
+ - `Sobel`:sobel算子
+ - `threshold`:二值化
+ - `morphologyEx`:闭操作
+ - 将结果`Mat`赋值到`out`里
+ - `return 0`
+
+
+#### int CPlateLocate::deskew(const Mat &src, const Mat &src_b,vector &inRects,vector &outPlates, bool useDeteleArea, Color color)
+ - 输入:
+ - `Mat &src`:原始图片
+ - `Mat &src_b`:二值化后的图片
+ - `vector &inRects`:闭操作识别颜色后的区域矩形块。
+ - `vector &outPlates`:输出`vector`
+ - `bool useDeteleArea`:
+ - `Color color`:输入的颜色(蓝牌或者黄牌)
+ - 对识别的区域进行旋转后,删除其中角度大于`m_angle`的,并对矩形进行划线(0,255,255)(BGR),之后存储到`CPlate类型中`,再保存到`outPlates`中
+
+
+#### bool CPlateLocate::isdeflection(const Mat &in, const double angle,double &slope)
+ - 判断是否倾斜
+
+
+#### bool CPlateLocate::rotation(Mat &in, Mat &out, const Size rect_size, const Point2f center, const double angle)
+ - 判断旋转
+
+
+#### int CPlateLocate::plateColorLocate(Mat src, vector &candPlates,int index)
+ - 输入:
+ - `Mat src`:原始图片,`vector &candPlates`:存储颜色筛选完并旋转的图
+ - 对`src`进行黄牌和蓝牌的并行计算
+ - `return 0`
+
+
+#### int CPlateLocate::plateMserLocate(Mat src, vector &candPlates, int img_index)
+ - 基本操作类似于`color`和`sobel`
+ - 采取的核心算法是`mser`
+ - 最终结果存储在`candPlates`中
+
+
+#### int CPlateLocate::sobelOperT(const Mat &in, Mat &out, int blurSize, int morphW,int morphH)
+ - 输入
+ - 原始图片`Mat &in`
+ - 输出图片`Mat &out`
+ - 滤波窗口大小`blurSize`
+ - 闭操作`kernel`的宽度`morphW`
+ - 闭操作`kernel`的长度`morphH`
+ - 处理等同于[`sobelOper`](#sobelOper),只不过在每一步操作时,都将分步的图片存储到了`/resources/image/tmp/`目录下
+
+
+#### int CPlateLocate::plateSobelLocate(Mat src, vector &candPlates,int index)
+ - 采取sobel算子进行筛选
+ - 输入
+ - `Mat src`:输入图像
+ - `vector &candPlates`:输出图像集合
+ - 执行过程
+ - `sobelFrtSearch`:矩形筛选
+ - 放大矩形区域
+ - 二次切割加入
+ - `deskew`旋转筛选
+ - 存储到`candPlates`中
+
+
+#### int plateLocate(Mat src, std::vector &resultVec, int index = 0)
+ - 输入`src`和`resultVec`
+ - 将`src`进行车牌定位检测,检测到的结果放置到`resultVec`中
+ - 检测过程如下:
+ - `plateColorLocate` | `plateSobelLocate` | `plateMserLocate`
+ - 三种检测手段得到的车牌候选矩形都会被放进`resultVec`中
+ - `resultVec`中放置的类型是`Mat`
+ - `return 0`
+
+
+#### int plateLocate(Mat src, std::vector &resultVec, int = 0)
+ - 输入`src`和`resultVec`
+ - 将`src`进行车牌定位检测,检测到的结果放置到`resultVec`中
+ - `resultVec`中放置的类型是`CPlate`
+ - `return 0`
diff --git a/easyPR-doc/core/plate_recognize.md b/easyPR-doc/core/plate_recognize.md
new file mode 100644
index 00000000..e69de29b
diff --git a/easyPR-doc/easyPR.md b/easyPR-doc/easyPR.md
new file mode 100644
index 00000000..82019f63
--- /dev/null
+++ b/easyPR-doc/easyPR.md
@@ -0,0 +1,10 @@
+### document index
+ - `class Kv`
+ - `class Utils`
+ - `class Generator`
+ - `class plate`
+ - `class CPlateLocate`
+ - `class PlateJudge`
+ - `class CPlateDetect`
+ - `feature`
+ - `config.h`:配置文件
diff --git a/easyPR-doc/img/SVM.png b/easyPR-doc/img/SVM.png
new file mode 100644
index 00000000..e3bda3d8
Binary files /dev/null and b/easyPR-doc/img/SVM.png differ
diff --git a/easyPR-doc/test/main.md b/easyPR-doc/test/main.md
new file mode 100644
index 00000000..e69de29b
diff --git a/easyPR-doc/util/Kv.md b/easyPR-doc/util/Kv.md
new file mode 100644
index 00000000..fd01d8f6
--- /dev/null
+++ b/easyPR-doc/util/Kv.md
@@ -0,0 +1,53 @@
+### Class Kv
+
+#### Properties
+ - [`std::map data_`](#data)
+
+#### Functions
+ - [`Kv()`](#Kv)
+ - [`void load(const std::string &file)`](#load)
+ - [`std::string get(const std::string &key)`](#get)
+ - [`void add(const std::string &key,const std::string &value)`](#add)
+ - [`void remove(const std::string &key)`](#remove)
+ - [`void clear()`](#clear)
+
+***
+
+
+#### std::map< std::string,std::string > data_
+ - 存储了`map< string string >`类型的数据
+
+***
+
+
+#### Kv()
+ - 无
+
+
+#### void load(const std::string &file)
+ - 参数为`file`,即要读入的文件名
+ - 解析之前会先将`data_`清空,即调用`this.clear()`
+ - 内部解析文件,文件的存储格式都为`string(空格)string\n`
+ - 将`space`前的`string`存储在`data_`的第一个`string里`,将空格后的`string`存储在`data_`的第二个`string`里
+
+
+#### std::string get(const std::string &key)
+ - 参数为在`data_`中的`key`
+ - 返回值为`key`对应的`value`
+ - 当`value`不存在时,会打印`[Kv] cannot find ${key}`,并返回`""`
+
+
+#### void add(const std::string &key,const std::string &value)
+ - 参数为`string key`和`string value`
+ - 在`data_`中添加`key:value`
+ - 如果在`data_`中已经存在`key`时,打印`[Kv] find duplicate: %s = %s , ignore\n`
+
+
+#### void remove(const std::string &key)
+ - 参数为`string key`
+ - 删除`data_`中`key`为`string key`的值
+ - 如果没有这个`key`,打印`[Kv] cannot find ${key}`
+
+
+#### void clear()
+ - 执行`data_.clear()`,清空`data_`
diff --git a/easyPR-doc/util/Utils.md b/easyPR-doc/util/Utils.md
new file mode 100644
index 00000000..46975b28
--- /dev/null
+++ b/easyPR-doc/util/Utils.md
@@ -0,0 +1,84 @@
+### Class Utils
+
+#### Properties
+ -
+
+#### Functions
+ - [`static long getTimestamp()`](#getTimestamp)
+ - [`static std::string getFileName(const std::string &path,const bool postfix = false)`](#getFileName)
+ - [`static std::vector splitString(const std::string &str,const char delimiter)`](#splitString)
+ - [`static T min(const T &v1, const T &v2)`](#min)
+ - [`static std::vector getFiles(const std::string &folder,const bool all = true)`](#getFiles)
+ - [`static void print_str_lines(const char** lines)`](#print_str_lines1)
+ - [`static void print_str_lines(const std::initializer_list &lines)`](#print_str_lines2)
+ - [`static void print_file_lines(const std::string &file)`](#print_file_lines)
+ - [`static unsigned int levenshtein_distance(const T &s1, const T &s2)`](#levenshtein_distance)
+ - [`static bool mkdir(const std::string folder)`](#mkdir)
+ - [`static bool imwrite(const std::string &file, const cv::Mat &image)`](#imwrite)
+ - [`(private)static std::size_t get_last_slash(const std::string &path)`](#get_last_slash)
+
+***
+
+***
+
+
+#### long getTimestamp()
+ - windows:
+ - 返回`cv::getTickCount()`,即系统启动到当前的时间
+ - `cv::getTickCount()`经常用于`opencv`下计算代码运行时间
+ - linux:
+ - 使用linux时间结构体`timespes`,`CLOCK_MONOTONIC`为系统启动时间
+ - 以毫秒的形式返回系统启动到当前的时间
+ - macOS:
+ - 使用了1970/1/1来代替计算时间
+
+
+#### std::string getFileName(const std::string &path,const bool postfix = false)
+ - 输入`string &path`:文件名,`bool postfix`:是否需要后缀
+ - 返回文件名(是否有后缀取决于postfix的值)
+
+
+#### static std::vector< std::string > splitString(const std::string &str,const char delimiter)
+ - 输入`string &str`和`const char delimiter`分隔符
+ - 返回`vector`,存储了用分隔符分割的字符串
+
+
+#### static T min(const T &v1, const T &v2)
+ - 返回`(v1 < v2) ? v1 : v2`;
+
+
+#### static std::vector< std::string > getFiles(const std::string &folder,const bool all = true)
+ - 输入`string &folder`:目录,`bool all`:是否搜索子目录
+ - 返回`vector`:文件的集合
+
+
+#### static void print\_str\_lines(const char** lines)
+ - 打印行
+
+
+#### static void print\_str\_lines(const std::initializer_list &lines)
+ - 打印行
+
+
+#### static void print\_file\_lines(const std::string &file)
+ - 读取`file`中的内容,并打印
+
+
+#### static unsigned int levenshtein_distance(const T &s1, const T &s2)
+ - 输入两个`T`类型`&s1`和`&s2`
+ - 返回这两个数据的编辑距离(Levenshtein Distance),即从s1转化到s2需要的最小步数.
+
+
+#### static bool mkdir(const std::string folder)
+ - 输入`string folder`:需要创建的目录
+ - 返回:`bool`,表示创建成功或者失败
+
+
+#### static bool imwrite(const std::string &file, const cv::Mat &image)
+ - 输入`string &file`:路径,`Mat &image`:图片
+ - 输出:是否存储成功
+
+
+#### std::size\_t get\_last\_slash(const std::string &path)
+ - 输入一个`string &path`,代表了路径
+ - 返回路径`/`最后的文件名的位置
diff --git a/easyPR-doc/util/program_options.md b/easyPR-doc/util/program_options.md
new file mode 100644
index 00000000..57eabf53
--- /dev/null
+++ b/easyPR-doc/util/program_options.md
@@ -0,0 +1,157 @@
+### Class:
+ - [Class Row](#Row)
+ - [Class Subroutine](#Subroutine)
+ - [Class Generator](#Generator)
+
+
+### Class Row
+
+#### Properties
+ - `(private)`:
+ - [`bool require_value`](#require_value)
+ - [`std::string option_short`](#option_short)
+ - [`std::string option_long`](#option_long)
+ - [`std::string default_value`](#default_value)
+ - [`std::string description`](#description)
+ - `(public)`:
+ - [`enum Field { kShort, kLong, kDefault, kDescription }`](#Field)
+ - [`typedef std::initializer_list Order`](#Order)
+
+#### Functions
+ - `(public)`:
+ - [`Row()`](#Row)
+ - [`inline std::string oshort() const { return option_short; }`](#oshort_get)
+ - [`inline std::string olong() const { return option_long; }`](#olong_get)
+ - [`inline std::string value() const { return default_value; }`](#value_get)
+ - [`inline std::string desc() const { return description; }`](#desc_get)
+ - [`inline bool required() const { return require_value; }`](#required_get)
+ - [`inline void oshort(const std::string& oshort) { option_short = oshort; }`](#oshort_set)
+ - [`inline void olong(const std::string& olong) { option_long = olong; }`](#olong_set)
+ - [`inline void value(const std::string& value) { default_value = value; }`](#value_set)
+ - [`inline void desc(const std::string& desc) { description = desc; }`](#desc_set)
+ - [`inline void required(bool required) { require_value = required; }`](#required_set)
+***
+ -
+***
+
+
+### Class Subroutine
+
+#### Properties
+ - `(public)`:
+ - [`typedef std::vector Usages`](#Usages)
+ - [`typedef std::initializer_list TemplateValue`](#TemplateValue)
+ - [`typedef std::vector TemplateValues`](#TemplateValues)
+ - `(private)`:
+ - [`Usages usages_`](#usages_)
+ - [`TemplateValues templates_`](#templates_)
+ - [`const char* first_line_`](#first_line_)
+ - [`const char* description_`](#description_)
+ - [`std::string name_`](#name_)
+ - [`std::string template_str_`](#template_str_)
+ - [`Row::Order order_`](#order_)
+
+#### Functions
+ - `(public)`:
+ - [`Subroutine()`](#Subroutine1)
+ - [`Subroutine(const char* name, const char* description)`](#Subroutine2)
+ - [`inline void add_usage_line(const Row& row) { usages_.push_back(row); }`](#add_usage_line1)
+ - [`inline void add_usage_line(const TemplateValue& row) {templates_.push_back(row);}`](#add_usage_line2)
+ - [`inline void set_first_line(const char* line) { first_line_ = line; }`](#set_first_line)
+ - [`inline void set_description(const char* desc) { description_ = desc; }`](#set_description)
+ - [`inline void set_template(const char* tstr, const Row::Order& order)`](#set_template)
+ - [`inline std::string to_string()`](#to_string)
+ - [`inline std::string get_name() const { return name_; }`](#get_name)
+ - [`inline const char* get_description() const { return description_; }`](#get_description)
+ - [`inline const char* get_first_line() const { return first_line_; }`](#get_first_line)
+ - [`inline Usages::iterator begin() { return usages_.begin(); }`](#begin)
+ - [`inline Usages::iterator end() { return usages_.end(); }`](#end)
+ - [`inline size_t size() { return usages_.size(); }`](#size)
+ - [`inline Row& at(size_t i) { return usages_.at(i); }`](#at)
+ - [`inline const Usages& get_usage() const { return usages_; }`](#get_usage)
+ - [`inline static const char* get_default_name() { return "EmptySubroutine"; }`](#get_default_name)
+ - `(private)`:
+ - [`friend std::ostream& operator<<(std::ostream& out, Subroutine& subroutine)`](#operator_subroutine)
+ - [`void print_with_row(std::ostream& out)`](#print_with_row)
+ - [`void print_with_template(std::ostream& out)`](#print_with_template)
+***
+
+***
+
+#### Subroutine()
+
+
+#### Subroutine(const char* name, const char* description)
+ - //need to confirm
+
+
+### Class Generator
+
+#### Properties
+ - [`typedef std::map SubroutineCollection`](#SubroutineCollection)
+ - [`(private)const char kDelimiter`](#kDelimiter)
+ - [`(private)SubroutineCollection subroutines_`](#subroutines)
+ - [`(private)std::string current_subroutine_`](#current_subroutine_)
+ - [`(private)Parser* parser_`](#parser_)
+
+#### Functions
+ - (`public:`)
+ - [`Generator()`](#Generator)
+ - [`~Generator()`](#~Generator)
+ - [`Generator& make_usage(const char* first_line)`](#make_usage)
+ - [`Parser* make_parser()`](#make_parser)
+ - [`Generator& add_subroutine(const char* name)`](#add_subroutine1`)
+ - [`Generator& add_subroutine(const char* name, const char* description)`](#add_subroutine2)
+ - [`std::map get_subroutine_list()`](#get_subroutine_list)
+ - [`inline std::string to_string()`](#to_string)
+ - [`inline Generator& operator()(const char* option, const char* description)`](#operator1)
+ - [`inline Generator& operator()(const char* option, const char* default_value,const char* description)`](#operator2)
+ - [`inline Subroutine& operator()(const char* name)`](#operator3)
+ - [`inline Generator& make_template(const char* template_str,const Row::Order& order)`](#operator4)
+ - (`private:`)
+ - [`(private)inline Subroutine* get_subroutine()`](#get_subroutine)
+ - [`(private)friend std::ostream& operator<<(std::ostream& out, Generator& generator)`](#operator5)
+ - [`(private)bool add_usage_line(const char* option,const char* default_value,const char* description)`](#add_usage_line)
+
+***
+
+#### typedef std::map SubroutineCollection
+ - 用于存储`[string:Subroutine]`的`map`:`SubroutineCollection`
+
+
+#### (private)SubroutineCollection subroutines_
+ - `SubroutineCollection`类型,用来存储`Subroutine`集合
+
+
+#### (private)std::string current_subroutine_
+ - 表示当前子程序
+
+
+#### (private)Parser* parser_
+ - 在构造方法中被初始化为`nullptr`
+
+***
+
+#### Generator()
+ - 向`subroutines_`添加一条["EmptySubroutine",new Subroutine("EmptySubroutine","")]
+
+
+#### Generator& make_usage(const char* first_line)
+ - 获取当前`current_subroutine_`在`subroutines_`中对应的`Subroutine`
+ - 将上述的`Subroutine`的属性`first_line`设置成输入的参数`first_line`
+ - 返回`*this`
+
+#### Generator& add_subroutine(const char* name)
+ - 执行`add_subroutine(name, "")`
+ - 执行`return *this`,返回当前`Generator`
+
+
+#### Generator& add_subroutine(const char* name, const char* description)
+ - 查找`subroutines_`中有没有子程序`name`
+ - 如果有,则`return *this`
+ - 如果没有,则将`[name:new Subroutine(name,description)]`添加到`subroutines_`中
+
+
+#### inline Subroutine* get_subroutine(){return subroutines_.at(current_subroutine_);}
+ - 输入`current_subroutine_`
+ - 返回`subroutines`中`current_subroutine_`对应的`Subroutine`,即当前指令