ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 6. 图像轮廓处理 ​前文所述,图像对象可以抽象为n维矩阵,矩阵中每一个元素都对应着图像上不同位置的信息,不同方向上的元素族具有相近或相同的值,我们可以认为这些元素族存在某种关系。落实到图像层面上来讲,这种关系就是轮廓,而这些元素族,就是颜色相像或相同的像素块,转换为灰度图后,即变为了亮度的连续与突变关系。如果进行进一步转换成为二值图像后,就变成了明暗色块的连续和突变。 <br> 这些连续与突变的组合,其实就是肉眼可观的轮廓。 ​在Robomaster比赛中,传统的视觉方法就是通过预处理,将采集到的图像转换为灰度图像或二值化图像,进行轮廓处理,特征比对,拟合,解算。最重要的就是对处理后的轮廓进行比对拟合。 <br> ​函数主要由这几部分组成: * 寻找轮廓 * 边缘检测 * 轮廓最小面积形状近似 * 获得轮廓特征值 ## 常用函数 ### 寻找轮廓 ```C++ void cv::findContours ( InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point() ) /** @brief Finds contours in a binary image. 简介 在二值图像中查找轮廓。 The function retrieves contours from the binary image using the algorithm @cite Suzuki85 . The contours are a useful tool for shape analysis and object detection and recognition. See squares.cpp in the OpenCV sample directory. 该函数使用@cite Suzuki85算法从二值图像检索轮廓。轮廓线是形状分析、目标检测和识别的有用工具。请参见OpenCV示例目录中的squares.cpp。 @note Since opencv 3.2 source image is not modified by this function. @注意,由于opencv 3.2源图像不受此函数的修改。 @param image Source, an 8-bit single-channel image. Non-zero pixels are treated as 1's. Zero pixels remain 0's, so the image is treated as binary . You can use #compare, #inRange, #threshold , #adaptiveThreshold, #Canny, and others to create a binary image out of a grayscale or color one. If mode equals to #RETR_CCOMP or #RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1). @param contours Detected contours. Each contour is stored as a vector of points (e.g. std::vector<std::vector<cv::Point> >). @param hierarchy Optional output vector (e.g. std::vector<cv::Vec4i>), containing information about the image topology. It has as many elements as the number of contours. For each i-th contour contours[i], the elements hierarchy[i][0] , hierarchy[i][1] , hierarchy[i][2] , and hierarchy[i][3] are set to 0-based indices in contours of the next and previous contours at the same hierarchical level, the first child contour and the parent contour, respectively. If for the contour i there are no next, previous, parent, or nested contours, the corresponding elements of hierarchy[i] will be negative. @param mode Contour retrieval mode, see #RetrievalModes @param method Contour approximation method, see #ContourApproximationModes @param offset Optional offset by which every contour point is shifted. This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image context. */ void cv::findContours ( InputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset = Point() ) /** @overload This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. 这是为方便起见而提供的重载成员函数。它与上述函数的不同之处在于它接受哪些参数。 */ ``` ### Canny 边缘检测 ```C++ void cv::Canny ( InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool L2gradient = false ) /** @brief Finds edges in an image using the Canny algorithm . 使用Canny算法查找图像中的边缘。 The function finds edges in the input image and marks them in the output map edges using the Canny algorithm. The smallest value between threshold1 and threshold2 is used for edge linking. The largest value is used to find initial segments of strong edges. See <http://en.wikipedia.org/wiki/Canny_edge_detector> 该函数在输入图像中查找边,并使用Canny算法在输出贴图边中标记它们。阈值1和阈值2之间的最小值用于边缘链接。最大值用于查找强边的初始分段。详见:http://en.wikipedia.org/wiki/Canny_edge_detector @param image 8-bit input image. @param edges output edge map; single channels 8-bit image, which has the same size as image . @param threshold1 first threshold for the hysteresis procedure. @param threshold2 second threshold for the hysteresis procedure. @param apertureSize aperture size for the Sobel operator. @param L2gradient a flag, indicating whether a more accurate \f$L_2\f$ norm \f$=\sqrt{(dI/dx)^2 + (dI/dy)^2}\f$ should be used to calculate the image gradient magnitude (L2gradient=true ), or whether the default \f$L_1\f$ norm \f$=|dI/dx|+|dI/dy|\f$ is enough (L2gradient=false ). */ ``` L2gradient a flag, indicating whether a more accurate `$ L_2 $`​​ norm`$ =\sqrt{(dI/dx)^2 + (dI/dy)^2} $`​​ should be used to calculate the image gradient magnitude ( `$ L_{2gradient} $` = true ), or whether the default `$ L_1 $`​​ norm `$ =|dI/dx|+|dI/dy| $` is enough ( `$ L_{2gradient} $` = false ). ```C++ void cv::Canny ( InputArray dx, InputArray dy, OutputArray edges, double threshold1, double threshold2, bool L2gradient = false ) /** @overload Finds edges in an image using the Canny algorithm with custom image gradient. 使用带有自定义图像梯度的Canny算法查找图像中的边缘。 @param dx 16-bit x derivative of input image (CV_16SC1 or CV_16SC3). @param dy 16-bit y derivative of input image (same type as dx). @param edges output edge map; single channels 8-bit image, which has the same size as image . @param threshold1 first threshold for the hysteresis procedure. @param threshold2 second threshold for the hysteresis procedure. @param L2gradient a flag, indicating whether a more accurate \f$L_2\f$ norm \f$=\sqrt{(dI/dx)^2 + (dI/dy)^2}\f$ should be used to calculate the image gradient magnitude ( L2gradient=true ), or whether the default \f$L_1\f$ norm \f$=|dI/dx|+|dI/dy|\f$ is enough ( L2gradient=false ). 见上 */ ``` ### Sobel算子 ```C++ void cv::Sobel ( InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize = 3, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT ) /** @brief Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator. 简介 使用扩展的Sobel运算符计算第一、第二、第三或混合图像导数。 In all cases except one, the ksize*ksize separable kernel is used to calculate the derivative. When ksize = 1, the 3*1 or 1*3 kernel is used (that is, no Gaussian smoothing is done). `ksize = 1` can only be used for the first or the second x- or y- derivatives. 在除一种情况外的所有情况下,都使用ksize*ksize可分离核来计算导数。当ksize=1时,使用3*1或1*3内核(即不进行高斯平滑)`ksize=1`只能用于第一个或第二个x或y导数。 There is also the special value ksize = #FILTER_SCHARR (-1) that corresponds to the 3*3 Scharr filter that may give more accurate results than the 3*3 Sobel. The Scharr aperture is 还有一个特殊值ksize=#FILTER_SCHARR(-1),对应于3*3 SCHARR过滤器,它可能比3*3 Sobel给出更精确的结果。夏尔光圈是 */ ``` ```[tex] \left[ \begin{array}{cccc} -3 & 0 & 3 \\ -10 & 0 & 10 \\ -3 & 0 & 3 \end{array} \right] ``` ```C++ /* for the x-derivative, or transposed for the y-derivative. 对于x-导数,或对于y-导数进行转置。 The function calculates an image derivative by convolving the image with the appropriate kernel: 该函数通过将图像与适当的核进行卷积来计算图像导数: */ ``` ```[tex] \texttt{dst} = \frac{\partial^{xorder+yorder} \texttt{src}}{\partial x^{xorder} \partial y^{yorder}} ``` ```C++ /* The Sobel operators combine Gaussian smoothing and differentiation, so the result is more or less resistant to the noise. Most often, the function is called with ( xorder = 1, yorder = 0, ksize = 3) or ( xorder = 0, yorder = 1, ksize = 3) to calculate the first x- or y- image derivative. The first case corresponds to a kernel of: Sobel算子结合了高斯平滑和微分,因此结果或多或少具有抗噪性。最常见的情况是,使用(xorder=1,yorder=0,ksize=3)或(xorder=0,yorder=1,ksize=3)调用该函数以计算第一个x或y图像导数。第一种情况对应于以下内核: */ ``` ```[tex] \left[ \begin{array}{cccc} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{array} \right] ``` ```C++ /* The second case corresponds to a kernel of: 第二种情况对应于以下内核: */ ``` ```[tex] \left[ \begin{array}{cccc} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{array} \right] ``` ```C++ /* @param src input image. @param dst output image of the same size and the same number of channels as src . @param ddepth output image depth, see @ref filter_depths "combinations"; in the case of 8-bit input images it will result in truncated derivatives. @param dx order of the derivative x. @param dy order of the derivative y. @param ksize size of the extended Sobel kernel; it must be 1, 3, 5, or 7. @param scale optional scale factor for the computed derivative values; by default, no scaling is applied (see #getDerivKernels for details). @param delta optional delta value that is added to the results prior to storing them in dst. @param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. @sa Scharr, Laplacian, sepFilter2D, filter2D, GaussianBlur, cartToPolar */ ``` ### 轮廓平滑,多边近似 ```C++ void cv::approxPolyDP ( InputArray curve, OutputArray approxCurve, double epsilon, bool closed ) /** @brief Approximates a polygonal curve(s) with the specified precision. 简介 以指定的精度近似多边形曲线。 The function cv::approxPolyDP approximates a curve or a polygon with another curve/polygon with less vertices so that the distance between them is less or equal to the specified precision. It uses the Douglas-Peucker algorithm <http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm> 函数cv::approxPolyDP使用另一条顶点较少的曲线/多边形来近似曲线或多边形,以便它们之间的距离小于或等于指定的精度。它使用Douglas Peucker算法http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm @param curve Input vector of a 2D point stored in std::vector or Mat @param approxCurve Result of the approximation. The type should match the type of the input curve. @param epsilon Parameter specifying the approximation accuracy. This is the maximum distance between the original curve and its approximation. @param closed If true, the approximated curve is closed (its first and last vertices are connected). Otherwise, it is not closed. */ ``` ### 最小面积旋转矩形近似 ```C++ RotatedRect cv::minAreaRect ( InputArray points ) /** @brief Finds a rotated rectangle of the minimum area enclosing the input 2D point set. 简介 查找包围输入二维点集的最小区域的旋转矩形。 The function calculates and returns the minimum-area bounding rectangle (possibly rotated) for a specified point set. Developer should keep in mind that the returned RotatedRect can contain negative indices when data is close to the containing Mat element boundary. 该函数计算并返回指定点集的最小面积边界矩形(可能已旋转)。开发人员应该记住,当数据接近包含的Mat元素边界时,返回的RotatedRect可以包含负索引。 @param points Input vector of 2D points, stored in std::vector<> or Mat */ ``` ### 边缘矩形近似 ```C++ Rect cv::boundingRect ( InputArray array ) /** @brief Calculates the up-right bounding rectangle of a point set or non-zero pixels of gray-scale image. 简介 计算点集的右上边界矩形或灰度图像的非零像素。 The function calculates and returns the minimal up-right bounding rectangle for the specified point set or non-zero pixels of gray-scale image. 该函数计算并返回指定点集或灰度图像非零像素的最小右上边界矩形。 @param array Input gray-scale image or 2D point set, stored in std::vector or Mat. */ ``` ### 最小面积圆形近似 ```C++ void cv::minEnclosingCircle ( InputArray points, Point2f & center, float & radius ) /** @brief Finds a circle of the minimum area enclosing a 2D point set. 简介 查找包围二维点集的最小面积圆。 The function finds the minimal enclosing circle of a 2D point set using an iterative algorithm. 该函数使用迭代算法查找二维点集的最小封闭圆。 @param points Input vector of 2D points, stored in std::vector\<\> or Mat @param center Output center of the circle. @param radius Output radius of the circle. */ ``` ### 轮廓周长 ```C++ double cv::arcLength ( InputArray curve, bool closed ) /** @brief Calculates a contour perimeter or a curve length. 简介 计算轮廓周长或曲线长度。 The function computes a curve length or a closed contour perimeter. 该函数用于计算曲线长度或闭合轮廓周长。 @param curve Input vector of 2D points, stored in std::vector or Mat. @param closed Flag indicating whether the curve is closed or not. */ ``` ### 轮廓面积 ```C++ double cv::contourArea ( InputArray contour, bool oriented = false ) /** @brief Calculates a contour area. 简介 计算轮廓面积。 The function computes a contour area. Similarly to moments , the area is computed using the Green formula. Thus, the returned area and the number of non-zero pixels, if you draw the contour using #drawContours or #fillPoly , can be different. Also, the function will most certainly give a wrong results for contours with self-intersections. 该函数用于计算轮廓区域。与力矩类似,使用格林公式计算面积。因此,如果使用#drawContours或#fillPoly绘制轮廓,则返回的区域和非零像素数可能不同。此外,对于具有自相交的等高线,该函数肯定会给出错误的结果。 */ Example: vector<Point> contour; contour.push_back(Point2f(0, 0)); contour.push_back(Point2f(10, 0)); contour.push_back(Point2f(10, 10)); contour.push_back(Point2f(5, 4)); double area0 = contourArea(contour); vector<Point> approx; approxPolyDP(contour, approx, 5, true); double area1 = contourArea(approx); cout << "area0 =" << area0 << endl << "area1 =" << area1 << endl << "approx poly vertices" << approx.size() << endl; /* @param contour Input vector of 2D points (contour vertices), stored in std::vector or Mat. @param oriented Oriented area flag. If it is true, the function returns a signed area value, depending on the contour orientation (clockwise or counter-clockwise). Using this feature you can determine orientation of a contour by taking the sign of an area. By default, the parameter is false, which means that the absolute value is returned. */ ``` 其实还有一些函数如凸包检测、近似三角形、多边形填充等等函数,但是在比赛中不会使用,在此不再赘述