OpenCV——识别各省份地图轮廓
好久没有发OpenCV的博客了,最近想到了一个识别地图轮廓的方案,就写来试试。(识别中国的28个省份地图轮廓,不考虑直辖市)
首先,我的基本思路是 用最小的矩形将地图的轮廓圈出来,可以根据长方形的长宽比判断,也可将其缩放至特定的大小,计算其轮廓上的像素个数来判断。
缺点:用摄像头读取图片时,使用这种方法会有一些误差。
也可以ANN训练识别,但是这样做效率低。
step 1. 读取图片、处理图像
- Mat src = imread("12.jpg");
- Mat grayImage;
- cvtColor(src, grayImage, CV_BGR2GRAY);
- threshold(grayImage, grayImage, , , CV_THRESH_BINARY);
- imshow("grayImage", grayImage);
问题来了,处理图片后的grayImage根本无法显示,结果为一张灰色的图片。
最后发现,因为大意,程序的最后没有加 cvWaitKey(0); 这句话,因此图片无法显示。
step 2. 寻找轮廓并画出
- #include <opencv2/opencv.hpp>
- #include <iostream>
- using namespace cv;
- using namespace std;
- int main()
- {
- Mat src = imread("timg.jpg");
- Mat grayImage, dstImage;
- src.copyTo(dstImage);
- int g_nStructElementSize = ; //结构元素(内核矩阵)的尺寸
- //获取自定义核
- Mat element = getStructuringElement(MORPH_RECT,
- Size( * g_nStructElementSize + , * g_nStructElementSize + ),
- Point(g_nStructElementSize, g_nStructElementSize));
- erode(src, src, element);
- cvtColor(src, grayImage, CV_BGR2GRAY);
- threshold(grayImage, grayImage, , , CV_THRESH_BINARY);
- imshow("2dst", grayImage);
- vector<vector<Point>> contours;
- vector<Vec4i> hierarchy;
- findContours(grayImage, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
- int i = ;
- Point2f pp[][];
- vector<vector<Point>>::iterator It;
- Rect rect[];
- for (It = contours.begin(); It < contours.end(); It++){ //画出包围轮廓的最小矩形
- Point2f vertex[];
- rect[i] = boundingRect(*It);
- vertex[] = rect[i].tl(); //矩阵左上角的点
- vertex[].x = (float)rect[i].tl().x, vertex[].y = (float)rect[i].br().y; //矩阵左下方的点
- vertex[] = rect[i].br(); //矩阵右下角的点
- vertex[].x = (float)rect[i].br().x, vertex[].y = (float)rect[i].tl().y; //矩阵右上方的点
- for (int j = ; j < ; j++)
- line(dstImage, vertex[j], vertex[(j + ) % ], Scalar(, , ), );
- }
- imshow("dst", dstImage);
- cvWaitKey();
- return ;
- }
结果发现根本找不到轮廓,最后发现原来是threshold函数参数设置错误,参数应如下:
- threshold(grayImage, grayImage,,, THRESH_BINARY_INV);
同时由于地图边框线太细,应当先腐蚀图像,再二值化:
- int g_nStructElementSize = ; //结构元素(内核矩阵)的尺寸
- ///获取自定义核
- Mat element = getStructuringElement(MORPH_RECT,
- Size( * g_nStructElementSize + , * g_nStructElementSize + ),
- Point(g_nStructElementSize, g_nStructElementSize));
- erode(src, src, element);
step 3. 收集地图的数据后,用10个省得数据来检测
最后在不断的探索中,发现有两个数据可以作为一个地图的特征,即轮廓长宽比和轮廓面积与图片的像素数之比。
最后的代码如下:
- #include <opencv2/opencv.hpp>
- #include <iostream>
- #include <math.h>
- using namespace cv;
- using namespace std;
- Mat result;
- const double cha = 0.02; //可接受范围的误差
- bool compare(double a, double b)
- {
- if (abs(a - b) < cha){
- return true;
- }
- return false;
- }
- bool result_output(double rate1,double rate2)
- {
- if (compare(rate1, (double) / ) && compare(rate2, 0.171524)){
- cout << "陕西省" << endl;
- return true;
- }
- if (compare(rate1, (double) / ) && compare(rate2, 0.270173)){
- cout << "安徽省" << endl;
- return true;
- }
- if (compare(rate1, (double) / ) && compare(rate2, 0.230148)){
- cout << "福建省" << endl;
- return true;
- }
- if (compare(rate1, (double) / ) && compare(rate2, 0.132584)){
- cout << "甘肃省" << endl;
- return true;
- }
- if (compare(rate1, (double) / ) && compare(rate2, 0.200146)){
- cout << "广东省" << endl;
- return true;
- }
- if (compare(rate1, (double) / ) && compare(rate2, 0.22718)){
- cout <<"广西壮族自治区" << endl;
- return true;
- }
- if (compare(rate1, (double) / ) && compare(rate2, 0.219451)){
- cout << "贵州省" << endl;
- return true;
- }
- if (compare(rate1, (double) / ) && compare(rate2, 0.196616)){
- cout << "海南省" << endl;
- return true;
- }
- if (compare(rate1, (double) / ) && compare(rate2, 0.247134)){
- cout << "河北省" << endl;
- return true;
- }
- if (compare(rate1, (double) / ) && compare(rate2, 0.176323)){
- cout << "河南省" << endl;
- return true;
- }
- cout << "无法检测" << endl;
- return false;
- }
- int main()
- {
- Mat src = imread("1.jpg");
- Mat grayImage, dstImage;
- src.copyTo(dstImage);
- int g_nStructElementSize = ; //结构元素(内核矩阵)的尺寸
- ///获取自定义核
- Mat element = getStructuringElement(MORPH_RECT,
- Size( * g_nStructElementSize + , * g_nStructElementSize + ),
- Point(g_nStructElementSize, g_nStructElementSize));
- erode(src, src, element);
- cvtColor(src, grayImage, CV_BGR2GRAY);
- blur(grayImage, grayImage, Size(, ));
- threshold(grayImage, grayImage,,, THRESH_BINARY_INV);
- grayImage.copyTo(result);
- vector< vector<Point> > contours;
- vector<Vec4i> hierarchy;
- findContours(grayImage, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
- drawContours(dstImage, contours, -, (, , ));
- vector<Point> point = contours[];
- Rect rect = boundingRect(point);
- Point2f vertex[];
- vertex[] = rect.tl();
- vertex[].x = (float)rect.tl().x, vertex[].y = (float)rect.br().y;
- vertex[] = rect.br();
- vertex[].x = (float)rect.br().x, vertex[].y = (float)rect.tl().y;
- for (int j = ; j < ; j++)
- line(dstImage, vertex[j], vertex[(j + ) % ], Scalar(, , ), );
- int x = rect.x, y = rect.y;
- int h = rect.height, w = rect.width;
- double rate = (double)h / w;
- cout << "height:" << h << endl;
- cout << "width:" << w << endl;
- cout << "h / w:" << rate << endl;
- double area = contourArea(point, false);
- double sum = grayImage.cols * grayImage.rows;
- cout << "面积:" << area << endl;
- cout << "面积比:" << area / sum << endl;
- imshow("show", dstImage);
- result_output(rate, area / sum);
- cvWaitKey();
- return ;
- }
最后发现一个问题,由于需要通过摄像头检测地图,图片可能会有一定角度的倾斜,因此应将Rect换成RotatedRect。
- RotatedRect rect = minAreaRect(point);
- Point2f vertex[];
- rect.points(vertex);
- for (int j = ; j < ; j++)
- line(dstImage, vertex[j], vertex[(j + ) % ], Scalar(, , ), );
- int h = rect.size.height, w = rect.size.width;
OpenCV——识别各省份地图轮廓的更多相关文章
- 【可视化】Echarts3 在世界地图中绘制中国各省份的轮廓
要在世界地图展现出来的情况下绘制中国省份的轮廓,根据现有的echarts-api是不可行的. 但好在echarts也提供了自定义地图的方式,使用echarts.registerMap();来实现 第一 ...
- 转载:使用 OpenCV 识别 QRCode
原文链接:http://coolshell.cn/articles/10590.html#jtss-tsina 识别二维码的项目数不胜数,每次都是开箱即用,方便得很. 这次想用 OpenCV 从零识别 ...
- 基于opencv 识别、定位二维码 (c++版)
前言 因工作需要,需要定位图片中的二维码:我遂查阅了相关资料,也学习了opencv开源库.通过一番努力,终于很好的实现了二维码定位.本文将讲解如何使用opencv定位二维码. 定位二维码不仅仅是为了识 ...
- 基于Opencv识别,矫正二维码(C++)
参考链接 [ 基于opencv 识别.定位二维码 (c++版) ](https://www.cnblogs.com/yuanchenhui/p/opencv_qr.html) OpenCV4.0.0二 ...
- opencv的实用研究--分析轮廓并寻找边界点
opencv的实用研究--分析轮廓并寻找边界点 轮廓是图像处理中非常常见的.对现实中的图像进行采样.色彩变化.灰度变化之后,能够处理得到的是“轮廓”.它直接地反应你了需要分析对象的边界特 ...
- OpenCV识别技术
OpenCV识别技术# 老师:james 20181019 # 识别技术# Pycharm + Python3 + OpenCV """ 一.识别技术: 什么是OpenC ...
- jQuery中国各个省份地图分部代码
jQuery中国各个省份地图分部代码 在线演示本地下载
- OpenCV——识别印刷体数字
数字识别和其他的所有计算机视觉相关的应用都会分为两个步骤:ROI抽取和识别. 1. ROI抽取即将感兴趣的区域从原始图像中分离初来,这个步骤包括二值化,噪点的消除等2. 识别即通过一些分类器将第一步中 ...
- python opencv识别蓝牌车牌号 之 取出车牌号 (1/3)
概述 车牌识别是计算机视频图像识别技术在车辆牌照识别中的一种应用,通常来讲如果结合opencv进行车牌识别主要分为四个大步骤,分别为: 图像采集 车牌定位 分割车牌字符 字符识别 当然,如果结合了机器 ...
随机推荐
- zXing使用注意事项-转
zXing使用注意事项 ------------------ zxing和zbar的比较: ZXing项目的示例程序对于摄像头的控制写的非常全面,ZBar的没有ZBar基于C语言编写,解码效率高于 ...
- 嵌入式开发之zynq---Zynq PS侧I2C驱动架构
http://blog.chinaunix.net/uid-24148050-id-120532.html http://bbs.csdn.net/topics/390538368?page=1 ht ...
- 使用OpenSSL创建自己的CA root certificate
在密码学中,CA(Certificate Authority,认证机构)是指一个被多个用户信任的机构,该机构能够创建和指派公钥证书. 为规范起见,我们先介绍本文可能涉及的术语, asymmetric ...
- jQuery Validation让验证变得如此easy(二)
上一个样例我们是统一引用jquery.validate.js这样全部必填字段的提示信息都将是This field is required. 如今要改成动态提示,比方姓名假设为空则提示姓名不能为空,密码 ...
- [SQL Server] 复制数据库任务
假设你要生产环境下的数据做相应的测试,比如修改及测试存储过程.更改和优化索引等.但是你用户在连接数据库的情况下,你又不能断开数据库的连接.如何取得数据库的副本呢? 一. 利用数据库任务中的复制数据库 ...
- yii2 页面渲染方法解析
render渲染.renderPartial渲染部分.renderContent.renderAjax.renderFile ① render显示view和layout ② renderPartial ...
- unity3d 使用GL 方式画线
这个是画线部分 private Vector3[] linePoints; public int m_LineCount; public int m_PointUsed; public void Re ...
- linux mysql远程连接的命令
mysql -u 用户名 -h 远程IP地址 -p 随后输入密码. 要确认远程数据库3306端口是否开放,mysql服务是否启动. hadoop@Master:~$ mysql -u root -h ...
- CentOS 65 安装vmware tools 杂记
CentOS 65中安装vmware tools时出现如下错误, centos vmware tools install failure ,no default label for /tmp/vmwa ...
- 性能监控-TP理解
首先给出Google到的答案: The tp90 is a minimum time under which 90% of requests have been served. tp90 = top ...