算子:
matchShapes( InputArray contour1, InputArray contour2, int method, double parameter )
(1)参数1是待匹配轮廓或者灰度图像
(2)参数2同参数1
(3)比较参数1和2相似度的方法,opencv提供了三种如下:
CV_CONTOURS_MATCH_I1
CV_CONTOURS_MATCH_I2
CV_CONTOURS_MATCH_I3
(4)参数4为目前还不支持,使用时赋个0就ok。
针对三种匹配方法进行比较,结果如下:

形状匹配过程:
将待识别图像 -> 灰度处理 -> 自动阈值分割
通过轮廓检索函数 cv.findContours 找到待识别图像所有轮廓
模板图像 -> 灰度图像 -> 自动阈值分割
通过轮廓检索函数 cv.findContours 找到模板图像中目标的外轮廓
将第2步得到的轮廓逐一和第4步得到的轮廓 通过 cv.matchShapes 函数进行形状匹配。找到其中最小值,最小值对应的待识别图像中的轮廓即为匹配到的模板图像
标出在待识别图像中找到的模板图像
注意:利用mathshape得到的匹配分值越小,则两个轮廓越相似,越大则越不相似。在匹配过程中会通过匹配分值与设定的分值进行比较,在保证匹配效果完美的情况下,设定的分值越低越好,如果设定的匹配分值略高,可能会导致两个完全不相似的形状匹配成功(亲身实验,分值设高,利用三角形会匹配到圆形)。
另外,matchShapes函数其实比较的是两个轮廓的Hu不变矩。Hu矩特性:具有旋转,缩放和平移不变性。由Hu矩组成的特征量对图片进行识别,优点就是速度很快,缺点是识别率比较低。 因此Hu不变矩一般用来识别图像中大的物体,对于物体的形状描述得比较好,图像的纹理特征不能太复杂。
代码:
(1)创建形状轮廓模板
vector<Point> ImageTemplateContours(Mat img_template)
{
//灰度化
Mat gray_img_template;
cvtColor(img_template, gray_img_template, COLOR_BGR2GRAY);
//阈值分割
Mat thresh_img_template;
threshold(gray_img_template, thresh_img_template, 0, 255, THRESH_OTSU);
//膨胀处理
Mat ellipse = getStructuringElement(MORPH_ELLIPSE, Size(15, 15));
Mat erode_img_template;
//erode(thresh_img_template, erode_img_template, ellipse);
morphologyEx(thresh_img_template, thresh_img_template, MORPH_OPEN, ellipse, Point(-1, -1), 1);
//寻找边界
vector<vector<Point>> contours_template;
vector<Vec4i> hierarchy;
findContours(thresh_img_template, contours_template, hierarchy, RETR_LIST, CHAIN_APPROX_NONE, Point());
//绘制边界
drawContours(img_template, contours_template, 0, Scalar(0, 0, 255), 1, 8, hierarchy);
return contours_template[0];
}
注:之所以返回findContours算子发现的所有轮廓中的第0个,这是因为第0个就是我想要的圆形模板
(2)进行形状模板匹配
vector<Point2d> ShapeTemplateMatch(Mat image, vector<Point> imgTemplatecontours, double minMatchValue)
{
vector<Point2d> image_coordinates;
//灰度化
Mat gray_img;
cvtColor(image, gray_img, COLOR_BGR2GRAY);
//阈值分割
Mat thresh_img;
threshold(gray_img, thresh_img, 0, 255, THRESH_OTSU);
//寻找边界
vector<vector<Point>> contours_img;
vector<Vec4i> hierarchy;
findContours(thresh_img, contours_img, hierarchy, RETR_LIST, CHAIN_APPROX_NONE, Point());
//根据形状模板进行匹配
int min_pos = -1;
double min_value = minMatchValue;//匹配分值,小于该值则匹配成功
for (int i = 0; i < contours_img.size(); i++)
{
//计算轮廓面积,筛选掉一些没必要的小轮廓
if (contourArea(contours_img[i])>12000)
{
//得到匹配分值
double value = matchShapes(contours_img[i], imgTemplatecontours, CONTOURS_MATCH_I3, 0.0);
//将匹配分值与设定分值进行比较
if (value < min_value)
{
min_pos = i;
//绘制目标边界
drawContours(image, contours_img, min_pos, Scalar(0, 0, 255), 1, 8, hierarchy, 0);
//获取重心点
Moments M;
M = moments(contours_img[min_pos]);
double cX = double(M.m10 / M.m00);
double cY = double(M.m01 / M.m00);
//显示目标中心并提取坐标点
circle(image, Point2d(cX, cY), 1, Scalar(0, 255, 0), 2, 8);
//putText(image, "center", Point2d(cX - 20, cY - 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0), 1, 8);
//将目标的重心坐标都存在数组中
image_coordinates.push_back(Point2d(cX, cY));//向数组中存放点的坐标
}
}
}
return image_coordinates;
}
两张图像进行比较,查看轮廓形状相似度...
SparkCore的RDD算子实现对数据的重新分区Coalesce和Repartition 1、coalesce可以改变RDD的分区数 当 shuffle=true时,可以将原来的rdd的分区数变多和变少 当 shuffle=false时,只能将原来的rdd的分区数变少(哪怕给一个更多的分区数,实际结果只会保持原来的分区数) 2、repartition的实质就是调用了coalesce coales...
数据准备 groupBy groupByKey recduceByKey aggregateByKey foldByKey combineByKey countByKey cogroup aggregate fold 打印结果...
另外可以自定义函数,不过运行CannyAlogrithm(img,30,50)报错,出现不知道什么问题,。嘿嘿,未完待续...
运行结果(建议一个监听一个监听的试效果,一起就显得杂乱):...
Top1:GroupBy Top2:GroupByKey Top3: Reduce Top4:ReduceBykey Top5:Aggregate Top6:AggregateByKey Top7:CountBykey Top8:CountByValue Top9:Fold Top10:FoldByKey Top11:CombineBykey...
基于OpencvSharp实现的setMouseBack 背景 SetMouseCallback CvMouseCallback 代码实现 参考资料 背景 由于是使用C#编写程序界面,因此选择了Opencvsharp作为opencv替代品。最近需要使用鼠标画图功能,了解到opencv自带的setMouseBack函数具备相应功能,通过上网查找相应代码,发现大部分都是基于Python和C++的,没有...
RDD转换算子Transformation(lazy):懒汉模式 (转换) 一个数据集分成两个RDD,两个可能合并 map 输入变换函数应用于RDD中所有元素 flatMap *输入变换函数应用于RDD中所有元素,将所有对象合并为一个对象。 filter mapValues 在mapvalues上一个RDD中的Key不变与新的Values一起组成新的RDD MapPartitions 由于单独运行...
spark算子 什么是算子 百度百科上对算子的解释是这样的,算子是一个函数空间到函数空间上的映射O:X→X。广义的讲,对任何函数进行某一项操作都可以认为是一个算子,甚至包括求幂次,开方都可以认为是一个算子,只是有的算子我们用了一个符号来代替他所要进行的运算罢了,所以大家看到算子就不要纠结,他和f(x)的f没区别,它甚至和加减乘除的基本运算符号都没有区别,只是他可以对单对象操作罢了(有的符...
PHP 代码如下:前提是需要在本地配好swoole的环境 /**********************以下是客户端的代码*****************************************/...