准确检测图像的轮廓 opencv_图像处理案例实战

0260f96f-4a13-eb11-8da9-e4434bdf6706.png

1. 切边

源图像:

0460f96f-4a13-eb11-8da9-e4434bdf6706.png

需求:扫描仪扫描到的法律文件,需要切边,去掉边缘空白,这样看上去才真实,人工操作成本与时间花费高,希望程序自动实现,高效、准确。 实现思路:边缘检测 + 轮廓发现或直线检测最大外接矩形。

例子代码:

#include

效果图

0660f96f-4a13-eb11-8da9-e4434bdf6706.png

总结:先利用 Canny 算子检测图像的轮廓,再利用 findContours 发现轮廓,因为这时候会得到很多轮廓,而我们只需要找到最大的轮廓,这时候可以根据源图像的情况设置过滤的条件(如本例中宽高设为不小于0.75)。找到这个矩形后,再把它画出来即可。

2. 直线检测

源图像:

0960f96f-4a13-eb11-8da9-e4434bdf6706.png

需求:寻找英语试卷填空题的下划线,这个对后期的切图与自动识别都比较重要。 实现思路:通过图像形态学操作来寻找直线,霍夫获取位置信息与显示

例子代码:

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
Mat srcImg, roiImg;
void detectLine();
void test()
{srcImg = imread("test2.jpg",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);//因为是截图,所以要去掉白边,用ROI图像的方法Rect roi = Rect(10, 10, srcImg.cols - 15, srcImg.rows - 15);  //切掉白边roiImg = srcImg(roi);namedWindow("Roi image", CV_WINDOW_NORMAL);imshow("Roi image", roiImg);detectLine();
}void detectLine()
{
Mat binaryImg, morhpImg;threshold(roiImg, binaryImg, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);  //二值化namedWindow("Binary Result", CV_WINDOW_NORMAL);imshow("Binary Result", binaryImg);//形态学操作Mat kernel = getStructuringElement(MORPH_RECT, Size(60, 1), Point(-1, -1));  morphologyEx(binaryImg, morhpImg, MORPH_OPEN, kernel, Point(-1, -1));namedWindow("Morphology Result", CV_WINDOW_NORMAL);imshow("Morphology Result", morhpImg);//膨胀,使得直线更加明显kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));dilate(morhpImg, morhpImg, kernel);namedWindow("Dilate Result", CV_WINDOW_NORMAL);imshow("Dilate Result", morhpImg);//霍夫变换标定直线vector<Vec4i> lines;   //每条线有两个点,把四个点的坐标存储起来HoughLinesP(morhpImg, lines, 1, CV_PI / 180.0, 30, 20.0, 0);  // 1 为极坐标方向上的步长Mat resultImg = roiImg.clone();   //输出结果cvtColor(resultImg, resultImg, COLOR_GRAY2BGR);for (int i = 0; i < lines.size(); i++){Vec4i ln = lines[i];  //取出直线line(resultImg, Point(ln[0], ln[1]), Point(ln[2], ln[3]), Scalar(0, 0, 255), 2, 8, 0);  //Point(ln[0], ln[1]), Point(ln[2], ln[3])两个坐标}namedWindow("Hough Lines-Final Result", CV_WINDOW_NORMAL);imshow("Hough Lines-Final Result", resultImg);
}
int main()
{test();waitKey(0);return 0;
}

效果图

0b60f96f-4a13-eb11-8da9-e4434bdf6706.png

总结:因为源图像是截图,所以最外围有白边,通常这种情况下可以利用 ROI 图像方法去掉不需要的部分,再通过二值化和形态学操作来寻找直线,最后利用霍夫概率变换获取直线的准确位置。

3. 对象提取

源图像:

0c60f96f-4a13-eb11-8da9-e4434bdf6706.png

需求:对图像中对象(圆形)进行提取,获取这样的对象,去掉其它干扰和非目标对象。并获取圆形的面积和周长。 实现思路:二值分割 + 形态学 + 横纵比计算。

步骤: - 找到对象的轮廓 - 通过面积、横纵比过滤点其它不需要的对象

