OpenCV

OpenCV 部分库函数整理。

OpenCV Tutorials

1. 寻找(二值)图像块轮廓:findContours()

1
2
3
4
5
6
7
8
9
10
#include <opencv2/imgproc.hpp>

void cv::findContours(
InputOutputArray image,
OutputArrayOfArrays contours,
OutputArray hierarchy, // 有重载函数去除了此参数
int mode,
int method,
Point offset = Point()
);
  • image:单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过 Canny、拉普拉斯等边缘检测算子处理过的二值图像。
  • contours:定义为 vector<vector<cv::Point>> contours,是一个双重向量,向量内每个元素保存了一组由连续的 Point 点构成的点的集合的向量,每一组 Point 点集就是一个轮廓。contours 的大小为轮廓的数量。
  • hierarchy:定义为 vector<Vec4i> hierarchyVec4i 的定义为 typedef Vec<int, 4> Vec4i,即向量内每一个元素包含了 4 个 int 型变量的向量。hierarchy 向量内每个元素保存了一个包含 4 个 int 整型的数组。 hiararchy 内的元素和轮廓向量 contours 内的元素是一一对应:hierarchy 内每一个元素的 4 个 int 型变量—— hierarchy[i][0] ~ hierarchy[i][3],分别表示第 i 个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则 hierarchy[i][0] ~ hierarchy[i][3] 的相应位被设置为默认值-1。
  • mode:轮廓的检索模式:
    • CV_RETR_EXTERNAL:只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略;
    • CV_RETR_LIST:检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,即不存在父轮廓或内嵌轮廓,所以 hierarchy 向量内所有元素的第 3、4 个分量都会被置为 -1;
    • CV_RETR_CCOMP:检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层;
    • CV_RETR_TREE:检测所有轮廓,所有轮廓建立一个等级树结构,外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。
  • method:轮廓的近似方法:
    • CV_CHAIN_APPROX_NONE:保存物体边界上所有连续的轮廓点到 contours 内;
    • CV_CHAIN_APPROX_SIMPLE:仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入 contours 内,拐点与拐点之间直线段上的信息点不予保留;
    • CV_CHAIN_APPROX_TC89_L1, CV_CHAIN_APPROX_TC89_KCOS:使用 teh-Chinl chain 近似算法。
  • offset:Point 偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,Point 可以是负值。
  • ref:https://blog.csdn.net/dcrmg/article/details/51987348

2. 图像二值化

2.1 图像颜色转化:cvtColor()

1
2
3
4
5
6
7
8
#include <opencv2/imgproc.hpp>

void cv::cvtColor(
InputArray src,
OutputArray dst,
int code,
int dstCn = 0
);
  • src:原始图像,格式为 8-bit unsigned / 16-bit unsigned / single-precision floating-point。

  • dst:目标图像:size 与 depth 和原始图像要相等。

  • code:色彩空间转换码。常用转换码包括:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    cv::COLOR_BGR2BGRA  // add alpha channel to RGB or BGR image
    cv::COLOR_RGB2RGBA
    cv::COLOR_BGRA2BGR
    cv::COLOR_RGBA2RGB
    cv::COLOR_BGR2RGBA
    cv::COLOR_RGB2BGRA
    cv::COLOR_RGBA2BGR
    cv::COLOR_BGRA2RGB
    cv::COLOR_BGR2RGB
    cv::COLOR_RGB2BGR
    cv::COLOR_BGRA2RGBA
    cv::COLOR_RGBA2BGRA
    cv::COLOR_BGR2GRAY
    cv::COLOR_RGB2GRAY // RGB to grayscale
    cv::COLOR_GRAY2BGR
    cv::COLOR_GRAY2RGB
    cv::COLOR_GRAY2BGRA
    cv::COLOR_GRAY2RGBA
    cv::COLOR_BGRA2GRAY
    cv::COLOR_RGBA2GRAY
  • dstCn:目标图像的通道数,此参数为 0 时,目标图像的通道数由原始图像自动生成。

  • ref:https://blog.csdn.net/duwangthefirst/article/details/79956616

2.2 二值化:threshold()

1
2
3
4
5
6
7
8
9
#include <opencv2/imgproc.hpp>

