C++实现钢管计数
来源:互联网 发布:网络主播思瑞护士视频 编辑:程序博客网 时间:2024/04/29 22:27
1. 图像二值化。也就是得到质量良好的截面区域。使用带有上下限(需根据场景手动设置)的二值化方法,去除深色背景(Threshhold1)和除钢管阴影以外的亮区域(Threshhold2)对ROI(感兴趣) 区域的干扰。
2. 提取目标连通区域轮廓。 经形态学开运算处理后,去除噪声点和独立小点特大区域的干扰, 分割出目标连通区域后, 提取所有连通区域的边界点。 其中连通区域的面积选择根
据经验设置。
3. 统计连通区域的圆特性。以连通区域的最小外接圆半径作为期望没计算轮廓上个点到圆心距离的方差来确定是否为类圆。 方差可信度的范围根据图像的效果进行手动设置。
下面是实现的代码:
// selectshape.cpp : 选择轮廓
//二值化的结果是识别的关键,提取出所有圆形区域,后面通过调节类圆的方差阈值,连通区域的大小可以提高识别率
#include "stdafx.h"
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;
#define VP vector<Point> //用VP符号代替 vector<point>
RNG rng(12345);
//带有上下限的threshold
void threshold2(Mat gray,Mat& thresh,int minvalue,int maxvalue)
{
Mat thresh1;
Mat thresh2;
//二值化 阈值为43
//THRESH_BINARY 当前点值大于阈值时,取Maxval,否则设置为0
threshold(gray,thresh1,43,255, THRESH_BINARY);
//?
//THRESH_BINARY_INV 当前点值大于阈值时,设置为0,否则设置为Maxval
threshold(gray,thresh2,111,255,THRESH_BINARY_INV);
thresh = thresh1 & thresh2;
}
//寻找并绘制出联通区域-----------------------------------------------------------------------此处出现大部分错误联通区域导致圆识别失败
vector<VP> connection2(Mat src,Mat& draw)
{
draw = Mat::zeros(src.rows,src.cols,CV_8UC3);
vector<VP>contours;
// —CV_RETR_LIST:检测所有轮廓,但不建立继承(包含)关系。
// – CV_CHAIN_APPROX_SIMPLE:只存储水平,垂直,对角直线的起始点。对drawContours函数来说,这两种方法没有区别。
findContours(src,contours,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
for (int i=0;i<contours.size();i++)
{
Scalar color = Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255));
drawContours(draw,contours,i,color,-1);
}
return contours;
}
//根据面积提取连通区域select_shape,返回轮廓
vector<VP> selectShapeArea(Mat src,Mat& draw,vector<VP> contours,int minvalue,int maxvalue)
{
vector<VP> result_contours;
draw = Mat::zeros(src.rows,src.cols,CV_8UC3);
for (int i=0;i<contours.size();i++)
{
//计算整个轮廓的面积
int countour_area = contourArea(contours[i]);
if (countour_area >minvalue && countour_area<maxvalue)
{
//初始化?
result_contours.push_back(contours[i]);
}
}
for (int i=0;i<result_contours.size();i++)
{
Scalar color = Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255));
drawContours(draw,result_contours,i,color,-1);
}
return result_contours;
}
//计算轮廓的圆的特性
float calculateCircularity(VP contour)
{
Point2f center;
float radius = 0;
minEnclosingCircle((Mat)contour,center,radius);
//以最小外接圆半径作为数学期望,计算轮廓上各点到圆心距离的方差
float fsum = 0;
float fcompare = 0;
for (int i=0;i<contour.size();i++)
{
//轮廓上各点
Point2f ptmp = contour[i];
//点到圆心距离差
float fdistenct = sqrt((float)((ptmp.x - center.x)*(ptmp.x - center.x)+(ptmp.y - center.y)*(ptmp.y-center.y)));
float fdiff = abs(fdistenct - radius);
fsum = fsum + fdiff*fdiff;
}
//各点到圆心距离的方差
fcompare = fsum/(float)contour.size();
return fcompare;
}
//选择类圆区域selectShapeCircularity
vector<VP> selectShapeCircularity(Mat src,Mat& draw,vector<VP> contours,float minvalue,float maxvalue)
{
vector<VP> result_contours;
draw = Mat::zeros(src.rows,src.cols,CV_8UC3);
for (int i=0;i<contours.size();i++)
{
float fcompare = calculateCircularity(contours[i]);
if (fcompare >=minvalue && fcompare <=maxvalue)
{
result_contours.push_back(contours[i]);
}
}
//将选出的类圆区域随机上蓝色
for (int i=0;i<result_contours.size();i++)
{
Scalar color = Scalar(255,0,0);
drawContours(draw,result_contours,i,color,-1);
}
return result_contours;
}
int _tmain(int argc, _TCHAR* argv[])
{
Mat src;
Mat drawCircleOnTheOriginal;
Mat gray;
Mat thresh;
Mat draw_connection;
Mat contours_area_open;
Mat contours_area_close;
Mat draw_open;
Mat draw_close;
Mat draw_area;
Mat draw_circle;
vector<VP>contours_connection;
vector<VP>contours_area;
vector<VP>contours_circle;
vector<VP>contours_tmp;
//read_image (Image1, 'F:/未来项目/钢管识别/FindTube/FindTube/1.jpg')
src = imread("1.jpg");
//rectangle(src,rect,Scalar(0,0,0),-1);
//rgb1_to_gray (Image1, GrayImage)
cvtColor(src,gray,COLOR_BGR2GRAY);
//threshold (GrayImage, Regions, 43, 111)
threshold2(gray,thresh,43,111);
//开闭运算Size(10, 10)可根据圆形区域大小改变
Mat seOpen = getStructuringElement(MORPH_CROSS, Size(10, 10));
morphologyEx(thresh.clone(), contours_area_open, MORPH_OPEN, seOpen);
//imshow("draw_open.jpg", contours_area_open);
/*Mat seClose = getStructuringElement(MORPH_CROSS, Size(3, 3));
morphologyEx(contours_area_open, contours_area_close, MORPH_CLOSE, seClose);
imshow("draw_close.jpg", contours_area_close);*/
//connection (Regions, ConnectedRegions)
contours_connection = connection2(contours_area_open, draw_connection);
//select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 150, 666)
//根据不同的场景修改区域大小的阈值130,666
double areaMin = 130;
double areaMax = 600;
contours_area = selectShapeArea(thresh.clone(), draw_area, contours_connection, areaMin, areaMax);
//select_shape (SelectedRegions, SelectedRegions1, 'circularity', 'and', 0.45, 1)
//根据不同的场景修改方差的范围,或者根据统计到的最小值的倍数确定
double believableValue = 25;
contours_circle = selectShapeCircularity(thresh.clone(), draw_circle, contours_area, 1, believableValue);
//dll
for (int i = 0; i<contours_circle.size(); i++)
{
Point2f center;
float radius;
minEnclosingCircle(contours_circle[i], center, radius);
if (radius > 10 * 0.8 && radius < 10 * 1.4)
{
//minEllipse 9.25
if (ellipseLikeCircle(minEllipse[i]))
{
circle(src, center, radius, Scalar(0, 0, 255));
//ellipse( src,minEllipse[i],Scalar(255,0,0));
pair<Point2f, float> tmp;
tmp.first = center;
tmp.second = radius;
contours_area.push_back(tmp);
}
}
}
//在原图上显示识别出的钢管
drawCircleOnTheOriginal = draw_circle + src;
imshow("draw_circleOnTheOriginal", drawCircleOnTheOriginal);
imwrite("draw_circleOnTheOriginal.jpg", drawCircleOnTheOriginal);
waitKey();
}
- C++实现钢管计数
- 计数排序C实现
- python 3.2 实现钢管划分 动态划分
- 计数排序c/c++实现
- 计数排序C语言实现
- 计数排序-C语言实现
- C数据结构---计数排序实现
- 计数排序算法实现(C版)
- 计数排序算法(C语言实现)
- 算法导论C语言实现: 计数排序
- C语言二叉排序树单词计数程序实现
- 计数排序的C语言实现
- 计数排序及C语言实现
- 计数排序C++实现
- 算法导论计数排序实现(C++)
- 数字图像处理-编程实现染色体计数 C语言实现
- 数字图像处理-编程实现染色体计数 C语言实现
- 【C++】智能指针之引用计数的实现
- Unix架构的演变图
- miniLZO无损压缩库评估
- Android 隐藏标题栏实现全屏
- HDU
- 如何有效地学习开源项目代码?
- C++实现钢管计数
- pandas读取csv文件提示不存在是什么原因?
- Python多版本, 多版本Anaconda安装,pycharm中有多个版本Anaconda(或Python)
- sso登录
- spyder python 分块运行 run cell
- CSND广告屏蔽chrome插件
- 第四章 Controller接口控制器详解(7)——跟着开涛学SpringMVC
- Myeclipse-常见问题第2篇-安装activiti插件教程
- PyQt实现界面的翻转切换效果