一、腐蚀(Erode)
取符合模板的点, 用区域最小值代替中心位置值(锚点)
作用: 平滑对象边缘、弱化对象之间的连接。
opencv 中相关函数:(erode)
1 // C++ 2 /** 3 shape: 形状 4 MORPH_RECT 矩形 5 MORPH_CROSS 交叉形 十字型 6 MORPH_ELLIPSE 椭圆形 7 esize : 大小 8 anchor: 锚点,默认为中心 9 **/ 10 Mat getStructuringElement(int shape, Size esize, Point anchor = Point(-1, -1)); 11 12 /** 13 src: input Mat 14 dst: output Mat 15 element : kernel element 16 完整参数:https://docs.opencv.org/4.1.0/d4/d86/group__imgproc__filter.html#gaeb1e0c1033e3f6b891a25d0511362aeb 17 **/ 18 erode(const Mat& src, Mat&dst , const Mat& element) // 基本参数
1 # python 2 # dst = cv.erode( src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]] ) 3 4 import cv2 as cv 5 import numpy as np 6 7 im = cv.imread("test.jpg") 8 gray = cv.cvtColor(im,cv.COLOR_BGR2GRAY) 9 ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV|cv.THRESH_OTSU) 10 11 # 获取 kerenl element 12 kernel = cv.getStructuringElement(cv.MORPH_RECT,(5,5)) 13 # 腐蚀 14 dst = cv.erode(binary,kernel)
二、 膨胀(Dilate)
实现: 使用kernel 划过图像,将区域的最大值赋给锚点位置。
作用: 致使图像的亮区扩展,能起到平滑边缘的作用。
// C++ /** src: input Mat dst: output Mat kernel : kernel element 完整参数:https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#ga4ff0f3318642c4f469d0e11f242f3b6c **/
#include<opencv2imgprocimgproc.hpp> void dilate(InputArray src, OutputArray dst , InputArray kernel) // 基本参数
三、边缘检测
边缘检测一般步骤:
平滑去噪
对比度增强
计算梯度
过滤判断边缘
1、Canny 边缘检测
1 // C++ 2 #include<opencv2imgprocimgproc.hpp> 3 4 /** 5 image : 输入图像 6 edges : 输出图像 7 threshold1: 阈值1,高于该值 被认为时边缘 8 threshold2: 阈值2, 低于该值可认为不是边缘 9 若在两值之间,该像素仅连接一个高阈值的像素时被保留。 10 apertureSize : kernel 大小,默认3 sobel kernel ,;取值 1 3 5 7 (奇数,<31) 11 L2gradient : L2 norm 求梯度 12 13 详细参数: https://docs.opencv.org/3.4/dd/d1a/group__imgproc__feature.html#ga04723e007ed888ddf11d9ba04e2232de 14 **/ 15 void Canny (InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool L2gradient = false )
1 import numpy as np 2 import cv2 as cv 3 4 # edges = cv.Canny( image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]] ) 5 6 img = cv2.imread('3.jpg',0) 7 edges = cv2.Canny(img,100,200)
2、 sobel
sobel kernel:
X 方向3X3: Y方向3x3:
X 方向5x5:
在opencv sobel 函数中当ksize =-1 时:kernel 为:SCHARR
opencv 中函数:
1 // C++ 2 #include <opencv2/imgproc.hpp> 3 4 /** https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gacea54f142e81b6758cb6f375ce782c8d 5 src: 输入图像 6 dst: 输出图像 7 ddepth: output image depth 8 src.depth() = CV_8U --------------- ddepth =-1/CV_16S/CV_32F/CV_64F 9 src.depth() = CV_16U/CV_16S ----- ddepth =-1/CV_32F/CV_64F 10 src.depth() = CV_64F --------------- ddepth = -1/CV_64F 11 dx / dy : 差分阶数 0 or 1 12 ksize: 取奇数 -1 : SCHARR (3x3) 1: 1x3 or 3x1 13 **/ 14 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 )
1 import cv2 as cv 2 import numpy as np 3 4 # dst = cv.Sobel( src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]] ) 5 6 img = cv.imread('flower.jpg',0) 7 #默认ksize=3 8 sobelx = cv.Sobel(img,cv2.CV_64F,1,0,ksize=3)
四、二值图像的轮廓分析
opencv 中可以使用 findContours()工具,分析二值图像的拓扑结构
void findContours//提取轮廓,用于提取图像的轮廓
(
InputOutputArray image,//输入图像,必须是8位单通道图像,并且应该转化成二值的
OutputArrayOfArrays contours,//检测到的轮廓,每个轮廓被表示成一个point向量
OutputArray hierarchy,//可选的输出向量,包含轮廓的拓扑信息。其中元素的个数和检测到的轮廓的数量相等
int mode, //说明需要的轮廓类型和希望的返回值方式
int method,//轮廓近似方法
Point offset = Point()
)
参数说明:
hierarchy: 每一个轮廓,都包含4个整型数据,分别表示:后一个轮廓的序号、前一个轮廓的序号、子轮廓的序号、父轮廓的序号。
mode: 轮廓检索模式
method :
1)、CV_CHAIN_APPROX_NONE 边界上所有连续点
2)、CV_CHAIN_APPROX_SIMPLE 拐点
3)and 4) 、 CV_CHAIN_APPROX_TC89_L1 、 CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似法
# python import cv2 as cv import numpy as np # contours, hierarchy = cv.findContours( image, mode, method[, contours[, hierarchy[, offset]]] ) img = cv.imread('12.jpeg') gray = cv.cvtColor ( img , cv2.COLOR_BGR2GRAY ) ret , binary = cv.threshold ( gray , 220 , 255 , cv2.THRESH_BINARY ) # 检测轮廓 contours , hierarchy = cv.findContours ( binary , cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE ) # 画出轮廓 cv.drawContours(img,contours,-1,(0,0,255),3) ''' void cv::drawContours ( InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar & color, int thickness = 1, int lineType = LINE_8, InputArray hierarchy = noArray(), int maxLevel = INT_MAX, Point offset = Point() ) #image:输入输出图像,Mat类型即可 #contours:使用findContours检测到的轮廓数据,每个轮廓以点向量的形式存储,point类型的vector #contourIdx:绘制轮廓的只是变量,如果为负值则绘制所有输入轮廓 #color:轮廓颜色 #thickness:绘制轮廓所用线条粗细度,如果值为负值,则在轮廓内部绘制 #lineTpye:线条类型,有默认值LINE_8 '''
五、 凸包 和 多边形拟合
凸包:
opencv 中使用 convexHull() 函数来查找对象的凸包。
void cv::convexHull ( InputArray points,
OutputArray hull,
bool clockwise = false,
bool returnPoints = true
)
参数: points: input 2D point set, stored in std::vector or Mat.
hull : 输出参数,用于输出函数调用后找到的凸包
clockwise : 操作方向,true顺时针,fasle逆时针
详细参考: https://docs.opencv.org/master/d3/dc0/group__imgproc__shape.html#ga014b28e56cb8854c0de4a211cb2be656
多边形拟合:
opencv 中使用 approxPolyDP() 函数对图像的轮廓点进行多边形拟合。
void approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)
参数:
curve : Input vector of a 2D point stored in std::vector or Mat
approxCurve : 表示输出的多边形点集
epsilon: 精度,两个轮廓点之间的最大距离数
closed: 表示输出的多边形是否封闭
#include<opencv2opencv.hpp> #include<opencv2imgprocimgproc.hpp> #include<iostream> using namespace std; using namespace cv; int main() { // 三通道二值图像 Mat img = imread("E:\pcblabels\labels2019-11-01-094405.jpg"); cout << "read image end..." << endl; // 膨胀 Mat kernel = getStructuringElement(MORPH_RECT, Size(6, 6)); Mat dilateImg; dilate(img, dilateImg, kernel); cout << "dilate end....." << endl; // 腐蚀 Mat erodeImg; erode(dilateImg, erodeImg, kernel); cout << "erode end....." << endl; // canny Mat cannyImg; Canny(dilateImg, cannyImg, 5, 2, 5); // ksize: 奇数 cout << "Canny end....." << endl; // find contours vector<vector<Point>> contours; vector<Vec4i> hierarchy; // 只检测最外层轮廓,并且保存轮廓上所有点 findContours(cannyImg, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point()); drawContours(contours, hierarchy, img.size()); // 找一个点数最多的轮廓 int index = 0; for (int i = 0; i< contours.size(); i++) { if (contours[i].size() > contours[index].size()) { index = i; } } cout << "findContours end....." << endl; //凸包 Mat hullImg = img.clone(); vector<Point> hull; convexHull(Mat(contours[index]), hull, true); drawContours(hullImg, vector<vector<Point>>{hull}, 0, Scalar(0,0,255), 1, 8, vector<Vec4i>(), 0, Point()); cout << "draw hull end....." << endl; // 多边形拟合 Mat approxImg = img.clone(); Mat approxImgRes = Mat::zeros(img.size(), CV_8UC1); vector<Point> approxPloy; approxPolyDP(contours[index], approxPloy, 1, true); drawContours(approxImg, contours, index, Scalar(255, 0, 0), 1, 8, hierarchy); drawContours(approxImgRes, vector<vector<Point>>{approxPloy}, 0, Scalar(255), 2, 8, vector<Vec4i>(), 0, Point()); cout << "draw approxPolyDP end....." << endl; return 0; }