double cv::threshold(
InputArray src,
OutputArray dst,
double thresh,
double maxval,
int type
);
  • src:源图像,可以为 8 位的灰度图,也可以为 32 位的彩色图像。

  • dst:输出图像。

  • thresh:阈值。

  • maxval:dst 中的最大值。

  • type:阈值类型,包含:

    1
    2
    3
    4
    5
    6
    7
    8
    cv::THRESH_BINARY      // 二值化
    cv::THRESH_BINARY_INV // 二值化
    cv::THRESH_TRUNC
    cv::THRESH_TOZERO
    cv::THRESH_TOZERO_INV
    cv::THRESH_MASK
    cv::THRESH_OTSU // 使用 OTSU 算法选择最佳阈值
    cv::THRESH_TRIANGLE // 使用 Triangle 算法选择最佳阈值

    dstBINARY(x,y)={maxval,if src(x,y)>thresh0,otherwisedstBINARY_INV(x,y)={0,if src(x,y)>threshmaxval,otherwisedstTRUNC(x,y)={thresh,if src(x,y)>threshsrc(x,y),otherwisedstTOZERO(x,y)={src(x,y),if src(x,y)>thresh0,otherwisedstTOZERO_INV(x,y)={0,if src(x,y)>threshsrc(x,y),otherwise\begin{aligned} &dst_{BINARY}(x, y) = \begin{cases} maxval, &\text{if } src(x, y) > thresh \\ 0, &\text{otherwise} \end{cases} \\ &dst_{BINARY\_INV}(x, y) = \begin{cases} 0, &\text{if } src(x, y) > thresh \\ maxval, &\text{otherwise} \end{cases} \\ &dst_{TRUNC}(x, y) = \begin{cases} thresh, &\text{if } src(x, y) > thresh \\ src(x, y), &\text{otherwise} \end{cases} \\ &dst_{TOZERO}(x, y) = \begin{cases} src(x, y), &\text{if } src(x, y) > thresh \\ 0, &\text{otherwise} \end{cases} \\ &dst_{TOZERO\_INV}(x, y) = \begin{cases} 0, &\text{if } src(x, y) > thresh \\ src(x, y), &\text{otherwise} \end{cases} \end{aligned}

  • ref:https://blog.csdn.net/u012566751/article/details/77046445

3. 判断点是否在多边形(轮廓)内

1
2
3
4
5
6
7
#include <opencv2/imgproc.hpp>

double cv::pointPolygonTest(
InputArray contour,
cv::Point2f pt,
bool measureDist
);
  • contour:类型为 vector<cv::Point>,即多边形的轮廓。
  • pt:需要判断的点。
  • measureDist:设置为 true 时,返回值为点到最近的多边形轮廓的距离,若返回正值,则表示点在多边形内部;若返回负值,则点在多边形外部;若返回 0,则点在多边形上。设置为 false 时,若返回值为 +1,则表示点在多边形内部;返回值为 -1,点在多边形外;返回 0,点在多边形上。

4. 图像的条件复制

1
2
3
4
5
6
7
8
9
10
11
#include <opencv2/core/mat.hpp>

// cv::Mat src;
// cv::Mat dst;
// cv::Mat mask;
// src.copyTo(dst, mask);

void cv::Mat::copyTo(
OutputArray m,
InputArray mask // 重载函数没有这个参数,表示仅将矩阵复制到 m
)
  • m:目标矩阵,如果源矩阵和目标矩阵大小不同,则重新分配目标矩阵的大小。
  • mask:和源矩阵大小相同,其中非零元素的坐标表示源图像中需要被复制到目标图像的像素坐标。类型应为 CV_8U,可以有 1 个或多个通道。

5. 计算本质矩阵

5.1 本质矩阵-1

1
2
3
4
5
6
7
8
9
10
11
12
#include <opencv2/calib3d.hpp>

cv::Mat cv::findEssentialMatrix(
InputArray points1,
InputArray points2,
InputArray cameraMatrix,
int method = cv::RANSAC,
double prob = 0.999,
double threshold = 1.0,
int maxIters = 1000,
OutputArray mask = cv::NoArray()
);
  • points1:从第一张图像来的 N(N>5)N(N>5) 个 2D 点,点坐标为浮点数。
  • points2:与 points1 相同格式和数量的第二张图像的 2D 点。
  • cameraMatrix:相机内参矩阵。函数假设 points1points2 为来自同一相机内参的特征点。
  • method:计算本质矩阵的方法:
    • cv::RANSAC
    • cv::LMEDS
  • prob:用于 RANSAC 法和 LMedS 法,表示预期计算得到的矩阵的置信度。
  • threshold:用于 RANSAC 法的参数,表示点到极线到像素距离阈值,如果大于此值,则点被视为离群点,通常设为 1.0 - 3.0。
  • maxIters:最大迭代次数。
  • mask:输出 NN 个元素,每个元素对应一个点是否为离群点,是则值为 0,否则值为 1。用于 RANSAC 法和 LMedS 法。

5.2 本质矩阵-2

1
2
3
4
5
6
7
8
9
cv::Mat cv::findEssentialMat(
InputArray points1,
InputArray points2,
InputArray cameraMatrix,
int method,
double prob,
double threshold,
OutputArray mask
);
  • 重载函数,仅与第一个函数的参数不同,即不手动设置迭代最大上限。

5.3 本质矩阵-3

1
2
3
4
5
6
7
8
9
10
11
cv::Mat cv::findEssentialMat(
InputArray points1,
InputArray points2,
double focal = 1.0,
cv::Point2d pp = cv::Point2d(0, 0),
int method = cv::RANSAC,
double prob = 0.999,
double threshold = 1.0,
int maxIters = 1000,
OutputArray mask = cv::NoArray()
);
  • focal:相机焦距,此函数假设 points1points2 来自同意相机焦距和原点。

  • pp:相机原点。

  • 根据上述参数计算相机内参:

    K=[focal0xpp0focalypp001]K = \left[ \begin{matrix} focal &0 &x_{pp} \\ 0 &focal &y_{pp} \\ 0 &0 & 1 \end{matrix} \right]

  • 其他参数同上。

5.4 本质矩阵-4

1
2
3
4
5
6
7
8
9
10
cv::Mat cv::findEssentialMat(
InputArray points1,
InputArray points2,
double focal,
cv::Point2d pp,
int method,
double prob,
double threshold,
OutputArray mask
);
  • 前一函数的重载,不手动设置迭代最大上限。

5.5 本质矩阵-5

1
2
3
4
5
6
7
8
9
10
11
12
cv::Mat cv::findEssentialMat(
InputArray points1,
InputArray points2,
InputArray cameraMatrix1,
InputArray distCoeffs1,
InputArray cameraMatrix2,
InputArray distCoeffs2,
int method = cv::RANSAC,
double prob = 0.999,
double threshold = 1.0,
OutputArray mask = cv::NoArray()
);
  • 函数计算来自两个不同相机的图像间的本质矩阵。
  • distCoeffs:畸变系数,为 4、5、8、12 和 14 元素的向量(k1,k2,p1,p2[,k3[,k4,k5,k6[,s1,s2,s3,s4[,τx,τy]]]]k_1, k_2, p_1, p_2 [, k_3 [, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4 [, \tau_x, \tau_y]]]]),若向量为空(NULL),则为 0 畸变。

5.6 本质矩阵-6

1
2
3
4
5
6
7
8
9
10
cv::Mat cv::findEssentialMat(
InputArray points1,
InputArray points2,
InputArray cameraMatrix1,
InputArray cameraMatrix2,
InputArray distCoeffs1,
InputArray distCoeffs2,
OutputArray mask,
const cv::UsacParams & params
);
  • 前一函数的重载。

6. 计算基础矩阵

6.1 基础矩阵-1

1
2
3
4
5
6
7
8
9
10
11
#include <opencv2/calib3d.hpp>

cv::Mat findFundamentalMat(
InputArray points1,
InputArray points2,
int method,
double ransacReprohThreshold,
double confidence,
int maxIters,
OutputArray mask = cv::NoArray()
);
  • points1:从第一张图像来的 NN 个 2D 点,点坐标为浮点数。
  • points2:与 points1 相同格式和数量的第二张图像的 2D 点。
  • method:计算基础矩阵的方法:
    • cv::FM_7POINT:7 点法,N=7N=7
    • cv::FM_8POINT:8 点法,N=8N=8
    • cv::RANSAC
    • cv::LEMDS
  • ransacReprohThreshold:用于 RANSAC 法的参数,表示点到极线到像素距离阈值,如果大于此值,则点被视为离群点,通常设为 1.0 - 3.0。
  • confidence:用于 RANSAC 法和 LMedS 法,表示预期计算得到的矩阵的置信度。
  • maxIters:最大迭代次数。
  • mask:优化的输出掩码。

6.2 基础矩阵-2

1
2
3
4
5
6
7
8
cv::Mat findFundamentalMat(
InputArray points1,
InputArray points2,
int method = cv::FM_RANSAC,
double ransacReprohThreshold = 3.,
double confidence = 0.99,
OutputArray mask = cv::NoArray()
);
  • 前一函数的重载函数,不手动设置最大迭代次数。

6.3 基础矩阵-3

1
2
3
4
5
6
7
8
cv::Mat findFundamentalMat(
InputArray points1,
InputArray points2,
OutputArray mask,
int method = cv::FM_RANSAC,
double ransacReprohThreshold = 3.,
double confidence = 0.99
);
  • 前一函数的重载函数,mask 为必传参数。

6.4 基础矩阵-4

1
2
3
4
5
6
cv::Mat findFundamentalMat(
InputArray points1,
InputArray points2,
OutputArray mask,
const cv::UsacParams & params
);
  • 前一函数的重载函数。

7. 单应矩阵

7.1 单应矩阵-1

1
2
3
4
5
6
7
8
9
10
11
#include <opencv2/calib3d.hpp>

cv::Mat cv::findHomographyMat(
InputArray srcPoints,
InputArray dstPoints,
int method = 0,
double ransacReprojThreshold = 3.,
OutputArray mask = cv::NoArray(),
const int maxIters = 2000,
const double confidence = 0.995
);
  • srcPoints:从源图像来的点,是一个类型为 cv::CV_32FC2 的矩阵或 vector<cv::Point2f> 的向量。

  • dstPoints:来自目标图像的点,类型同上。

  • method:计算单应矩阵的方法:

    • 0:使用所有点通过最小二乘法计算。

    • cv::RANSAC

    • cv::LMEDS

    • cv::RHO

  • ransacReprojThreshold:判断点为内点(inlier)的最大重投影误差,即如果

    dstPointsiconvertHomogeneous(HsrcPointsi)2>threshold\| dstPoints_i - \operatorname{convertHomogeneous}(H \cdot srcPoints_i) \|_2 > threshold

    则第 ii 个点为离群点。如果特征点为像素坐标,则通常值设为 1.0 - 10.0。

  • confidence:预期计算得到的矩阵的置信度。

  • maxIters:最大迭代次数。

  • mask:输出 NN 个元素,每个元素对应一个点是否为离群点,是则值为 0,否则值为 1。用于 RANSAC 法和 LMedS 法。

7.2 单应矩阵-2

1
2
3
4
5
6
7
cv::Mat cv::findHomographyMat(
InputArray srcPoints,
InputArray dstPoints,
OutputArray mask,
int method = 0,
double ransacReprojThreshold = 3.,
);
  • 前一函数的重载函数。

7.3 单应矩阵-3

1
2
3
4
5
6
cv::Mat cv::findHomographyMat(
InputArray srcPoints,
InputArray dstPoints,
OutputArray mask,
const cv::UsacParams & params
);
  • 重载函数。

8. 本质矩阵进行位姿求解

8.1 本质矩阵求解位姿-1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <opencv2/calib3d.hpp>

int cv::recoverPose(
InputArray points1,
InputArray points2,
InputArray cameraMatrix1,
InputArray distCoeffs1,
InputArray cameraMatrix2,
InputArray distCoeffs2,
OutputArray E,
OutputArray R,
OutputArray t,
int method = cv::RANSAC,
double prob = 0.999,
double threshold = 1.0,
InputOutputArray mask = cv::NoArray()
);
  • points1:从第一张图像来的 N(N>5)N(N>5) 个 2D 点,点坐标为浮点数。
  • points2:与 points1 相同格式和数量的第二张图像的 2D 点。
  • cameraMatrix:相机内参矩阵。函数假设图像来自两个不同的相机。
  • distCoeffs:畸变系数,为 4、5、8、12 和 14 元素的向量(k1,k2,p1,p2[,k3[,k4,k5,k6[,s1,s2,s3,s4[,τx,τy]]]]k_1, k_2, p_1, p_2 [, k_3 [, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4 [, \tau_x, \tau_y]]]]),若向量为空(NULL),则为 0 畸变。
  • E:输出的本质矩阵。
  • R:输出的旋转矩阵,结果表述为 R21R_{21},即将第 2 张图像的相机坐标转为第 1 张图像的相机坐标。
  • t:输出的平移向量,结果表述为 t21t_{21}
  • method:计算本质矩阵的方法:
    • cv::RANSAC
    • cv::LMEDS
  • prob:用于 RANSAC 法和 LMedS 法,表示预期计算得到的矩阵的置信度。
  • threshold:用于 RANSAC 法的参数,表示点到极线到像素距离阈值,如果大于此值,则点被视为离群点,通常设为 1.0 - 3.0。
  • maxIters:最大迭代次数。
  • mask:作为输入如果非空,则标识了根据输入本质矩阵所规定的 points1points2 中的内点(inliers),只有这些点参与求解位姿。输出 NN 个元素,每个元素对应一个点是否为离群点,是则值为 0,否则值为 1。用于 RANSAC 法和 LMedS 法。

8.2 本质矩阵求解位姿-2

1
2
3
4
5
6
7
8
9
int cv::recoverPose(
InputArray E,
InputArray points1,
InputArray points2,
InputArray cameraMatrix,
OutputArray R,
OutputArray t,
InputOutputArray mask = cv::NoArray()
);
  • 根据给定的本质矩阵求解位姿。
  • E:输入的本质矩阵。
  • points1:从第一张图像来的 N(N>5)N(N>5) 个 2D 点,点坐标为浮点数。
  • points2:与 points1 相同格式和数量的第二张图像的 2D 点。
  • cameraMatrix:相机内参矩阵。函数假设图像来自相同的相机。
  • R:输出的旋转矩阵,结果表述为 R21R_{21},即将第 2 张图像的相机坐标转为第 1 张图像的相机坐标。
  • t:输出的平移向量,结果表述为 t21t_{21}
  • method:计算本质矩阵的方法:
    • cv::RANSAC
    • cv::LMEDS
  • mask:作为输入如果非空,则标识了根据输入本质矩阵所规定的 points1points2 中的内点(inliers),只有这些点参与求解位姿。输出 NN 个元素,每个元素对应一个点是否为离群点,是则值为 0,否则值为 1。用于 RANSAC 法和 LMedS 法。

8.3 本质矩阵求解位姿-3

1
2
3
4
5
6
7
8
9
10
int cv::recoverPose(
InputArray E,
InputArray points1,
InputArray points2,
OutputArray R,
OutputArray t,
double focal = 1.0,
cv::Point2d pp = cv::Point2d(0, 0),
InputOutputArray mask = cv::NoArray()
);
  • 前一函数的重载函数,利用给定的参数计算相机内参矩阵:

    K=[focal0xpp0focalypp001]K = \left[ \begin{matrix} focal &0 &x_{pp} \\ 0 &focal &y_{pp} \\ 0 &0 & 1 \end{matrix} \right]

8.4 本质矩阵求解位姿-4

1
2
3
4
5
6
7
8
9
10
int cv::recoverPose(
InputArray E,
InputArray points1,
InputArray points2,
OutputArray R,
OutputArray t,
double distanceThresh,
InputOutputArray mask = cv::NoArray(),
OutputArray triangulatedPoints = cv::NoArray()
);
  • distanceThresh:用于过滤距离过远的点。
  • triangulatedPoints:三角化求解得到的 3D 点。

9. PnP

9.1 普通 PnP

1
2
3
4
5
6
7
8
9
10
11
12
#include <opencv2/calib3d.hpp>

bool cv::solvePnP(
InputArray objectPoints,
InputArray imagePoints,
InputArray cameraMatrix,
InputArray distCoeffs,
OutputArray rvec,
OutputArray tvec,
bool useExtrinsicGuess = false,
int flags = cv::SOLVEPNP_ITERATIVE
);
  • objectPoints:对象坐标系下的点,大小为 N×3,1channelN \times 3, 1-channel1×N/N×1,3channels1 \times N / N \times 1, 3 - channels。通常可以可以使用 vector<cv::Point3d>

  • imagePoints:对应的相机坐标系下的图像点,大小为 N×2,1channelN \times 2, 1-channel1×N/N×1,2channels1 \times N / N \times 1, 2 - channels。通常可以可以使用 vector<cv::Point2d>

  • cameraMatrix:相机内参矩阵。

  • distCoeffs:畸变系数,为 4、5、8、12 和 14 元素的向量(k1,k2,p1,p2[,k3[,k4,k5,k6[,s1,s2,s3,s4[,τx,τy]]]]k_1, k_2, p_1, p_2 [, k_3 [, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4 [, \tau_x, \tau_y]]]]),若向量为空(NULL),则为 0 畸变。

  • rvec:输出旋转矩阵对应的旋转向量,将对象坐标系下的点转为相机坐标系。使用下方法转为矩阵形式:

    1
    2
    3
    4
    5
    6
    7
    #include <opencv2/calib3d.hpp>

    void cv::Rodrigues(
    InputArray src, // 旋转向量
    OutputArray dst, // 旋转矩阵
    OutputArray jacobian = cv::NoArray()
    );

    jacobian:可选输出的雅可比矩阵,大小为 3×93 \times 99×39 \times 3,表示输出矩阵相对输入向量的部分导。

  • tvec:输出的位姿的平移向量部分。

  • useExtrinsicGuess:用于 cv::SOLVEPNP_ITERATIVE 的参数,若为 true,则用给定的旋转和初始值进行优化求解。

  • flags:求解 PnP 问题的方式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    cv::SOLVEPNP_ITERATIVE
    cv::SOLVEPNP_P3P
    cv::SOLVEPNP_AP3P
    cv::SOLVEPNP_EPNP
    cv::SOLVEPNP_DLS
    cv::SOLVEPNP_IPPE
    cv::SOLVEPNP_IPPE_SQUARE
    cv::SOLVEPNP_UPNP
    cv::SOLVEPNP_SQPNP

9.2 通用算法求解 PnP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <opencv2/calib3d.hpp>

bool cv::solvePnPGeneric(
InputArray objectPoints,
InputArray imagePoints,
InputArray cameraMatrix,
InputArray distCoeffs,
OutputArrayOfArrays rvecs,
OutputArrayOfArrays tvecs,
bool useExtrinsicGuess = false,
int flags = cv::SOLVEPNP_ITERATIVE,
InputArray rvec = cv::NoArray(),
InputArray tvec = cv::NoArray(),
OutputArray reprojectionError = cv::NoArray()
);
  • objectPoints:对象坐标系下的点,大小为 N×3,1channelN \times 3, 1-channel1×N/N×1,3channels1 \times N / N \times 1, 3 - channels。通常可以可以使用 vector<cv::Point3d>

  • imagePoints:对应的相机坐标系下的图像点,大小为 N×2,1channelN \times 2, 1-channel1×N/N×1,2channels1 \times N / N \times 1, 2 - channels。通常可以可以使用 vector<cv::Point2d>

  • cameraMatrix:相机内参矩阵。

  • distCoeffs:畸变系数,为 4、5、8、12 和 14 元素的向量(k1,k2,p1,p2[,k3[,k4,k5,k6[,s1,s2,s3,s4[,τx,τy]]]]k_1, k_2, p_1, p_2 [, k_3 [, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4 [, \tau_x, \tau_y]]]]),若向量为空(NULL),则为 0 畸变。

  • rvecs:输出旋转矩阵对应的旋转向量,将对象坐标系下的点转为相机坐标系。使用下方法转为矩阵形式:

    1
    2
    3
    4
    5
    6
    7
    #include <opencv2/calib3d.hpp>

    void cv::Rodrigues(
    InputArray src, // 旋转向量
    OutputArray dst, // 旋转矩阵
    OutputArray jacobian = cv::NoArray()
    );

    jacobian:可选输出的雅可比矩阵,大小为 3×93 \times 99×39 \times 3,表示输出矩阵相对输入向量的部分导。

  • tvecs:输出的位姿的平移向量部分。

  • useExtrinsicGuess:用于 cv::SOLVEPNP_ITERATIVE 的参数,若为 true,则用给定的旋转和初始值进行优化求解。

  • flags:求解 PnP 问题的方式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    cv::SOLVEPNP_ITERATIVE
    cv::SOLVEPNP_P3P
    cv::SOLVEPNP_AP3P
    cv::SOLVEPNP_EPNP
    cv::SOLVEPNP_DLS
    cv::SOLVEPNP_IPPE
    cv::SOLVEPNP_IPPE_SQUARE
    cv::SOLVEPNP_UPNP
    cv::SOLVEPNP_SQPNP
  • rvec:当使用 cv::SOLVEPNP_ITERATIVEuseExtrinsicGuess = true 时的迭代初始旋转向量。

  • tvec:当使用 cv::SOLVEPNP_ITERATIVEuseExtrinsicGuess = true 时的迭代初始平移向量。

  • reprojectionError:根据求解得到的位姿计算得到的图像点和 3D 对象点的重投影 RMS 误差。

9.3 RANSAC 法求解 PnP

9.3.1 RANSAC 法-1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <opencv2/calib3d.hpp>

bool cv::solvePnPRansac(
InputArray objectPoints,
InputArray imagePoints,
InputArray cameraMatrix,
InputArray distCoeffs,
OutputArray rvec,
OutputArray tvec,
bool useExtrinsicGuess = false,
int iterationsCount = 100,
float reprojectionError = 8.0,
double confidence = 0.99,
OutputArray inliers = cv::NoArray(),
int flags = cv::SOLVEPNP_ITERATIVE
);
  • objectPoints:对象坐标系下的点,大小为 N×3,1channelN \times 3, 1-channel1×N/N×1,3channels1 \times N / N \times 1, 3 - channels。通常可以可以使用 vector<cv::Point3d>

  • imagePoints:对应的相机坐标系下的图像点,大小为 N×2,1channelN \times 2, 1-channel1×N/N×1,2channels1 \times N / N \times 1, 2 - channels。通常可以可以使用 vector<cv::Point2d>

  • cameraMatrix:相机内参矩阵。

  • distCoeffs:畸变系数,为 4、5、8、12 和 14 元素的向量(k1,k2,p1,p2[,k3[,k4,k5,k6[,s1,s2,s3,s4[,τx,τy]]]]k_1, k_2, p_1, p_2 [, k_3 [, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4 [, \tau_x, \tau_y]]]]),若向量为空(NULL),则为 0 畸变。

  • rvec:输出旋转矩阵对应的旋转向量,将对象坐标系下的点转为相机坐标系。使用下方法转为矩阵形式:

    1
    2
    3
    4
    5
    6
    7
    #include <opencv2/calib3d.hpp>

    void cv::Rodrigues(
    InputArray src, // 旋转向量
    OutputArray dst, // 旋转矩阵
    OutputArray jacobian = cv::NoArray()
    );

    jacobian:可选输出的雅可比矩阵,大小为 3×93 \times 99×39 \times 3,表示输出矩阵相对输入向量的部分导。

  • tvec:输出的位姿的平移向量部分。

  • useExtrinsicGuess:用于 cv::SOLVEPNP_ITERATIVE 的参数,若为 true,则用给定的旋转和初始值进行优化求解。

  • iterationsCount:迭代次数。

  • reprojectionError:用于 RANSAC 法的参数,表示点到极线到像素距离阈值,如果大于此值,则点被视为离群点。

  • confidence:用于 RANSAC 法,表示预期计算得到的矩阵的置信度。

  • inliers:输出包含 objectPointsimagePoints 的内点(inliers)的索引向量。

  • flags:求解 PnP 问题的方式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    cv::SOLVEPNP_ITERATIVE
    cv::SOLVEPNP_P3P
    cv::SOLVEPNP_AP3P
    cv::SOLVEPNP_EPNP
    cv::SOLVEPNP_DLS
    cv::SOLVEPNP_IPPE
    cv::SOLVEPNP_IPPE_SQUARE
    cv::SOLVEPNP_UPNP
    cv::SOLVEPNP_SQPNP

