初步认识

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>using namespace cv;
using namespace std;//声明一些全局变量,比如图像、模板和结果矩阵,以及匹配方法和窗口名称
Mat img; Mat templ; Mat result;
char* image_window = "Source Image";
char* result_window = "Result window";
int match_method;int main(int argc, char* argv[])
{//图片加载img = imread("E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\ocr\\1.png");templ = imread("E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\ocr\\template\\1.png");namedWindow(image_window, WINDOW_AUTOSIZE);namedWindow(result_window, WINDOW_AUTOSIZE);//创建将存储每个模板位置匹配结果的结果矩阵。详细观察结果矩阵的大小(匹配所有可能的位置)int result_cols = img.cols - templ.cols + 1;int result_rows = img.rows - templ.rows + 1;result.create(result_rows, result_cols, CV_32FC1);//执行模板匹配matchTemplate(img, templ, result, match_method);// 归一化normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());//利用cv::minMaxLoc对结果矩阵R中的最小值和最大值进行局部定位double minVal; double maxVal; Point minLoc; Point maxLoc;Point matchLoc;minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());//对于前两个方法(TM_SQDIFF和MT_SQDIFF_NORMED),最好的匹配是最小值。//对于其他来说,值越高代表匹配越好。因此,我们将相应的值保存在matchLoc变量中:if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED){matchLoc = minLoc;}else{matchLoc = maxLoc;}//显示源图像和结果矩阵。在可能匹配的最高区域周围画一个矩形rectangle(img, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );imshow( image_window, img);imshow( result_window, result );waitKey(0);destroyAllWindows();}

-

大图是匹配的效果

字符识别算法

想法:把所有的字符模板放到一张图片,根据其各自位置建一个列表,将分割好的图片一次检测匹配,根据其在模板大图上的位置,根据索引在列表找到对应的字符

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <imgproc.hpp>
#include <iostream>
#include <map>using namespace cv;
using namespace std;Mat getPos(Mat& image);//定位到字串的位置
void segChar(Mat& image);//字符分割 保存至文件夹
void charTem(Mat& image);//利用图像融合,做一个字符模板
string recog();//读取文件夹中char 图片,进行模板匹配,找到字符
//建立对应的字符字典
map<int, string> maps = { {0, "N",},{1, "J",},{2, "S",},{3, "G",},};int pos[4] = {};int main(int argc, char* argv[])
{//图片加载Mat img;img = imread("E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\1.png");//定位 并取出文字区域 Mat pos_img;pos_img = getPos(img);//分割每个字符图片 保存至文件夹segChar(pos_img);//实现字符的模板charTem(img);//识别string chars = recog();cout << chars << endl;imshow("test1", pos_img);waitKey(0);destroyAllWindows();}Mat getPos(Mat& image)
{Mat ret;Mat img_copy;image.copyTo(img_copy);Mat img = img_copy;//!!! 图像预处理 部分cvtColor(img_copy, img_copy, COLOR_BGR2GRAY);bitwise_not(img_copy, img_copy);//黑白像素取反GaussianBlur(img_copy, img_copy, Size(3, 3), 0, 0);//高斯模糊,消除噪点threshold(img_copy, img_copy, 50, 255, THRESH_BINARY | THRESH_OTSU);//阈值化dilate(img_copy, img_copy, Mat(), Point(-1, -1),5);//膨胀int morph_size = 2;//闭运算,把字符之间进一步缩短,变成一团Mat element = getStructuringElement(MORPH_RECT, Size(morph_size * 2, morph_size * 2), Point(morph_size, morph_size));morphologyEx(img_copy, img_copy,MORPH_CLOSE,element,Point(-1,1),3);//!!! 找轮廓部分vector<vector<Point> > contours;vector<Vec4i> hierarchy;findContours(img_copy, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);//获取轮廓的左上和右下两个坐标位置,左上是坐标最小的,右下是坐标最大的int left[2] = { contours[0][0].x, contours[0][0].y };int right[2] = { contours[0][0].x, contours[0][0].y };for (size_t i = 0; i < contours.size(); i++){for (size_t j = 1; j < contours[i].size(); j++){if (left[0] > contours[i][j].x) {left[0] = contours[i][j].x;}if (left[1] > contours[i][j].y) {left[1] = contours[i][j].y;}if (right[0] < contours[i][j].x) {right[0] = contours[i][j].x;}if (right[1] < contours[i][j].y) {right[1] = contours[i][j].y;}}}//在原图中框出区域//rectangle(ret,Point(left[0],left[1]), Point(right[0],right[1]),(255));//取出框中的图像ret = img(Rect(left[0], left[1], right[0]- left[0], right[1] - left[1]));//参数是 矩形区域的左上角坐标和对应的x,y的边长return ret;}void segChar(Mat& image)
{Mat img_copy;image.copyTo(img_copy);//!!! 图像预处理 部分cvtColor(img_copy, img_copy, COLOR_BGR2GRAY);bitwise_not(img_copy, img_copy);//黑白像素取反GaussianBlur(img_copy, img_copy, Size(3, 3), 0, 0);//高斯模糊,消除噪点threshold(img_copy, img_copy, 50, 255, THRESH_BINARY | THRESH_OTSU);//阈值化dilate(img_copy, img_copy, Mat(), Point(-1, -1), 3);//膨胀erode(img_copy, img_copy, Mat(), Point(-1, -1), 3);//!!! 投影法进行字符分割,投影到水平方向,那就是统计每个横坐标上的那一列有多少个白色的像素//!  画出像素投影图int src_width = img_copy.cols;int src_height = img_copy.rows;int* projectValArry = new int[src_width]();//创建用于储存每列白色像素个数的数组//memset(projectValArry, 0, src_width*4);//初始化数组//取列白色像素个数for (int i = 0; i < src_height; i++) {for (int j = 0; j < src_width; j++) {if (img_copy.at<uchar>(i, j)) {projectValArry[j]++;}}}//将每列白色像素数目绘制成直方图//定义画布 绘制垂直投影下每列白色像素的数目Mat verticalProjectionMat(src_height, src_width, CV_8UC1, Scalar(0));for (int i = 0; i < src_width; i++) {for (int j = 0; j < projectValArry[i]; j++) {verticalProjectionMat.at<uchar>(src_height - j - 1, i) = 255;}}imshow("verticalProjectionMat", verticalProjectionMat);//汉字的分割确实没有英文效果好//! 根据每列白色像素数目设置截取起始和截止列vector<Mat> split_src;//定义Mat vector ,存储图片组bool white_block = 0, black_block = 0;//定义标志,用来指示在白色像素区还是在全黑区域int temp_col_forword = 0, temp_col_behind = 0;//定义列temp_col_forword  temp_col_behind,记录字符截取起始列和截止列Mat split_temp;//遍历数组projectValArry,统计每列的白色像素,投影到水平区域for (int i = 0; i < src_width; i++) {if (projectValArry[i]) {//表示区域有白色像素white_block = 1;black_block = 0;}else {              //若无白色像素(进入黑色区域)if (white_block == 1) {//若前一列有白色像素temp_col_behind = i;//取当前列为截止列//截取下一部分
split_temp = img_copy(Rect(temp_col_forword, 0, temp_col_behind - temp_col_forword, src_height)).clone();
split_src.push_back(split_temp);//将截取玩的图片存入列表中}temp_col_forword = i;//记录最新黑色区域的列号,记为起始列black_block = 1;//表示进入黑色区域white_block = 0;}}//! 将截出来的图片组放入文件夹for (size_t i = 0; i < split_src.size(); i++){string img_Name = "E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\ocr\\" + to_string(i) + ".jpg";imwrite(img_Name, split_src[i]);}imshow("test2", img_copy);}void charTem(Mat& image)
{Mat img = Mat::zeros(image.size(), image.type());int img_col = img.cols;int img_row = img.rows;//cout << img_col << " : " << img_row << endl;//778 : 270//依次将几个字符按顺序图像融合,注意各自的坐标位置Mat img1 = imread("E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\ocr\\0.jpg");cout << img1.size() << endl;Mat imageROI1 = img(Rect(100, 100, img1.cols, img1.rows));// 设置图片1要放入模板的位置pos[0] = 100;// 0位置 对应 字符 N addWeighted(imageROI1, 0, img1, 1, 0, imageROI1);Mat img2 = imread("E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\ocr\\1.jpg");Mat imageROI2 = img(Rect(200, 100, img2.cols, img2.rows));// 设置图片1要放入模板的位置pos[1] = 200;// 0位置 对应 字符 J addWeighted(imageROI2, 0, img2, 1, 0, imageROI2);Mat img3 = imread("E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\ocr\\2.jpg");Mat imageROI3 = img(Rect(300, 100, img3.cols, img3.rows));// 设置图片1要放入模板的位置pos[2] = 300;// 0位置 对应 字符 J addWeighted(imageROI3, 0, img3, 1, 0, imageROI3);Mat img4 = imread("E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\ocr\\3.jpg");Mat imageROI4 = img(Rect(400, 100, img4.cols, img4.rows));// 设置图片1要放入模板的位置pos[2] = 400;// 0位置 对应 字符 J addWeighted(imageROI4, 0, img4, 1, 0, imageROI4);imshow("test3", img);string img_Name = "E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\template\\temp.jpg";imwrite(img_Name, img);}
string recog()
{string ret;Mat temp = imread("E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\template\\temp.jpg");//模板String pattern = "E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\ocr";vector<cv::String> fn;glob(pattern, fn, false);vector<Mat> images;//size_t count = fn.size(); //number of png files in images folder,我这10个字符的图片for (size_t i = 0; i < fn.size(); i++){string img_Name = "E:\\研究生\\数字图像处理\\c++\\字符识别\\Project1\\ocr\\" + to_string(i) + ".jpg";Mat img = imread(img_Name);images.push_back(img);}//识别过程Mat result;int result_cols = temp.cols - images[0].cols + 1;int result_rows = temp.rows - images[0].rows + 1;int match_method = 0;result.create(result_rows, result_cols, CV_32FC1);vector<Point> loc;for (size_t i = 0; i < images.size(); i++){matchTemplate(temp, images[i], result, match_method);// 归一化normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());//利用cv::minMaxLoc对结果矩阵R中的最小值和最大值进行局部定位double minVal; double maxVal; Point minLoc; Point maxLoc;Point matchLoc;minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());//对于前两个方法(TM_SQDIFF和MT_SQDIFF_NORMED),最好的匹配是最小值。//对于其他来说,值越高代表匹配越好。因此,我们将相应的值保存在matchLoc变量中:if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED){matchLoc = minLoc;}else{matchLoc = maxLoc;}loc.push_back(matchLoc);}//根据matchloc 的数值进行字符的匹配for (size_t i = 0; i < loc.size(); i++){cout << loc[i].x << endl;if (loc[i].x > 95 &loc[i].x < 105){ret = ret + maps[0];}else if (loc[i].x > 195 & loc[i].x < 205) {ret = ret + maps[1];}else if (loc[i].x > 295 & loc[i].x < 305) {ret = ret + maps[2];}else if (loc[i].x > 395 & loc[i].x < 405) {ret = ret + maps[3];}}return ret;}

VS Opencv 字符模板匹配小实例相关推荐

  1. Opencv java模板匹配-角点检测(11)

    函数 在opencv中有模板匹配的方法, Imgproc.matchTemplate(src, template, result, Imgproc.TM_CCOEFF); 这个方法输入的参数分别是: ...

  2. OpenCV—python 模板匹配与图像特征匹配

    文章目录 一.理论介绍与算法 二.算法代码 单目标匹配 多目标匹配 三 多尺度模板匹配 一.理论介绍与算法 模板匹配是在一幅图像中寻找一个特定目标的方法之一,这种方法的原理非常简单,遍历图像中的每一个 ...

  3. OpenCV:模板匹配

    小程序「跳一跳」的自动化. 主要涉及到了OpenCV的模板匹配和边缘检测技术,以及Android开发调试工具ADB. 如果放在一起说,感觉内容有些多. 所以,分三期来讲,也能多了解一些东西. 首先介绍 ...

  4. OpenCV SURF FLANN匹配的实例(附完整代码)

    OpenCV SURF FLANN匹配的实例 OpenCV SURF FLANN匹配的实例 OpenCV SURF FLANN匹配的实例 #include <iostream> #incl ...

  5. Python+OpenCV:模板匹配(Template Matching)

    Python+OpenCV:模板匹配(Template Matching) Template Matching with Single Objects ######################## ...

  6. 基于VS与OpenCV的模板匹配学习(4):手写OpenCV matchTemplate()

    基于VS与OpenCV的模板匹配学习(4):手写OpenCV matchTemplate() 文章目录 基于VS与OpenCV的模板匹配学习(4):手写OpenCV matchTemplate() 前 ...

  7. Python+Opencv实现模板匹配

    目录 一.模板匹配简介 二.传统模板匹配算法不足之处 三.多尺度模板匹配实现步骤 四.多尺度模板匹配实现代码 五.多尺度模板匹配效果展示和分析 六.思维扩展 参考资料 注意事项 一.模板匹配简介    ...

  8. 基于opencv的模板匹配详解

    1.什么是模板匹配 在OpenCV教程中这样解释模板匹配: 模板匹配是一项在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术.这里说的模板是我们已知的小图像,模板匹配就是在一副大图像中搜寻目标. ...

  9. Opencv(六)模板匹配、轮廓检测、轮廓周围绘制矩形框和圆形框

    模板匹配介绍 模板匹配就是在整个图像区域发现与给定子图像匹配的小块区域. 所以模板匹配首先需要一个模板图像T(给定的子图像) 另外需要一个待检测的图像-源图像S 工作方法,在带检测图像上,从左到右,从 ...

最新文章

  1. #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  2. [转载][总结]函数getopt(),getopt_long及其参数optind
  3. django中的FBV和CBV
  4. 【西安石油大学主办|IEEE CPS出版】2020智能控制、测量与信号处理国际学术会议诚邀您投稿参会!...
  5. 【语音识别基础】总有一天你会用到,嗯,没有公式~
  6. 如何将3dmax结合前端_如何将阅读与写作结合
  7. UIApplication对象及其代理UIApplicationDelegate[转]
  8. 【微软2014实习生及秋令营技术类职位在线測试】题目2 : K-th string
  9. 为什么Spring Boot推荐使用logback-spring.xml来替代logback.xml来配置logback日志的问题分析...
  10. 【雕爷学编程】Arduino动手做(84)---DS1307时钟模块
  11. 信息科技:铁塔和400G光模块表现亮眼
  12. Win10,Office2016及以上图标异常解决方案
  13. Panel控件的使用
  14. exchange java_java中用Exchange
  15. 和画意思相近的字_有没有类似“鸢语慕君年青筏画卿颜”这种古风情侣网名啊...
  16. 兼容性最好的android模拟器,哪个安卓模拟器好用,性能最好,兼容性最强
  17. 生活随记-找爸爸的小女孩
  18. LaTeX写一份完整的物理实验报告
  19. 安装和配置NFS服务器
  20. xxljob默认登录_三千字带你搞懂XXL-JOB任务调度平台

热门文章

  1. MongoDB数据库协议解析及C/C++代码实现
  2. 计算机网络八股文背诵版(收藏夹吃灰系列)
  3. 图像处理matlab基本操作
  4. matlab怎么导出矩阵,如何将matlab中矩阵导出到txt文件中
  5. 十三、关于@MapperScan和@Mapper的使用
  6. 《电路基础》同相运算放大器
  7. python调用按键精灵插件_按键精灵——如何实现办公自由(四)
  8. All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com/r/tool
  9. c语言作业年历显示报告,c语言程序设计年历显示
  10. 制定客户体验管理计划的 5 个步骤