一,利用面积对轮廓进行筛选

注意这种面积筛选有一个弊端就是比如有两个轮廓,

A轮廓为500

B轮廓为300

当面积设置为 area<400时就可以筛选出面积小于300的所有轮廓

反之大于300的轮廓 如果有两个圆轮廓一大一小,可能就只能保留一个了

如果知道这两个形状的轮廓面积,或许可以利用 逻辑与  进行筛选。

效果图

//圆心
#include<iostream>
#include<opencv2\opencv.hpp>
using namespace std;
using namespace cv;int main()
{//载入图像Mat src = imread("D:\\Besktop\\faimage\\Image\\21_25_27.bmp");Mat src_clone = src.clone();if (src.empty()) {cout << "图片为空" << endl;return 0;}imshow("src", src);//转灰度图Mat gray;cvtColor(src, gray, COLOR_BGR2GRAY);//图像二值化threshold(gray, gray, 0, 255, THRESH_BINARY | THRESH_OTSU);imshow("threshold", gray);//执行形态学开操作去除噪点/*Mat kernel = getStructuringElement(MORPH_RECT, Size(3,3), Point(-1, -1));morphologyEx(gray, gray, MORPH_OPEN, kernel, Point(-1, -1), 1);imshow("morphologyEx", gray);*///边缘检测Canny(gray, gray, 0, 255);Mat graycanny;resize(gray, graycanny, Size(600, 600));imshow("canny", graycanny);//轮廓发现vector<vector<Point>> contours;vector<Vec4i> her;findContours(gray, contours, her, RETR_TREE, CHAIN_APPROX_SIMPLE);//获取某一轮廓重心点Moments M;M = moments(contours[0]);double cX = double(M.m10 / M.m00);double cY = double(M.m01 / M.m00);//Mat resultImage = Mat::zeros(gray.size(), CV_8UC3);RNG rng(12345);double area = 0.0;Point pRadius;for (int i = 0; i < contours.size(); i++) {double area = contourArea(contours[i], false);//根据面积及纵横比过滤轮廓if (area > 200) {Rect rect = boundingRect(contours[i]);float scale = float(rect.width) / float(rect.height);if (scale < 1 && scale>0) {drawContours(gray, contours, i, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), -1);int x = rect.width / 2;int y = rect.height / 2;//找出圆心并绘制pRadius = Point(rect.x + x, rect.y + y);circle(gray, pRadius, 15, Scalar(0, 0, 255), 15);}}}Mat graycanny1;resize(gray, graycanny1, Size(600, 600));imshow("resultImage", graycanny1);//imshow("resultImage", resultImage);//在原图上绘制圆心circle(src_clone, pRadius, 15, Scalar(0, 0, 255), 15);cout << "圆心坐标:" << cX << "" << cY << endl;//cout <<"[x,y]" << pRadius << endl;Mat graycanny2;resize(src_clone, graycanny2, Size(600, 600));imshow("src_clone", graycanny2);//imshow("src_clone", src_clone);waitKey(0);return 0;
}

二,利用边缘检测和轮廓筛选找出轮廓