9.3.2 RANSAC 法-2

1
2
3
4
5
6
7
8
9
10
bool cv::solvePnPRansac(
InputArray objectPoints,
InputArray imagePoints,
InputArray cameraMatrix,
InputArray distCoeffs,
OutputArray rvec,
OutputArray tvec,
OutputArray inliers,
const cv::UsacParams & params = cv::UsacParams()
);
  • 前一函数的重载函数。

9.4 RefineLM 法求解 PnP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <opencv2/calib3d.hpp>

void cv::solvePnPRefineLM(
InputArray objectPoints,
InputArray imagePoints,
InputArray cameraMatrix,
InputArray distCoeffs,
OutputArray rvec,
OutputArray tvec,
cv::TermCriteria criteria = cv::TermCriteria(
cv::TermCriteria::EPS + cv::TermCriteria::COUNT,
20, FLT_EPSILON
)
);
  • objectPoints:对象坐标系下的点,大小为 N×3,1channelN \times 3, 1-channel1×N/N×1,3channels1 \times N / N \times 1, 3 - channels。通常可以可以使用 vector<cv::Point3d>

  • imagePoints:对应的相机坐标系下的图像点,大小为 N×2,1channelN \times 2, 1-channel1×N/N×1,2channels1 \times N / N \times 1, 2 - channels。通常可以可以使用 vector<cv::Point2d>

  • cameraMatrix:相机内参矩阵。

  • distCoeffs:畸变系数,为 4、5、8、12 和 14 元素的向量(k1,k2,p1,p2[,k3[,k4,k5,k6[,s1,s2,s3,s4[,τx,τy]]]]k_1, k_2, p_1, p_2 [, k_3 [, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4 [, \tau_x, \tau_y]]]]),若向量为空(NULL),则为 0 畸变。

  • rvec:输出旋转矩阵对应的旋转向量,将对象坐标系下的点转为相机坐标系。使用下方法转为矩阵形式:

    1
    2
    3
    4
    5
    6
    7
    #include <opencv2/calib3d.hpp>

    void cv::Rodrigues(
    InputArray src, // 旋转向量
    OutputArray dst, // 旋转矩阵
    OutputArray jacobian = cv::NoArray()
    );

    jacobian:可选输出的雅可比矩阵,大小为 3×93 \times 99×39 \times 3,表示输出矩阵相对输入向量的部分导。

  • tvec:输出的位姿的平移向量部分。

  • criteria:结束 LM 迭代法的标准。

