燕山大学数据结构与算法课程实践——ISBN号识别系统的设计与开发

这篇具有很好参考价值的文章主要介绍了燕山大学数据结构与算法课程实践——ISBN号识别系统的设计与开发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

项目背景

        ISBN 号是国际标准书号的简称,它是国际标准化组织于 1972 年公布的一项国际通用的出版物统一编号方法。所有正规出版的普通图书版权页都有 ISBN 号, ISBN international standard of book number 几个英文字母的缩写,即国际标准书号。这个号码印刷在每本图书封底( 或护封 ) 的右下角,由一组用四个分割线“-”隔开的 13 个数字。例如: ISBN 978-7-111-47818-8 。其中, ISBN987 代表是中国, 7 代表分类, 111代表出版社编号,47818 代表本书在出版社所有出版书中的编号, 9 是校验码,即:用 1 分别乘 ISBN 的前12 位中的奇数位,用 3 乘以偶数位,乘积之和以 10 为模,用 10 减去此模,即可得到校验位的值,其值范围为 0-9 。例如: S=9*1+7*3+8*1+7*3+1*1+1*3+1*1+4*3+7*1+8*3+1*1+8*3=132 132%10=2 10-2=8 因此校验码即为 8 。在该码的下方有一个条形码,条形码的下方写着 13 个数字,与 ISBN 后面的数字是相同的。

任务:开发一套ISBN号识别系统

        给定 100 张包含 ISBN 号的图片,建议在 VS + OpenCV 环境下完成对给定的 ISBN 图像的识别, 每幅图像的文件名为图中的 ISBN ,例如 ISBN978-7-111-47818-8.jpg. 你可以自由参考现有的文献中的方法,从设计的原理、技术方案到程序实现,给出你能识别出的ISBN 的正确率和准确率。例如:如果有 100 幅图片,你能识别出 90 幅,那么你的系统识别的正确率是 90% ;每一张照片有 13 个需要识别的数字, 100 张照片共有 1300 个需要识别的数字,你的系统识别出了 1000 个,那识别系统的准确率是 1000/1300=76.92%

采用的研究方法及相关工具

        本项目使用vs2019和OpenCV4开发,在对其进行图像的转正,然后灰度值转化,对图像进行去噪处理,再进行图像二值化的转化,对图书ISBN编号进行垂直方向数字分割,切割后的每个字符图片与模板进行匹配,实现对ISBN的快速识别。最后,计算出识别出的ISBN相应的正确率和准确率。

项目的方案设计

        通过图像预处理读入图像,对其进行灰度值转化和二值化,将二值化图片进行倾斜校正,校正之后寻找到ISBN号所在区域,对源图片进行分割获得彩色ISBN号,再将其转换为二值图像,寻找ISBN号字符的边界后截取每个字符,截取后的字符通过调整最后与模板进行对比,差值最小的模板号即为读取的ISBN 号,与正确的ISBN号比较得到项目的正确率和准确率。

核心代码的实现

图像预处理:读入图片、转化为灰度图和二值图