这一种则是利用轮廓的中心点对轮廓进行拟合,从而达到寻找轮廓

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;int main()
{Mat img = imread("D:\\Besktop\\faimage\\测试原图\\22_21_27.bmp");//String dest = "D:\\Besktop\\1\\";/*string path = "D:\\Besktop\\faimage\\测试原图\\";String dest = "D:\\Besktop\\1\\";String savedfilename;int len = path.length();vector<cv::String> filenames;cv::glob(path, filenames);for (int i = 0; i < filenames.size(); i++)Mat frame;frame = imread(filenames[i], i);savedfilename = dest + filenames[i].substr(len);*/Mat gray_img, thresh_img;//灰度cvtColor(img, gray_img, COLOR_BGR2GRAY);threshold(gray_img, thresh_img, 0, 255, THRESH_TRIANGLE);//开运算Mat ellipse = getStructuringElement(MORPH_ELLIPSE, Size(13, 13));morphologyEx(thresh_img, thresh_img, MORPH_OPEN, ellipse, Point(-1, -1), 2);//寻找轮廓vector<vector<Point>> contours;vector<Vec4i> hierarchy1;findContours(thresh_img, contours, hierarchy1, RETR_LIST, CHAIN_APPROX_NONE, Point());//获取某一轮廓重心点Moments M;M = moments(contours[0]);double cX = double(M.m10 / M.m00);double cY = double(M.m01 / M.m00);//绘制轮廓drawContours(img, contours, 0, Scalar(0, 255, 0), 2, 8, hierarchy1);//显示轮廓重心并提取坐标点circle(img, Point2d(cX, cY), 6, Scalar(0, 255, 0), 2, 8);namedWindow("Center Point", CV_WINDOW_NORMAL);imshow("Center Point", img);//imwrite("D:\\Besktop\\1\\22_21_27.bmp", img);putText(img, "center", Point2d(cX - 20, cY - 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0), 1, 8);cout << "重心坐标:" << cX << " " << cY << endl << endl;waitKey(0);return 0;
}

三,这一种方法类似于第一种的面积筛选唯一不同的时候增加了几步形态学处理

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
//第二步 通过面积过滤,通过纵横比的测量,圆形的纵横比应该在1:1左右,如果不是1:1,就把它过滤掉
Mat srcImg, binaryImg, dstImg;
void test()
{srcImg = imread("D:\\Besktop\\faimage\\Image\\21_25_27.bmp", IMREAD_GRAYSCALE);if (srcImg.empty()){cout << "could not load image...\n" << endl;}namedWindow("Original image", CV_WINDOW_NORMAL);  //CV_WINDOW_NORMAL 使得鼠标可以控制显示窗口的大小imshow("Original image", srcImg);//二值化threshold(srcImg, binaryImg, 0, 255, THRESH_BINARY | THRESH_OTSU);namedWindow("Binary Result", CV_WINDOW_NORMAL);imshow("Binary Result", binaryImg);//形态学操作,开操作,去掉小的对象,闭操作,连接里面的洞(开闭操作要先获得结构元素)Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));  //Point(-1, -1)是中心点,这里是 2 x 2位置morphologyEx(binaryImg, dstImg, MORPH_CLOSE, kernel, Point(-1, -1));namedWindow("Close Result", CV_WINDOW_NORMAL);imshow("Close Result", dstImg);kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));morphologyEx(dstImg, dstImg, MORPH_OPEN, kernel, Point(-1, -1));namedWindow("Open Result", CV_WINDOW_NORMAL);imshow("Open Result", dstImg);//轮廓发现vector<vector<Point>> contours;  //存储轮廓vector<Vec4i> hireachy;findContours(dstImg, contours, hireachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());//通过面积过滤,通过纵横比的测量,圆形的纵横比应该在1:1左右,如果不是1:1,就把它过滤掉Mat resultImg = Mat::zeros(srcImg.size(), CV_8SC3);Point cc;for (int i = 0; i < contours.size(); i++){//面积过滤double area = contourArea(contours[i]);  //循环获取指定的面积if (area < 100)  //通过循环过滤掉小于100的面积continue;//横纵比过滤Rect rect = boundingRect(contours[i]);float ratio = float(rect.width) / float(rect.height);if (ratio < 1.1 && ratio> 0.9)  //把满足条件的保留画出来{drawContours(resultImg, contours, i, Scalar(0, 0, 255), -1, 8, Mat(), 0, Point());  //画出来 第五个参数改为 -1 ,使得整个圆形填充cout << "circle area: " << area << endl;  //面积和周长打印出来(像素度量)cout << "circle length: " << arcLength(contours[i], true) << endl;//找中心点int x = rect.x + rect.width / 2;int y = rect.y + rect.height / 2;cc = Point(x, y);circle(resultImg, cc, 2, Scalar(0, 0, 255), 2, 8, 0);  //画出中心点}}namedWindow("Final Result", CV_WINDOW_NORMAL);imshow("Final Result", resultImg);//在原图上定位显示中心点Mat circleImg = srcImg.clone();cvtColor(circleImg, circleImg, COLOR_GRAY2BGR);circle(circleImg, cc, 20, Scalar(0, 0, 255), 2, 8, 0);namedWindow("Center Point", CV_WINDOW_NORMAL);imshow("Center Point", circleImg);
}int main()
{test();waitKey(0);return 0;
}