第一步:发现轮廓 例子代码:

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
//第一步
Mat srcImg, binaryImg, dstImg;
void test()
{srcImg = imread("case3.png", IMREAD_GRAYSCALE);if (srcImg.empty()){cout << "could not load image...n" << endl;}namedWindow("Original image", 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());Mat resultImg = Mat::zeros(srcImg.size(), CV_8SC3);for (int i = 0; i < contours.size(); i++){drawContours(resultImg, contours, i, Scalar(0, 0, 255), 2, 8, Mat(), 0, Point());  //画出来}namedWindow("Final Result", CV_WINDOW_NORMAL);imshow("Final Result", resultImg);
}
int main()
{test();waitKey(0);return 0;
}

效果图

1260f96f-4a13-eb11-8da9-e4434bdf6706.png

第二步:过滤并计算面积和周长 例子代码:

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
//第二步 通过面积过滤,通过纵横比的测量,圆形的纵横比应该在1:1左右,如果不是1:1,就把它过滤掉
Mat srcImg, binaryImg, dstImg;
void test()
{srcImg = imread("case3.png", 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, 2, Scalar(0, 0, 255), 2, 8, 0);namedWindow("Center Point", CV_WINDOW_NORMAL);imshow("Center Point", circleImg);
}int main()
{test();waitKey(0);return 0;
}

效果图

1360f96f-4a13-eb11-8da9-e4434bdf6706.png

总结:首先把图像二值化,通过闭操作把中间小的洞连接上,再通过开操作把周围小的点去掉,再通过轮廓发现找到对象的轮廓。再通过面积、纵横比过滤点其它不需要的对象,圆形的纵横比应该在1:1左右,如果不是1:1,就把它过滤掉。然后再计算面积和周长。


欢迎关注我的微信公众号“OpenCV图像处理算法”,主要是记录自己学习图像处理算法的历程,包括特征提取、目标跟踪、定位、机器学习和深度学习,每一个例子都会提供源码和例子所用的资料,欢迎同行的同学关注我和我一起虚度光阴吧!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/435518.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pp助手苹果版_再见!PP助手iOS端即将下线 曾是中国最大的苹果助手

苹果PP助手即将下线 在今日PP助手官方发布公告&#xff1a;尊敬的PP助手iOS版用户&#xff1a;衷心感谢您多年以来对我们的支持及厚爱。因业务调整&#xff0c;PP助手将于2020年2月28日正式下线iOS版产品&#xff0c;包括PP助手iOS版、PP助手iOS PC版等。 对您造成的不便还望理…

oppo手机工程模式清除数据需要密码_手机隐藏的快捷键都有哪些?

手机从开发出来到现在&#xff0c;已经换了很多代了&#xff0c;从大哥大&#xff0c;小灵通&#xff0c;到诺基亚到山寨机到苹果到华为&#xff0c;几十年过去了。手机从奢侈品一下飞去每个人手里&#xff0c;反正我手机有手机已经快10年了&#xff0c;所以我相信每个人对自己…

关于竖表转横表的问题

本文作者&#xff1a;dinya内容摘要&#xff1a;在开发过程&#xff0c;经常遇到一些将表的显示方式进行转换的需求&#xff0c;我们习惯性称之为竖表到横表的转换&#xff0c;本文通过一个例子来简要说明常见的两种竖表转横表的问题。本文适宜读者范围&#xff1a;oracle初级&…

全系光谱完整版

宇宙射线也叫电磁波&#xff0c;其中包含γ射线、X射线、紫外线、可见光、红外线、近红外、远红外&#xff0c;还有无线电和超声波。 无线电波是振荡电路中自由电子作周期性的运动产生的&#xff0e; 红外线、可见光、紫外线是原子外层电子受激发产生的&#xff0e; X射线是原…

cat 几行_迷风花说Cat!Cat因为林教练是好教练回去现实却给了一巴掌

滔博TES前主教练迷风花26日发布了微博&#xff0c;就自己离职、Cat林教练事件以及汤汤纵情转会事件进行了澄清&#xff0c;网友粉丝们在看到教练迷风花发布的微博后&#xff0c;更加了解了很多事情的真相&#xff0c;粉丝们纷纷对教练迷风花送上了祝福&#xff0c;教练迷风花到…

前端和后端的英文_计算机专业的本科生在前端、后端、测试和运维之间该如何选择...

首先&#xff0c;对于计算机专业的同学来说&#xff0c;在选择发展方向的时候往往会遇到一些困惑&#xff0c;当前随着计算机技术体系的不断壮大&#xff0c;计算机领域的岗位分类也越来越细化&#xff0c;而且在新技术的推动下&#xff0c;还在不断出现新的岗位&#xff0c;比…

医学影像后处理技术超详细收藏版(上)

转自&#xff1a;医学影像后处理技术超详细收藏版&#xff08;上&#xff09; 导语&#xff1a; 医学图像后处理是通过综合运用计算机图像处理技术&#xff0c;医学知识&#xff0c;将由各种数字化成像技术所获得的人体信息按照一定的需要在计算机上表现出来&#xff0c;使之…

【转】VTK和ITK中的坐标系统

当我们在处理医学图像和应用时&#xff0c;一个问题就是坐标系统之间的不同。在图像应用中通常有三个坐标系&#xff0c;分别是世界坐标系&#xff0c;解剖坐标系和图像坐标系。 每种坐标系目的不同&#xff0c;呈现数据的方式也不一样。 解剖坐标系由三个平面组成&#xff0c;…

(ZT)在日本市场推广 iPhone 应用的经验

原贴&#xff1a;http://www.cocoachina.com/appstore/market/2010/0728/1942.html 本文作者为 CocoaChina 会员 “lawrencewu”&#xff0c;是一位专攻日本市场的 iPhone 开发者。他的10款 App &#xff08;9个收费&#xff0c;一个免费&#xff09;在9个月的时间里已经取得了…

嵌入式系统 Boot Loader 技术内幕

1. 引言 在专用的嵌入式板子运行 GNU/Linux 系统已经变得越来越流行。一个嵌入式 Linux 系统从软件的角度看通常可以分为四个层次&#xff1a; 1. 引导加载程序。包括固化在固件(firmware)中的 boot 代码(可选)&#xff0c;和 Boot Loader 两大部分。 2. Linux 内核。特定于嵌入…

互联网医院 2020年突出成就_【关注】中国社科院发布2020中国医院互联网影响力排行榜...

导 读:11月4日&#xff0c;中国社科院健康业发展研究中心联合好大夫在线&#xff0c;发布2020中国医院互联网影响力排行榜&#xff0c;这是该榜单连续第5年发布。中国社科院健康业发展研究中心以好大夫在线平台611.6亿次的患者浏览轨迹、6648万患者的在线问诊记录、4.7亿次医…

h5链接加上 vconsole_又出爆款!凯美瑞和红旗H5没法比!

论舒适性而言&#xff0c;三厢版车型的优势还是十分明显的。基本可以满足日常商务用途和家用等多种用车环境。今天带来的两款车都是三厢车&#xff0c;分别是红旗H5和宝马1系。那这两款车究竟是骡子是马&#xff0c;还是让大家一起来看看它们的实际表现吧。车型&#xff1a;红旗…

HDOJ 1010 HDU 1010 Tempter of the Bone ACM 1010 IN HDU

MiYu原创, 转帖请注明 : 转载自 ______________白白の屋题目地址:http://acm.hdu.edu.cn/showproblem.php?pid1010 题目描述:代码Tempter of the BoneTime Limit: 2000/1000MS (Java/Others) Memory Limit: 65536/32768K (Java/Others)Total Submission(s): 16817Accepted …

console application_灵活使用 console 让 js 调试更简单

摘要&#xff1a; 玩转console。原文&#xff1a;灵活使用 console 让 js 调试更简单作者&#xff1a;前端小智Fundebug经授权转载&#xff0c;版权归原作者所有。Web 开发最常用的高度就是 console.log &#xff0c;虽然 console.log 占有一席之地&#xff0c;但很多人并没有意…

a byte of python中文版_面试官问 Python 版 “垃圾回收”机制,我没答上来

点击“开发者技术前线”&#xff0c;选择“星标?”13&#xff1a;21 在看|星标|留言, 真爱选自《萌萌哒的柯基》 作者&#xff1a;heroyfhttps://www.heroyf.club/2019/10/23/python_gc/前言对于python来说&#xff0c;一切皆为对象&#xff0c;所有的变量赋值都遵循着对象引…

漫谈 Linux,Windows 和 Mac

好了&#xff0c;现在来一点技术性的。这段时间收到很多人的来信&#xff08;大部分自称是菜鸟&#xff09;。他们看了我很早以前写的推崇 Linux 的文章&#xff0c;想知道如何“抛弃 Windows&#xff0c;学习 Linux”。天知道他们在哪里找到那么老的文章&#xff0c;真是好事不…

AspNet2.0页面生命周期

AspNet2.0页面生命周期 页面框架通过如下过程处理aspx文件请求: 1&#xff1a;解析aspx文件,并创建一个控件树&#xff1b; 2&#xff1a;使用控件树动态实现一个继承自Page类的类或者控件 &#xff1b; 3&#xff1a;动态编译类&#xff1b; 4&#xff1a;缓存编…

数字时钟设计verilog_数字IC设计基本概念之创建时钟

来自微信公众号 “数字芯片实验室”时序分析的一个重要部分是准确地指定时钟和相关属性&#xff0c;例如延迟&#xff08;latency&#xff09;和不确定性&#xff08;uncertainty&#xff09;。 EDA工具可以分析以下类型的时钟信息&#xff1a;时钟网络latency和 skew&#xff…

敏捷开发流程的8个步骤_敏捷开发——个体和互动高于流程和工具

敏捷开发是软件公司主流的项目管理方法&#xff0c;敏捷方法论有许多种&#xff0c;包括Scrum、极限编程(XP)以及精益(Lean)方法&#xff0c;但是它们都具有一个共同点&#xff1a;遵循敏捷宣言和敏捷原则。透明性。每一个敏捷项目成员都知道即将做什么以及项目进展如何。经常性…

ArcGis Desktop10 注册机授权方法与安装步骤

今天&#xff0c;由于需要处理一些空间数据&#xff0c;安装ArcGIS Desktop10&#xff0c;所以就把注册机的授权方法与安装过程&#xff0c;写成Blog与大家一起分享&#xff01; 第一步&#xff1a;安装 ArcGIS许可管理器。如图所示&#xff1a; 第二步&#xff1a;打开注册机&…