1.int rightNums = 0, acNums = 0, sumNums=0; //1:正确的个数;  2:正确的字符个数  3:总共的字符个数  
2.  
3.    string path1 = "C:/Users/Administrator/Desktop/二级项目/ISBN/ISBN测试数据--100幅图"; //文件路径  
4.  
5.    vector<String> imgPaths;  
6.    glob(path1, imgPaths, false); //1:文件路径  2:输出数组  3:递归遍历所有图片  
7.    int imgNums = imgPaths.size(); //图片总个数  
8.  
9.    for (int i = 0; i < imgNums; i++)  
10.    {  
11.        Mat Img = imread(imgPaths[i]); //读入图片  
12.        if (Img.empty()) //图片不存在  
13.        {  
14.            cout << imgPaths[i] << "  Not Loaded" << endl;  
15.            continue;  
16.        }  
17.  
18.        //对图片的大小进行统一调整  
19.        double width = 400; //宽度  
20.        double height = width * Img.rows / Img.cols; //高度  
21.        resize(Img, Img, Size(width, height)); //重新对图片大小进行调整。1:源图像  2:输出图像  3:图像大小  
22.  
23.        //将原图转化为灰度图再转化为二值图 该二值图像中,黑色设为1,白色设为0(关键!!!)  
24.        //---转化为灰度图  
25.        Mat erImg;  
26.        cvtColor(Img,erImg, COLOR_BGR2GRAY); //将图片转化为灰度图  
27.        //COLOR_BGR2GRAY的原理  GRAY = B * 0.114 + G * 0.587 + R * 0.299  
28.  
29.        threshold(erImg, erImg, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);//将灰度图转化为二值图  
30.        //1:源图片  2:输出图片  3:阈值1  4:域指2  5:方式  
31.        //自动设置阈值的方法OTSU  当点大于阈值设置为0(白)  小于阈值设置为255(黑)  

图像的旋转

1.//获取旋转角度  
2.double getAngles(Mat inImg)  
3.{  
4.    //计算垂直方向导数  
5.    Mat tempImg;  
6.    Sobel(inImg, tempImg, -1, 0, 1, 5);  
7.    //它可以用来对图像进行边缘检测, 或者用来计算某个像素点的法线向量。  
8.    //参数说明:1,输入图像;2,输出图像,需要有和原图一样的尺寸和类型;  
9.    //3,图像的深度;4,x方向上的差分阶数;5,y方向上的差分阶数;  
10.    //6,int类型ksize,有默认值3,表示Sobel核的大小;必须取1,3,5或7  
11.  
12.    //直线检测  
13.    vector<Vec2f> lines;  
14.    HoughLines(tempImg, lines, 1, CV_PI / 180, 180);  
15.    //参数说明:1:源图像;   
16.    //2:InputArray类型的lines,经过调用HoughLines函数后储存了霍夫线变换检测到线条的输出矢量  
17.    //3:以像素为单位的距离精度   4:以弧度为单位的角度精度  
18.    //5:累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值  
19.  
20.    //计算旋转角度  
21.    float angle = 0.0;  
22.    for (int i = 0; i < lines.size(); i++)  
23.    {  
24.        float theta = lines[i][1];  
25.        angle += theta;  
26.    }  
27.  
28.    if (lines.size() == 0) //未i检测到直线  
29.    {  
30.        angle = CV_PI / 2;  
31.    }  
32.    else //检测到直线,取平均值  
33.    {  
34.        angle = angle / lines.size();  
35.    }  
36.    return angle;  
37.}  

寻找ISBN号所在区域

1.//寻找ISBN所在行  
2.void FindISBNRows(Mat inputImg, int boundary, int top, int bottom, int minsize, int& startindex, int& endindex)  
3.{  
4.  
5.    //边缘检测,方便找到梯度大的地方,忽略梯度小的地方  
6.    Mat canImg;  
7.    //去噪(均值滤波)  
8.    blur(inputImg, canImg, Size(3, 3));//1:源图像  2:输出图像  3:内核大小  
9.  
10.    Canny(canImg, canImg, boundary, boundary * 2, 3);  
11.    //参数说明:1,输入。2,输出。3,阈值1.4.阈值2。5,sobel核大小。  
12.    //高于和靠近阈值2的点会被认为是边界     
13.    //注:低于阈值1的像素点会被认为不是边缘;高于阈值2的像素点会被认为是边缘;  
14.    //在阈值1和阈值2之间的像素点, 若与第2步得到的边缘像素点相邻,则被认为是边缘,否则被认为不是边缘  
15.  
16.    //寻找上边界  
17.    for (int i = top; i < bottom; i++)  
18.    {  
19.  
20.        if (canImg.at<uchar>(i, 0) != 0) //有像素点存在  
21.        {  
22.            startindex = i;  //上边界  
23.            break;   
24.        }  
25.    }  
26.  
27.    //寻找下边界  
28.    for (int i = bottom; i >= top; i--)  
29.    {  
30.        if (canImg.at<uchar>(i, 0) != 0)  
31.        {  
32.            endindex = i;  //下边界  
33.            break;  
34.        }  
35.    }  
36.  
37.  
38.    //范围过小,调整阈值再次寻找  
39.    if (abs(endindex - startindex) < minsize)  
40.    {  
41.        boundary -= 10; //缩小阈值重新寻找  
42.        if (boundary <= 0)  
43.        {  
44.            startindex = top;  
45.            endindex = bottom;  
46.            return;  
47.        }  
48.        FindISBNRows(inputImg, boundary, top, bottom, minsize, startindex, endindex);  
49.    }  
50.  
51.  
52.}  

截取ISBN号所在区域转化为二值图

1.//弥补旋转缺失的区域  
2.        Mat BG = Mat(Img.rows, Img.cols, CV_8UC1, Scalar(255));  
3.        warpAffine(BG, BG, M, Img.size());  
4.        bitwise_not(BG, BG);  
5.        Mat turnImg; //彩色图片  
6.        warpAffine(Img, turnImg, M, Img.size());  
7.        Img.copyTo(turnImg, BG); //弥补旋转确实的区域  
8.  
9.//截取ISBN所在的区域  
10.        Mat isbnImg = Mat(turnImg, Range(start1, end1), Range(0, turnImg.cols));  //截取的是原图的那一部分  
11.  
12.        //调整大小  
13.        width = 900;  
14.        height = width * isbnImg.rows / isbnImg.cols;  
15.        resize(isbnImg, isbnImg, Size(width, height));  
16.  
17.//转化为二值图  
18.        erImg = Mat();  
19.        cvtColor(isbnImg, erImg, COLOR_BGR2GRAY);  
20.        threshold(erImg, erImg, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);  
21.

截取字符和模板匹配,并将正确的ISBN和识别出的ISBN输出

1.//寻找每个字符的位置  
2.void findChar(Mat inputImg, vector<float>& p)  //记录每个字符的左右边界列坐标  
3.{  
4.    int boundary = 0;    //阈值                     
5.    for (int j = 1; j < inputImg.cols - 1; j++)  
6.    {  
7.        if (inputImg.at<uchar>(0, j) > boundary && inputImg.at<uchar>(0, j - 1) <= boundary)   //1是黑色  
8.        {  
9.            p.push_back(j - 1);   //左边缘,是图形的左半边轮廓装入数组中  
10.        }  
11.        else if (inputImg.at<uchar>(0, j) > boundary && inputImg.at<uchar>(0, j + 1) <= boundary)  
12.        {  
13.            p.push_back(j + 1);   //右边缘,是图形的右半边轮廓装入数组中  
14.        }  
15.    }  
16.}  
17.  
18.//差值函数  
19.int CalcImg(Mat inputImg) {  
20.    int nums = 0;  
21.    for (int i = 0; i < inputImg.rows; i++) {  
22.        for (int j = 0; j < inputImg.cols; j++) {  
23.            if (inputImg.at<uchar>(i, j) != 0) {  
24.                nums += inputImg.at<uchar>(i, j);  
25.            }  
26.        }  
27.    }  
28.    return nums;  
29.}  
30.  
31.//模板匹配  
32.bool cmp(pair<int, int>x, pair<int, int>y)    //按照从小到大的顺序排序  
33.{  
34.    return x.second < y.second;  
35.}  
36.  
37.  
38.//模板匹配函数  
39.char CheckImg(Mat inputImg) {  
40.    string wjlj = "样例/*.jpg";  
41.    vector<String> wjm;  
42.    glob(wjlj, wjm, false); //读入模板名  
43.    int wjmlen = wjm.size();  
44.  
45.    pair<int, int>* nums = new pair<int, int>[wjmlen];  
46.    for (int i = 0; i < wjmlen; i++) {  
47.        nums[i].first = i;  
48.        Mat numImg = imread(wjm[i], 0);//  
49.        Mat delImg;  
50.        absdiff(numImg, inputImg, delImg);//计算两个数组差的绝对值  
51.        nums[i].second = CalcImg(delImg);  
52.    }  
53.  
54.    sort(nums, nums + wjmlen,cmp); //-------------------------------------------------  
55.  
56.    int index = nums[0].first / 2;  
57.    switch (index) {  
58.        case 0:  
59.        case 1:  
60.        case 2:  
61.        case 3:  
62.        case 4:  
63.        case 5:  
64.        case 6:  
65.        case 7:  
66.        case 8:  
67.        case 9:  
68.            return index + '0';   //如果是数字就return该数字  
69.        case 10:  
70.            return 'I';  
71.        case 11:  
72.            return 'S';  
73.        case 12:  
74.            return 'B';  
75.        case 13:  
76.            return 'N';  
77.        case 14:  
78.            return 'X';  
79.        default:  
80.            return ' ';  
81.    }  
82.}  

计算正确率和准确率并输出

1.//计算准确率  
2.        sumNums += cmpData.length();  
3.        int acOfone = 0;  
4.        for (int a = 0; a < cmpData.length(); a++) {  
5.            if (res[a] == cmpData[a]) {  
6.                acNums++;  
7.                acOfone++;  
8.            }  
9.        }  
10.        cout << "正确识别的个数为:" << acOfone << endl;  
11.  
12.        //计算正确率  
13.        if (res == cmpData) {  
14.            rightNums++;  
15.            cout << "Yes" << endl;  
16.        }  
17.        else {  
18.            cout << "No" << endl;  
19.        }  
20.  
21.  
22.        if (i == imgNums-1)  
23.        {  
24.            cout << endl;  
25.            /*printf("正确个数:%4.d 正确率:%f\n", rightNums, rightNums * 1.0 / 100); 
26.            printf("准确个数:%4.d 准确率:%f\n", acNums, acNums * 1.0 / sumNums);*/  
27.            cout << setprecision(6) << fixed << "正确总数比:" << rightNums << "/" << imgNums << " " << "       准确率" << rightNums * 1.0 / imgNums << endl;  
28.            cout << setprecision(6) << fixed << "正确字符总比数:" << acNums << "/" << sumNums << " " << "精确率" << acNums * 1.0 / sumNums;  
29.            //waitKey(0);  
30.            cout << endl;  
31.        }  

运行结果

isbn识别与开发,数据结构,计算机视觉,opencv,图像处理,c++

isbn识别与开发,数据结构,计算机视觉,opencv,图像处理,c++ 

有疑问欢迎私信讨论。文章来源地址https://www.toymoban.com/news/detail-840365.html

到了这里,关于燕山大学数据结构与算法课程实践——ISBN号识别系统的设计与开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 燕山大学机器学习实验一:线性回归1——糖尿病情预测

    一、加载糖尿病数据集 diabetes,观察数据 1.载入糖尿病情数据库 diabetes,查看数据。 2.切分数据,组合成 DateFrame 数据,并输出数据集前几行,观察数据。 二、基于线性回归对数据集进行分析 3.查看数据集信息,从数据集中抽取训练集和测试集。 4.建立线性回归模型,训练数

    2024年02月08日
    浏览(52)
  • 燕山大学计算机网络实验(windows网络配置方法及基本网络命令、交换机和路由器的使用、小型校园网络模拟搭建)

    项目源码以及报告获取,可看我专栏简介 1、查看本机网络配置,根据配置信息,把本机地址改为静态地址,并使用ipconfig、ping命令验证网络状态,如果网络不通请根据相关现象测试,并给出自己的推论和思考。(请使用自己的笔记本连接校园网无线进行操作) 2、在本机网络

    2024年02月01日
    浏览(60)
  • 《数据结构与算法分析》课程设计——迷宫问题

    中国矿业大学信控学院   补一下我之前在博客园发布的内容  懒得调了, 想复制完整代码直接复制最下面的 ,想复制分布代码去看我博客园链接吧 《数据结构与算法分析》课程设计——迷宫问题 - 刷子zz - 博客园 一、  问题描述 问题中迷宫可用方阵[m,n]表示,0表示能通过

    2024年02月10日
    浏览(48)
  • 数据结构与算法基础(青岛大学-王卓)(1)

    程序=数据结构+算法 数据(data) 数值型 非数值型(文字,图像…) 数据元素(data element) 数据的基本单位,在程序中当做一个整体进行考虑和处理(如表中的一行包含多列信息) 是数据这个集合的个体 数据项(data item) 构成数据元素的不可分割的 最小单位 () 数据对象(data object) 性质相

    2024年02月03日
    浏览(44)
  • 数据结构与算法基础(青岛大学-王卓)(5)

    叮叮咚咚,新一期来袭,我还在吃桃子,吃桃子,吃桃子。。。串和python的字符串差不多,数组和广义表像是python的list 串(string) - 字符串 概念及术语 定义: 零个或多个任意字符组成的有限序列,是一种内容受限的线性表 子串 : 串中任意个连续字符组成的子序列称为该串的

    2024年02月09日
    浏览(48)
  • 数据结构与算法基础(青岛大学-王卓)(6)

    啊呀呀,不小心又断更快一个月了,我还是认真每天学习滴,最近还是香瓜,菜瓜,西瓜,羊角蜜不能停口啊,哈哈,二叉树这一章真是硬茬,难啃啊。 树的定义 树的深度 :树中节点的最大层次 有序树 : 树中结点的各子树从左至右有次序 ( 最左边的为第一个孩子 ) 无序

    2024年02月16日
    浏览(53)
  • 数据结构与算法课程设计---最小生成树的应用

    1.问题 假定有这么一个问题,有11个城市,城市之间有一些天然气管道,铺设天然气管道需要花费不同的金额,现在要你选择其中一些天然气管道,使得所有城市可以互相联通且花费最小。 2.分析 我们把这个问题抽象为一张图,每个城市是一个顶点,城市与城市之间的管道是

    2024年02月08日
    浏览(50)
  • 合肥工业大学 宣城校区 数据结构与算法实验 队列、二叉树、查找和排序

    1.实验目标 熟练掌握队列的顺序存储结构和链式存储结构。 熟练掌握队列的有关算法设计,并在循环顺序队列和链队列上实现。 根据具体给定的需求,合理设计并实现相关结构和算法。 2.实验内容和要求 循环顺序队列的实验要求 循环顺序队列结构和运算定义,算法的实现以

    2024年02月11日
    浏览(47)
  • 数据结构课程设计题目——链表综合算法设计、带头双向循环链表、插入、显示、删除、修改、排序

      课程设计题目1–链表综合算法设计   一、设计内容   已知简单的人事信息系统中职工记录包含职工编号(no)、职工姓名(name)、部门名称(depname)、职称(title)和工资数(salary)等信息(可以增加其他信息),设计并完成一个简单的人事信息管理系统,要求完成但不

    2024年02月08日
    浏览(61)
  • 北京林业大学数据结构实验二 基于栈的算术表达式求值算法

    参见课本P75 例3.3

    2024年02月06日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包