这三种方法都是opencv中的一些方法,有任何建议和问题均可评论区提问,说不定你的建议正是我疑惑的地方!!!

四,利用轮廓拟合的方法对图片中的某个轮廓进行拟合(这里主要是圆心)

此方法运行环境为opencv4.5.5

相关代码

#if 1
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main(int argc, char** argv)
{// 读取图片Mat src = imread("图片路径");// 转换为灰度图Mat gray;cvtColor(src, gray, COLOR_BGR2GRAY);// 进行边缘检测Mat edge;Canny(gray, edge, 100, 200);// 圆形拟合vector<Vec3f> circles;HoughCircles(edge, circles, HOUGH_GRADIENT, 1, edge.rows / 16, 100, 30, 10, 50);// 绘制圆形和圆心for (size_t i = 0; i < circles.size(); i++){Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));int radius = cvRound(circles[i][2]);circle(src, center, radius, Scalar(0, 0, 255), 2);circle(src, center, 3, Scalar(0, 255, 0), -1);}// 显示结果namedWindow("src", WINDOW_NORMAL);imshow("src", src);waitKey(0);return 0;
}#endif // 1

五,这种是利用凸包 对圆形进行拟合并且将所有的轮廓都绘制外界圆

opencv4.5.5

代码

#if 1
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main(int argc, char** argv)
{// 读取图片Mat img = imread("图片路径");// 转换为灰度图Mat gray;cvtColor(img, gray, COLOR_BGR2GRAY);// 进行二值化处理Mat thresh;threshold(gray, thresh, 128, 255, THRESH_BINARY);// 找到所有轮廓vector<vector<Point>> contours;findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);// 遍历轮廓,找到圆形轮廓for (size_t i = 0; i < contours.size(); i++){// 只考虑凸包vector<Point> hull;convexHull(contours[i], hull);// 尝试将轮廓拟合为圆形Point2f center;float radius;//bool isCircle = fitCircle(hull, center, radius);minEnclosingCircle(hull, center, radius);cout << center.x << "," << center.y << endl;// 标出圆心circle(img, center, 5, Scalar(0, 255, 0), -1);// 绘制圆形circle(img, center, radius, Scalar(0, 0, 255), 2);}// 显示结果Mat ss;resize(img, ss, Size(600, 600));imshow("Contours", ss);waitKey();
}
#endif // 0

有问题欢迎评论区讨论

