wordpress 数据库密码,网站建设seo视频教程,wordpress 热门关键字,wordpress视频站模板内容来源于《opencv4应用开发入门、进阶与工程化实践》
二值分析#xff1a;
常见的二值化方法#xff1a;
基于全局阈值#xff08;threshold#xff09;得到的二值图像#xff1b;基于自适应阈值#xff08;adaptiveThreshold#xff09;得到的二值图像#xff1…内容来源于《opencv4应用开发入门、进阶与工程化实践》
二值分析
常见的二值化方法
基于全局阈值threshold得到的二值图像基于自适应阈值adaptiveThreshold得到的二值图像边缘检测Canny基于像素值范围inRange
threshold
thresholdType介绍:
THRESH_BINARY表示大于thresh的取maxval,否则取0;THRESH_BINARY_INV表示大于thresh的取0,否则取maxvalue;THRESH_TRUNC表示大于thresh取threshold,否则不改变灰度值;THRESH_TOZERO表示大于thresh的不改变灰度值,否则取0;THRESH_TOZERO_INV表示大于thresh取0,窦泽不改变灰度值;THRESH_OTSU表示使用otsu自动计算阈值;THRESH_TRIANGLE表示使用Triangle自动计算阈值;
adaptiveThreshold
void adaptiveThreshold( InputArray src, OutputArray dst,double maxValue, int adaptiveMethod,int thresholdType, int blockSize, double C );src表示需要进行二值化的图像;需要注意的是,该输入必须是8-bit单通道的图像;dst表示输出图像的二值图像;maxValue是一个非零值,用于对哪些满足条件的阈值进行赋值;adaptiveMethod表示选择哪一种自适应阈值算法;Opencv提供两种,ADAPTIVE_THRESH_MEAN_C与ADAPTIVE_THRESH_GAUSSIAN_C,下面会详细介绍;thresholdType表示二值化类型,OpenCV提供两种, THRESH_BINARY与THRESH_BINARY_INV,下面会详细介绍;blocksize表示参与计算的像素的领域范围,必须使用奇数;C可以为正数, 零或者负数;用于在计算过程中容忍程度;
thresholdType介绍 adaptiveMethod介绍
第一种ADAPTIVE_THRESH_MEAN_C,针对像素(x,y)的计算方式如下:
T(x,y)结果是在(x,y)的邻域blockSize×blockSize范围内所有灰度值的均值减去C;
第二种ADAPTIVE_THRESH_GAUSSIAN_C,针对像素(x,y)的计算方式如下:
首先,生成一个大小为blockSize×blockSize的高斯核,作为权重;其次,利用高斯核与(x,y)邻域范围内灰度值,进行加权求和,再减去C,得到T(x,y);
高斯核符合高斯分布距离越近权重越大。
Canny
标准的边缘检测算法包括如下几步
将图像转为灰度图像通过高斯模糊卷积实现降噪计算图像梯度的大小与角度非最大信号压制双阈值边缘连接
在图像利用Sobel算子也是滤波函数计算x, y两个方向的梯度: 其次,计算梯度的强度和方向:根据X轴和Y轴方向的梯度可以计算图像中像素点的梯度幅值G与角度θ 非最大抑制
理想情况下只有边缘像素的梯度是大于阈值T的但实际情况下局部也会出现多个高梯度阈值所以要需要每个像素根据自身角度方向与两侧像素梯度值进行比较如果当前像素点的梯度值小于两侧像素的梯度值则将当前像素点的值设置为0如果大于两侧像素的梯度值则保留。
双阈值连接
双阈值连接时保证边缘连续的关键步骤。一个高阈值H一个低阈值L。
双阈值连接首先使用L对梯度图像进行处理高于L保留低于L丢弃并将值设为零。然后使用H进行处理高于H都视为边缘像素点。梯度值在[L,H]之间的如果从低阈值像素点出发最终可以通过相邻的像素点连接到高阈值像素点而且整个连线上的像素点梯度值都大于L则保留否则设置为0。
轮廓发现与轮廓绘制
轮廓发现
void findContours//提取轮廓用于提取图像的轮廓
(
InputOutputArray image,//输入图像必须是8位单通道图像并且应该转化成二值的
OutputArrayOfArrays contours,//检测到的轮廓每个轮廓被表示成一个point向量
OutputArray hierarchy,//可选的输出向量包含图像的拓扑信息。其中元素的个数和检测到的轮廓的数量相等
int mode,//说明需要的轮廓类型和希望的返回值方式
int method,//轮廓近似方法
Point offset Point()
)
轮廓绘制
void drawContours//绘制轮廓用于绘制找到的图像轮廓
(InputOutputArray image,//要绘制轮廓的图像InputArrayOfArrays contours,//所有输入的轮廓每个轮廓被保存成一个point向量int contourIdx,//指定要绘制轮廓的编号如果是负数则绘制所有的轮廓const Scalar color,//绘制轮廓所用的颜色int thickness 1, //绘制轮廓的线的粗细如果是负数则轮廓内部被填充int lineType 8, /绘制轮廓的线的连通性InputArray hierarchy noArray(),//关于层级的可选参数只有绘制部分轮廓时才会用到int maxLevel INT_MAX,//绘制轮廓的最高级别这个参数只有hierarchy有效的时候才有效//maxLevel0绘制与输入轮廓属于同一等级的所有轮廓即输入轮廓和与其相邻的轮廓//maxLevel1, 绘制与输入轮廓同一等级的所有轮廓与其子节点。//maxLevel2绘制与输入轮廓同一等级的所有轮廓与其子节点以及子节点的子节点Point offset Point()
)
代码示例
void BinaryAnalysis::find_contours_demo(Mat image) {Mat gray;cvtColor(image, gray, COLOR_BGR2GRAY);std::vectorvectorPoint contours;vectorVec4i hierarchy;findContours(gray, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());Mat result Mat::zeros(image.size(), image.type());drawContours(result, contours, -1, Scalar(0, 0, 255), 2, 8);imshow(轮廓发现, result);
}
轮廓测量
轮廓测量指对二值图像的每个轮廓的弧长和面积进行测量根据轮廓的面积和弧长对大小不同的对象实现查找、过滤与处理的操作以寻找感兴趣的RoI区域。
计算面积
//计算面积
double cv::contourArea(InputArray contourbool oriented false
)
//计算弧长、周长
double cv::arcLength(InputArray curvebool closed)
//计算轮廓外接矩形
Rect cv::boundingRect(InputArray array
)
//示例代码
void BinaryAnalysis::contours_analysis_demo(Mat image) {// 二值化Mat gray, binary;cvtColor(image, gray, COLOR_BGR2GRAY);double t threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);// 轮廓发现std::vectorvectorPoint contours;vectorVec4i hierarchy;findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());Mat result Mat::zeros(image.size(), image.type());drawContours(result, contours, -1, Scalar(0, 0, 255), 2, 8);// 轮廓测量for (size_t t 0; t contours.size(); t) {Rect box boundingRect(contours[t]);double area contourArea(contours[t]);double arc arcLength(contours[t], true);putText(result, format(area:%.2f, area), box.tl(), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 255, 0), 1, 8);putText(result, format(arc:%.2f, arc), Point(box.x, box.y14), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 255, 0), 1, 8);}imshow(轮廓测量, result);
}
轮廓拟合逼近
//拟合椭圆
RotatedRect cv::fitEllipse(InputArray
)
//拟合直线
void cv::fitLine(InputArray pointsOutputArray lineint distType,double param,double reps,double aeps
)//distType表示拟合时使用的距离计算公式、、param表示对模型进行拟合距离计算的公式是否需要用到该参数。当distType参数为567时表示需要用到该参数否则该参数不参与拟合距离计算、、reps与aeps表示对拟合结果的精度要求
//轮廓逼近
void cv::approxPolyDP(InputArray curveOutputArray approxCurvedouble epsilonbool closed
)轮廓椭圆拟合与直线拟合示例代码
//示例代码
void BinaryAnalysis::contours_fitness_demo(Mat image) {// 二值化Mat edges;int t 80;Canny(image, edges, t, t * 2, 3, false);//返回一个结构元素卷积核主要用于后续的膨胀腐蚀操作Mat k getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));//膨胀函数对于3*3的核取最大的数放在中心位置dilate(edges, edges, k);// 轮廓发现std::vectorvectorPoint contours;vectorVec4i hierarchy;findContours(edges, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());for (size_t t 0; t contours.size(); t) {if (contours[t].size() 5) {continue;}// 拟合椭圆// RotatedRect rrt fitEllipse(contours[t]);// ellipse(image, rrt, Scalar(0, 0, 255), 2, 8);// 拟合直线Vec4f oneline;fitLine(contours[t], oneline, DIST_L1, 0, 0.01, 0.01);float vx oneline[0];float vy oneline[1];float x0 oneline[2];float y0 oneline[3];// 直线参数斜率k与截矩bfloat k vy / vx;float b y0 - k*x0;// 寻找轮廓极值点int minx 0, miny 10000;int maxx 0, maxy 0;for (int i 0; i contours[t].size(); i) {Point pt contours[t][i];if (miny pt.y) {miny pt.y;}if (maxy pt.y) {maxy pt.y;}}maxx (maxy - b) / k;minx (miny - b) / k;line(image, Point(maxx, maxy), Point(minx, miny), Scalar(0, 0, 255), 2, 8, 0);}imshow(轮廓拟合-直线拟合, image);
}
轮廓逼近示例代码
void BinaryAnalysis::contours_apprv_demo(Mat image) {Mat gray, binary;cvtColor(image, gray, COLOR_BGR2GRAY);double t threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);std::vectorvectorPoint contours;vectorVec4i hierarchy;findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());for (size_t t 0; t contours.size(); t) {std::vectorPoint pts;approxPolyDP(contours[t], pts, 10, true);for (int i 0; i pts.size(); i) {circle(image, pts[i], 3, Scalar(0, 0, 255), 2, 8, 0);}}imshow(轮廓逼近, image);
}
轮廓分析
可以根据轮廓发现得到的每个对象轮廓的最大外接矩形活最小外接矩形计算其横纵比周长面积。
下面的示例代码使用了轮廓测量与分析的相关函数完成了对每个对象轮廓的分析得到了每个对象轮廓的属性输出。
void BinaryAnalysis::contours_attrs_demo(Mat image) {// 二值化Mat edges;int t 80;Canny(image, edges, t, t * 2, 3, false);Mat k getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));dilate(edges, edges, k);// 轮廓发现std::vectorvectorPoint contours;vectorVec4i hierarchy;findContours(edges, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());Mat result Mat::zeros(image.size(), image.type());drawContours(result, contours, -1, Scalar(0, 0, 255), 2, 8);imshow(轮廓发现, result);Mat mask Mat::zeros(image.size(), CV_8UC1);for (size_t t 0; t contours.size(); t) {Rect box boundingRect(contours[t]);RotatedRect rrt minAreaRect(contours[t]);std::vectorPoint hulls;convexHull(contours[t], hulls);double hull_area contourArea(hulls);double box_area box.width*box.height;double area contourArea(contours[t]);// 计算横纵比double aspect_ratio saturate_castdouble(rrt.size.width) / saturate_castdouble(rrt.size.height);// 计算延展度double extent area / box_area;// 计算实密度double solidity area / hull_area;// 生成mask与计算像素均值mask.setTo(Scalar(0));drawContours(mask, contours, t, Scalar(255), -1);Scalar bgra mean(image, mask);putText(image, format(extent:%.2f, extent), box.tl(), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 0, 255), 1, 8);putText(image, format(solidity:%.2f, solidity), Point(box.x, box.y 14), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 0, 255), 1, 8);putText(image, format(aspect_ratio:%.2f, aspect_ratio), Point(box.x, box.y 28), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 0, 255), 1, 8);putText(image, format(mean:(%d,%d,%d), (int)bgra[0], (int)bgra[1], (int)bgra[2]), Point(box.x, box.y 42), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 0, 255), 1, 8);}imshow(轮廓分析, image);
}
直线检测圆检测
在二值图像分析中直线检测和轮廓发现是经常遇到的处理要求。Opencv中的直线检测是基于霍夫变换完成的。
//标准霍夫直线检测
void cv::HoughLines(InputArray imageOutputArray linesdouble rho //距离步长d1指该直线到原点的距离对于屏幕坐标原点是左上角的点double theta //角度步长int threshold //double srn 0double stn0double min_theta0double max_thetaCV_PI
)
//概率霍夫直线检测
void cv::HoughLinesP(InputArray imageOutputArray linesdouble rhodouble thetaint thresholddouble minLineLength0double maxLineGap0
)
//霍夫圆检测
void cv::HoughCircle(InputArray imageOutputArray circles//输出圆心与直径int method //方法当前只支持基于梯度的方法double dp //关键参数累加分辨率double minDist //两个圆之间的最小距离double param1100 //边缘检测中的高梯度阈值double param2100 //边缘检测中的低梯度阈值int minRadius0 //最小圆半径int maxRadius0 //最大圆半径
)
示例代码
void BinaryAnalysis::hough_line_demo(Mat image) {Mat edges;Canny(image, edges, 50, 200, 3);vectorVec2f lines;HoughLines(edges, lines, 1, CV_PI / 180, 150, 0, 0);Mat result1, result2;cvtColor(edges, result1, COLOR_GRAY2BGR);result2 result1.clone();for (size_t i 0; i lines.size(); i){float rho lines[i][0], theta lines[i][1];Point pt1, pt2;double a cos(theta), b sin(theta);double x0 a*rho, y0 b*rho;pt1.x cvRound(x0 1000 * (-b));pt1.y cvRound(y0 1000 * (a));pt2.x cvRound(x0 - 1000 * (-b));pt2.y cvRound(y0 - 1000 * (a));line(result1, pt1, pt2, Scalar(0, 0, 255), 3, LINE_AA);}imshow(标准霍夫直线检测, result1);// 概率霍夫直线检测vectorVec4i linesP;HoughLinesP(edges, linesP, 1, CV_PI / 180, 50, 50, 10);for (size_t t 0; t linesP.size(); t) {Point p1 Point(linesP[t][0], linesP[t][1]);Point p2 Point(linesP[t][2], linesP[t][3]);line(result2, p1, p2, Scalar(0, 0, 255), 2, 8, 0);}imshow(概率霍夫直线检测, result2);
}void BinaryAnalysis::hough_circle_demo(Mat image) {Mat gray;cvtColor(image, gray, COLOR_BGR2GRAY);GaussianBlur(gray, gray, Size(5, 5), 0, 0);std::vectorVec3f circles;HoughCircles(gray, circles, HOUGH_GRADIENT_ALT, 2, 10, 100, 50, 20, 40);for (size_t t 0; t circles.size(); t) {Vec3f c circles[t];Point center Point(c[0], c[1]);int radius c[2];circle(image, center, radius, Scalar(255, 0, 255), 2, 8, 0); circle(image, center, 3, Scalar(255, 0, 0), 3, 8, 0);}imshow(霍夫圆检测, image);
}
最大内接圆与最小外接圆
opencv未提供API函数来寻找最大内接圆但是可以通过点多边形测试函数巧妙地获取轮廓最大内接圆地半径从而找到最大内接圆。
//最小外接圆
void cv::minEnclosingCircle(InputArray poointsPoint2f centerfloat radius
)
//点多边形测试函数
double cv::pointPolygonTest(InputArray contourPoint2f ptbool measureDist //是否测量距离当measureDist设置为true时返回的是该点到轮廓的真是距离。设置为false时返回的是1、0、-1
)
//示例代码
void BinaryAnalysis::inner_extenerl_circle_demo(Mat image) {Mat gray;cvtColor(image, gray, COLOR_BGR2GRAY);std::vectorvectorPoint contours;vectorVec4i hierarchy;findContours(gray, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());for (size_t t 0; t contours.size(); t) {// 最小外接圆Point2f pt;float radius;minEnclosingCircle(contours[t], pt, radius);circle(image, pt, radius, Scalar(255, 0, 0), 2, 8, 0);// 点多边形测试Mat raw_dist(image.size(), CV_32F);for (int i 0; i image.rows; i){for (int j 0; j image.cols; j){raw_dist.atfloat(i, j) (float)pointPolygonTest(contours[t], Point2f((float)j, (float)i), true);}}// 获取最大内接圆半径double minVal, maxVal;Point maxDistPt; // inscribed circle centerminMaxLoc(raw_dist, minVal, maxVal, NULL, maxDistPt);minVal abs(minVal);maxVal abs(maxVal);circle(image, maxDistPt, maxVal, Scalar(0, 0, 255), 2, 8, 0);}imshow(最大内接圆与最小外接圆演示, image);
}
轮廓匹配
二值图像轮廓发现可以得到每个圆形的轮廓然后计算轮廓几何矩再根据几何矩计算图像的中心位置。根据中心位置计算中心距然后根据中心距计算中心归一化距。再根据归一化距计算胡距最后比较轮廓胡距之间的相似性从而实现轮廓匹配。
//几何矩、中心距、中心归一化距可通过moments函数一次就计算出来
Moments cv::moments(InoutArray arraybool binaryImagefalse //是否为二值图像
)void cv::HuMoments(const Moments momentsdouble hu[7] //胡距的7个值
)
//将胡距作为输入对轮廓进行匹配。胡距具有缩放不变性与旋转不变性所以进行轮廓外形匹配时可以匹配到旋转与分辨率不一样的同一个轮廓。
//轮廓匹配函数
double cv::matchShapes(InputArray contour1InputArray contour2int method //比较方法double parameter //opencv3.x以后不需要
)
//示例代码
void BinaryAnalysis::contour_match_demo(Mat image) {Mat src imread(D:/images/abc.png);imshow(input, src);Mat src2 imread(D:/images/a5.png);namedWindow(input2, WINDOW_FREERATIO);imshow(input2, src2);// 轮廓提取vectorvectorPoint contours1;vectorvectorPoint contours2;contours_info(src, contours1);contours_info(src2, contours2);// hu矩计算Moments mm2 moments(contours2[0]);Mat hu2;HuMoments(mm2, hu2);// 轮廓匹配for (size_t t 0; t contours1.size(); t) {Moments mm moments(contours1[t]);Mat hum;HuMoments(mm, hum);double dist matchShapes(hum, hu2, CONTOURS_MATCH_I1, 0);printf(contour match distance : %.2f\n, dist);if (dist 1) {printf(draw it \n);Rect box boundingRect(contours1[t]);rectangle(src, box, Scalar(0, 0, 255), 2, 8, 0);}}imshow(match result, src);
}
最大轮廓与关键点编码
根据二值图像实现轮廓发现分析每个轮廓并根据面积找到最大轮廓对最大轮廓使用轮廓逼近从而得到轮廓编码点。最后绘制编码点信息并显示。
void BinaryAnalysis::max_contour_demo(Mat image) {// 二值图像Mat mask;inRange(image, Scalar(0, 0, 0), Scalar(110, 110, 110), mask);bitwise_not(mask, mask);// 轮廓发现vectorvectorPoint contours;vectorVec4i hierarchy;findContours(mask, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);int height image.rows;int width image.cols;int index -1;int max 0;// 最大轮廓寻找for (size_t t 0; t contours.size(); t) {double area contourArea(contours[t]);if (area max) {max area;index t;}}Mat result Mat::zeros(image.size(), image.type());Mat pts;drawContours(result, contours, index, Scalar(0, 0, 255), 1, 8);// 关键点编码提取与绘制approxPolyDP(contours[index], pts, 4, true);for (int i 0; i pts.rows; i) {Vec2i pt pts.atVec2i(i, 0);circle(result, Point(pt[0], pt[1]), 2, Scalar(0, 255, 0), 2, 8, 0);circle(result, Point(pt[0], pt[1]), 2, Scalar(0, 255, 0), 2, 8, 0);}imshow(最大轮廓与关键点编码, result);
}
凸包检测
//轮廓提取凸包
void cv::convexHull(InputArray pointsOutputArray hullbool clockwise falsebool returnPoints true//是否返回点集
)
//判断轮廓是否为凸包
bool cv::isContourConvex(InputArray contour
)//示例代码
void BinaryAnalysis::convex_demo(Mat image) {vectorvectorPoint contours;contours_info(image, contours);for (size_t t 0; t contours.size(); t) {vectorPoint hull;convexHull(contours[t], hull);bool isHull isContourConvex(contours[t]);printf(test convex of the contours %s \n, isHull ? Y : N);int len hull.size();for (int i 0; i hull.size(); i) {circle(image, hull[i], 4, Scalar(255, 0, 0), 2, 8, 0);line(image, hull[i%len], hull[(i 1) % len], Scalar(0, 0, 255), 2, 8, 0);}}imshow(凸包检测, image);
}