9.5 RefineVVS 法求解 PnP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <opencv2/calib3d.hpp>

void cv::solvePnPRefineVVS(
InputArray objectPoints,
InputArray imagePoints,
InputArray cameraMatrix,
InputArray distCoeffs,
OutputArray rvec,
OutputArray tvec,
cv::TermCriteria criteria = cv::TermCriteria(
cv::TermCriteria::EPS + cv::TermCriteria::COUNT,
20, FLT_EPSILON
),
double VVSlambda = 1
);
  • objectPoints:对象坐标系下的点,大小为 N×3,1channelN \times 3, 1-channel1×N/N×1,3channels1 \times N / N \times 1, 3 - channels。通常可以可以使用 vector<cv::Point3d>

  • imagePoints:对应的相机坐标系下的图像点,大小为 N×2,1channelN \times 2, 1-channel1×N/N×1,2channels1 \times N / N \times 1, 2 - channels。通常可以可以使用 vector<cv::Point2d>

  • cameraMatrix:相机内参矩阵。

  • distCoeffs:畸变系数,为 4、5、8、12 和 14 元素的向量(k1,k2,p1,p2[,k3[,k4,k5,k6[,s1,s2,s3,s4[,τx,τy]]]]k_1, k_2, p_1, p_2 [, k_3 [, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4 [, \tau_x, \tau_y]]]]),若向量为空(NULL),则为 0 畸变。

  • rvec:输出旋转矩阵对应的旋转向量,将对象坐标系下的点转为相机坐标系。使用下方法转为矩阵形式:

    1
    2
    3
    4
    5
    6
    7
    #include <opencv2/calib3d.hpp>

    void cv::Rodrigues(
    InputArray src, // 旋转向量
    OutputArray dst, // 旋转矩阵
    OutputArray jacobian = cv::NoArray()
    );

    jacobian:可选输出的雅可比矩阵,大小为 3×93 \times 99×39 \times 3,表示输出矩阵相对输入向量的部分导。

  • tvec:输出的位姿的平移向量部分。

  • criteria:结束 LM 迭代法的标准。

  • VVSlambda:等价于阻尼高斯-牛顿法中的 α\alpha 增益。

10. DNN 的使用

1
2
3
#include <opencv2/dnn/dnn.hpp>

cv::dnn::Net net;

10.1 forward() 的调用

1
2
3
cv::Mat cv::dnn::Net::forward(
const cv::String & outputName = cv::String() // 可以为 string
);
  • 返回网络 outputName 层的第一个输出。
1
2
3
4
void cv::dnn::Net::forward(
OutputArrayOfArrays outputBlobs,
const cv::String & outputName = cv::String()
);
  • outputBlobs:包含特定层的所有输出。
  • outputName:需要获取输出的输出层名。
1
2
3
4
void cv::dnn::Net::forward(
OutputArrayOfArrays outputBlobs,
const std::vector<cv::String> & outBlobNames
);
  • outputBlobs:包含特定层的第一个输出。
  • outputNames:需要获取输出的几个输出层名。
1
2
3
4
void cv::dnn::Net::forward(
std::vector<std::vector<cv::Mat>> & outputBlobs,
const std::vector<cv::String> & outBlobNames
);
  • outputBlobs:包含特定层的所有输出。
  • outputNames:需要获取输出的几个输出层名。