C++opencv找圆心?看着一篇,一定有你要(边缘轮廓检测,拟合,凸包)找出相应的轮廓或者全部轮廓画外界圆轮廓并且标出轮廓中心相关推荐

  1. 海思方案,最全芯片性能介绍,找方案看这一篇就够了

    海思方案,Hi3518EV100,Hi3518CV100,Hi3515CV100,Hi3516CV100,Hi3516ECV100,Hi3516D,Hi3516A,Hi3519,Hi3520D,Hi3 ...

  2. ICCV 2021 放榜!一文看尽10篇论文的开源项目(检测/分割/Transformer等)

    点击下方卡片,关注"CVer"公众号 AI/CV重磅干货,第一时间送达 前言 ICCV 2021 刚刚公布获奖结果!先恭喜各位论文被收录的同学.ICCV 2021 最终收录1617 ...

  3. c语言游泳是怎么钓鱼的,钓鱼怎么找水层?看完这篇你就懂!

    原标题:钓鱼怎么找水层?看完这篇你就懂! 钓鱼的人经常会听到钓友们时常在谈论着草鱼.鲢鳙怎样找水层这样的问题.下面就给大家说一下鱼儿是怎样找水层的. 一.在什么情况下知道鱼儿们调皮了? 1.气压.水温 ...

  4. api网关选型_如何轻松打造百亿流量API网关?看这一篇就够了(下)

    如何轻松打造百亿流量API网关?看这一篇就够了(上) 上篇整体描述了网关的背景,涉及职能.分类.定位环节,本篇进入本文的重点,将会具体谈下百亿级流量API网关的演进过程. 准备好瓜子花生小板凳开始积累 ...

  5. 数据产品必备技术知识:机器学习及常见算法,看这一篇就够了

    大家都知道,产品经理需要懂技术,很多面试官都偏好有技术背景的同学,毕竟产品经理经常要和开发同学相爱相杀.当然也不是一定要求能够精通,但是至少不要让这块成为沟通的障碍,懂点技术,实际工作中也能少被开发同 ...

  6. Redis看这一篇就够了

    大数据时代NoSQL开始大行其道,其中常用于缓存的Redis可谓风头正盛,是大小公司技术架构中必不可少的一种中间件,也是职场技术同仁们必知必会的一种技术.本场Chat将从各个方面对Redis进行全面的 ...

  7. Vscode上使用opencv(C++接口,Windows篇)

    Vscode上使用opencv(C++接口,Windows篇) opencv是任何一个学习或者对视觉算法感兴趣的同学几乎都会用的一个库,Python接口的opencv玩了一阵子了,最近心血来潮,想要玩 ...

  8. 不知道从哪里找数据?这一篇,都解决(持续更新)

    不知道从哪里找数据?这一篇,都搞定!(持续更新) 相信很多小伙伴在做数据分析或者可视化的时候,经常会遇到--方法工具都有了,但是数据,数据,数据没有啊! 好不容易找到了看起来还不错的网站,再一看,年费 ...

  9. 【转】内存中找怪物之代码注入篇

    导读: 网上看了N多的文章,对内存中找怪极少有详细介绍,大多数人搞定人物内存中的有关参数后,止步于内存中的找怪.人物只有一个,而怪有各种各样的,数量又同时出现多个,比在内存中找人物坐标难度要大得多. ...

最新文章

  1. ie浏览器修复工具_电脑故障修复不求人!50个小工具可帮你一键修复
  2. 如何修改 Linkis 依赖的 Spark、Hive 版本?
  3. VMWare虚拟系统上网设置及VMWare虚拟机三种工作模式详解
  4. linux互传文件nc命令
  5. 使用Spring.Net进行Webservice开发发布遇到的问题
  6. 4.Linux性能诊断 --- Linux工作流程内存管理
  7. Dymola — 多学科系统仿真平台
  8. 足球机器人比赛3V3
  9. 扫雷——Windows上的经典小游戏
  10. 2017公共DNS服务器评估报告——公共DNS推荐(摘录)
  11. 新浪公司总裁兼首席执行官 曹国伟
  12. 【windows】常见的系统环境变量,如%appdata%表示什么意思
  13. ohoTips - 最屌的消息弹窗工具!
  14. Web安全-ReDos正则表达式的拒绝服务攻击
  15. SEO人员,为什么要做流量过滤,如何操作?
  16. 数据库数据修改报错The instance of entity type ‘XXX‘ cannot be tracked
  17. tiny4412 设备树之i2c设备(二)
  18. rabbitMQ在linux上安装教程和问题解决
  19. C++资料整理(持续更新)
  20. 华为手机如何连接无线打印服务器,惊呆了!华为Mate 20居然支持无线打印

热门文章

  1. 如何用LaTeX写一个PPT
  2. [Mac软件推荐] 三款提高 Mac 使用效率的必备软件
  3. 叉积 微分 恒等式_不等式(O):常见符号及恒等式
  4. Xposed插件的编写
  5. c语言窗口插入图片,c语言添加图片Word版
  6. Touch in Android
  7. 制作角色血条 [代码清单10-2]
  8. 阿卜杜拉国王科技大学的计算机,阿卜杜拉国王科技大学(KAUST)探索奖学金项目...
  9. 阿里 VP 贾扬清确认离职!尚未创立公司,方向或是 AI 架构?
  10. C++实现 1432. 棋盘挑战