好久没有发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——识别各省份地图轮廓的更多相关文章

  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. 第三百二十六节,web爬虫,scrapy模块,解决重复ur——自动递归url

    第三百二十六节,web爬虫,scrapy模块,解决重复url——自动递归url 一般抓取过的url不重复抓取,那么就需要记录url,判断当前URL如果在记录里说明已经抓取过了,如果不存在说明没抓取过 ...

  2. Unity5-----------之GI设置简介

    GI global illumination 全局照明indirect illumination 间接照明模拟出光线追踪的效果 实现方法:1.ssao系列 2.lightmap.辐射度3.PBRT 实 ...

  3. jQuery回调、递延对象总结

    jQuery回调.递延对象总结(上篇)—— jQuery.Callbacks jQuery回调.递延对象总结(中篇) —— 神奇的then方法 jQuery回调.递延对象总结(下篇) —— 解密jQu ...

  4. Python——thread

    该模块在Python 3中更名为 _thread. 该模块实现对Python多线程的低层次操作原语,也提供了多线程之间用于同步的锁机制.threading 模块基于本模块提供了更易用的高层次线程API ...

  5. powerDesigner生成Html及Word

    转载地址:https://blog.csdn.net/zdp072/article/details/51900794 1:点击Reports 2:点击New Reports 3:定义名字,选择简体中文 ...

  6. spring cloud feign 上传文件报not a type supported by this encoder解决方案

    上传文件调用外部服务报错: not a type supported by this encoder 查看SpringFormEncoder类的源码: public class SpringFormE ...

  7. spring 配置 Java配置类装配bean

    https://www.cnblogs.com/chenbenbuyi/p/8457700.html 自动化装配的确有很大的便利性,但是却并不能适用在所有的应用场景,比如需要装配的组件类不是由自己的应 ...

  8. WPF TextBox属性IsReadOnlyCaretVisible

    纠结了半天WPF下只读的TextBox怎么显示输入焦点提示,发现wpf 4中已有新属性“IsReadOnlyCaretVisible”,大善^_^

  9. Spring学习总结六——SpringMVC一

    一:什么是springMVC MVC,顾名思义,m就是model模型,包括处理业务.访问数据库以及封装数据实体类等,view视图层 负责和用户进行交互,就是展示给用户的部分,包括jsp页面,html等 ...

  10. pycahrm使用docstrings来指定变量类型、返回值类型、函数参数类型

    py里面不需要显示声明类型,这和java c这些静态语言不同,虽然python这样做少了一些代码和写代码的困难度,但还是非常多的弊端的,运行速度 代码安全, 这些都是语言本身带来的本的弊端,这些没办法 ...