好久没有发OpenCV的博客了,最近想到了一个识别地图轮廓的方案,就写来试试。(识别中国的28个省份地图轮廓,不考虑直辖市)

首先,我的基本思路是  用最小的矩形将地图的轮廓圈出来,可以根据长方形的长宽比判断,也可将其缩放至特定的大小,计算其轮廓上的像素个数来判断。

缺点:用摄像头读取图片时,使用这种方法会有一些误差。

也可以ANN训练识别,但是这样做效率低。

step 1. 读取图片、处理图像

  1. Mat src = imread("12.jpg");
  2. Mat grayImage;
  3. cvtColor(src, grayImage, CV_BGR2GRAY);
  4. threshold(grayImage, grayImage, , , CV_THRESH_BINARY);
  5. imshow("grayImage", grayImage);

问题来了,处理图片后的grayImage根本无法显示,结果为一张灰色的图片。

最后发现,因为大意,程序的最后没有加 cvWaitKey(0); 这句话,因此图片无法显示。

step 2. 寻找轮廓并画出

  1. #include <opencv2/opencv.hpp>
  2. #include <iostream>
  3. using namespace cv;
  4. using namespace std;
  5.  
  6. int main()
  7. {
  8. Mat src = imread("timg.jpg");
  9. Mat grayImage, dstImage;
  10. src.copyTo(dstImage);
  11.  
  12. int g_nStructElementSize = ; //结构元素(内核矩阵)的尺寸
  13. //获取自定义核
  14. Mat element = getStructuringElement(MORPH_RECT,
  15. Size( * g_nStructElementSize + , * g_nStructElementSize + ),
  16. Point(g_nStructElementSize, g_nStructElementSize));
  17. erode(src, src, element);
  18. cvtColor(src, grayImage, CV_BGR2GRAY);
  19. threshold(grayImage, grayImage, , , CV_THRESH_BINARY);
  20. imshow("2dst", grayImage);
  21.  
  22. vector<vector<Point>> contours;
  23. vector<Vec4i> hierarchy;
  24. findContours(grayImage, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
  25. int i = ;
  26. Point2f pp[][];
  27. vector<vector<Point>>::iterator It;
  28. Rect rect[];
  29. for (It = contours.begin(); It < contours.end(); It++){ //画出包围轮廓的最小矩形
  30. Point2f vertex[];
  31. rect[i] = boundingRect(*It);
  32. vertex[] = rect[i].tl(); //矩阵左上角的点
  33. vertex[].x = (float)rect[i].tl().x, vertex[].y = (float)rect[i].br().y; //矩阵左下方的点
  34. vertex[] = rect[i].br(); //矩阵右下角的点
  35. vertex[].x = (float)rect[i].br().x, vertex[].y = (float)rect[i].tl().y; //矩阵右上方的点
  36.  
  37. for (int j = ; j < ; j++)
  38. line(dstImage, vertex[j], vertex[(j + ) % ], Scalar(, , ), );
  39. }
  40. imshow("dst", dstImage);
  41. cvWaitKey();
  42. return ;
  43. }

结果发现根本找不到轮廓,最后发现原来是threshold函数参数设置错误,参数应如下:

  1. threshold(grayImage, grayImage,,, THRESH_BINARY_INV);

同时由于地图边框线太细,应当先腐蚀图像,再二值化:

  1. int g_nStructElementSize = ; //结构元素(内核矩阵)的尺寸
  2. ///获取自定义核
  3. Mat element = getStructuringElement(MORPH_RECT,
  4. Size( * g_nStructElementSize + , * g_nStructElementSize + ),
  5. Point(g_nStructElementSize, g_nStructElementSize));
  6. erode(src, src, element);

step 3. 收集地图的数据后,用10个省得数据来检测

最后在不断的探索中,发现有两个数据可以作为一个地图的特征,即轮廓长宽比和轮廓面积与图片的像素数之比。

最后的代码如下:

  1. #include <opencv2/opencv.hpp>
  2. #include <iostream>
  3. #include <math.h>
  4. using namespace cv;
  5. using namespace std;
  6.  
  7. Mat result;
  8. const double cha = 0.02; //可接受范围的误差
  9.  
  10. bool compare(double a, double b)
  11. {
  12. if (abs(a - b) < cha){
  13. return true;
  14. }
  15. return false;
  16. }
  17.  
  18. bool result_output(double rate1,double rate2)
  19. {
  20. if (compare(rate1, (double) / ) && compare(rate2, 0.171524)){
  21. cout << "陕西省" << endl;
  22. return true;
  23. }
  24. if (compare(rate1, (double) / ) && compare(rate2, 0.270173)){
  25. cout << "安徽省" << endl;
  26. return true;
  27. }
  28. if (compare(rate1, (double) / ) && compare(rate2, 0.230148)){
  29. cout << "福建省" << endl;
  30. return true;
  31. }
  32. if (compare(rate1, (double) / ) && compare(rate2, 0.132584)){
  33. cout << "甘肃省" << endl;
  34. return true;
  35. }
  36. if (compare(rate1, (double) / ) && compare(rate2, 0.200146)){
  37. cout << "广东省" << endl;
  38. return true;
  39. }
  40. if (compare(rate1, (double) / ) && compare(rate2, 0.22718)){
  41. cout <<"广西壮族自治区" << endl;
  42. return true;
  43. }
  44. if (compare(rate1, (double) / ) && compare(rate2, 0.219451)){
  45. cout << "贵州省" << endl;
  46. return true;
  47. }
  48. if (compare(rate1, (double) / ) && compare(rate2, 0.196616)){
  49. cout << "海南省" << endl;
  50. return true;
  51. }
  52. if (compare(rate1, (double) / ) && compare(rate2, 0.247134)){
  53. cout << "河北省" << endl;
  54. return true;
  55. }
  56. if (compare(rate1, (double) / ) && compare(rate2, 0.176323)){
  57. cout << "河南省" << endl;
  58. return true;
  59. }
  60. cout << "无法检测" << endl;
  61. return false;
  62. }
  63. int main()
  64. {
  65. Mat src = imread("1.jpg");
  66. Mat grayImage, dstImage;
  67. src.copyTo(dstImage);
  68.  
  69. int g_nStructElementSize = ; //结构元素(内核矩阵)的尺寸
  70. ///获取自定义核
  71. Mat element = getStructuringElement(MORPH_RECT,
  72. Size( * g_nStructElementSize + , * g_nStructElementSize + ),
  73. Point(g_nStructElementSize, g_nStructElementSize));
  74. erode(src, src, element);
  75. cvtColor(src, grayImage, CV_BGR2GRAY);
  76. blur(grayImage, grayImage, Size(, ));
  77. threshold(grayImage, grayImage,,, THRESH_BINARY_INV);
  78. grayImage.copyTo(result);
  79.  
  80. vector< vector<Point> > contours;
  81. vector<Vec4i> hierarchy;
  82. findContours(grayImage, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
  83. drawContours(dstImage, contours, -, (, , ));
  84. vector<Point> point = contours[];
  85.  
  86. Rect rect = boundingRect(point);
  87. Point2f vertex[];
  88. vertex[] = rect.tl();
  89. vertex[].x = (float)rect.tl().x, vertex[].y = (float)rect.br().y;
  90. vertex[] = rect.br();
  91. vertex[].x = (float)rect.br().x, vertex[].y = (float)rect.tl().y;
  92. for (int j = ; j < ; j++)
  93. line(dstImage, vertex[j], vertex[(j + ) % ], Scalar(, , ), );
  94. int x = rect.x, y = rect.y;
  95. int h = rect.height, w = rect.width;
  96. double rate = (double)h / w;
  97. cout << "height:" << h << endl;
  98. cout << "width:" << w << endl;
  99. cout << "h / w:" << rate << endl;
  100. double area = contourArea(point, false);
  101. double sum = grayImage.cols * grayImage.rows;
  102. cout << "面积:" << area << endl;
  103. cout << "面积比:" << area / sum << endl;
  104.  
  105. imshow("show", dstImage);
  106. result_output(rate, area / sum);
  107.  
  108. cvWaitKey();
  109. return ;
  110. }

最后发现一个问题,由于需要通过摄像头检测地图,图片可能会有一定角度的倾斜,因此应将Rect换成RotatedRect。

  1. RotatedRect rect = minAreaRect(point);
  2. Point2f vertex[];
  3. rect.points(vertex);
  4. for (int j = ; j < ; j++)
  5. line(dstImage, vertex[j], vertex[(j + ) % ], Scalar(, , ), );
  6.  
  7. int h = rect.size.height, w = rect.size.width;

OpenCV——识别各省份地图轮廓的更多相关文章

  1. 【可视化】Echarts3 在世界地图中绘制中国各省份的轮廓

    要在世界地图展现出来的情况下绘制中国省份的轮廓,根据现有的echarts-api是不可行的. 但好在echarts也提供了自定义地图的方式,使用echarts.registerMap();来实现 第一 ...

  2. 转载:使用 OpenCV 识别 QRCode

    原文链接:http://coolshell.cn/articles/10590.html#jtss-tsina 识别二维码的项目数不胜数,每次都是开箱即用,方便得很. 这次想用 OpenCV 从零识别 ...

  3. 基于opencv 识别、定位二维码 (c++版)

    前言 因工作需要,需要定位图片中的二维码:我遂查阅了相关资料,也学习了opencv开源库.通过一番努力,终于很好的实现了二维码定位.本文将讲解如何使用opencv定位二维码. 定位二维码不仅仅是为了识 ...

  4. 基于Opencv识别,矫正二维码(C++)

    参考链接 [ 基于opencv 识别.定位二维码 (c++版) ](https://www.cnblogs.com/yuanchenhui/p/opencv_qr.html) OpenCV4.0.0二 ...

  5. opencv的实用研究--分析轮廓并寻找边界点

    opencv的实用研究--分析轮廓并寻找边界点 ​      轮廓是图像处理中非常常见的.对现实中的图像进行采样.色彩变化.灰度变化之后,能够处理得到的是“轮廓”.它直接地反应你了需要分析对象的边界特 ...

  6. OpenCV识别技术

    OpenCV识别技术# 老师:james 20181019 # 识别技术# Pycharm + Python3 + OpenCV """ 一.识别技术: 什么是OpenC ...

  7. jQuery中国各个省份地图分部代码

    jQuery中国各个省份地图分部代码 在线演示本地下载

  8. OpenCV——识别印刷体数字

    数字识别和其他的所有计算机视觉相关的应用都会分为两个步骤:ROI抽取和识别. 1. ROI抽取即将感兴趣的区域从原始图像中分离初来,这个步骤包括二值化,噪点的消除等2. 识别即通过一些分类器将第一步中 ...

  9. python opencv识别蓝牌车牌号 之 取出车牌号 (1/3)

    概述 车牌识别是计算机视频图像识别技术在车辆牌照识别中的一种应用,通常来讲如果结合opencv进行车牌识别主要分为四个大步骤,分别为: 图像采集 车牌定位 分割车牌字符 字符识别 当然,如果结合了机器 ...

随机推荐

  1. zXing使用注意事项-转

    zXing使用注意事项   ------------------ zxing和zbar的比较: ZXing项目的示例程序对于摄像头的控制写的非常全面,ZBar的没有ZBar基于C语言编写,解码效率高于 ...

  2. 嵌入式开发之zynq---Zynq PS侧I2C驱动架构

    http://blog.chinaunix.net/uid-24148050-id-120532.html http://bbs.csdn.net/topics/390538368?page=1 ht ...

  3. 使用OpenSSL创建自己的CA root certificate

    在密码学中,CA(Certificate Authority,认证机构)是指一个被多个用户信任的机构,该机构能够创建和指派公钥证书. 为规范起见,我们先介绍本文可能涉及的术语, asymmetric ...

  4. jQuery Validation让验证变得如此easy(二)

    上一个样例我们是统一引用jquery.validate.js这样全部必填字段的提示信息都将是This field is required. 如今要改成动态提示,比方姓名假设为空则提示姓名不能为空,密码 ...

  5. [SQL Server] 复制数据库任务

    假设你要生产环境下的数据做相应的测试,比如修改及测试存储过程.更改和优化索引等.但是你用户在连接数据库的情况下,你又不能断开数据库的连接.如何取得数据库的副本呢? 一.  利用数据库任务中的复制数据库 ...

  6. yii2 页面渲染方法解析

    render渲染.renderPartial渲染部分.renderContent.renderAjax.renderFile ① render显示view和layout ② renderPartial ...

  7. unity3d 使用GL 方式画线

    这个是画线部分 private Vector3[] linePoints; public int m_LineCount; public int m_PointUsed; public void Re ...

  8. linux mysql远程连接的命令

    mysql -u 用户名 -h 远程IP地址 -p  随后输入密码. 要确认远程数据库3306端口是否开放,mysql服务是否启动. hadoop@Master:~$ mysql -u root -h ...

  9. CentOS 65 安装vmware tools 杂记

    CentOS 65中安装vmware tools时出现如下错误, centos vmware tools install failure ,no default label for /tmp/vmwa ...

  10. 性能监控-TP理解

    首先给出Google到的答案: The tp90 is a minimum time under which 90% of requests have been served. tp90 = top ...