C#-opencvsharp-图像中的数字提取

这篇具有很好参考价值的文章主要介绍了C#-opencvsharp-图像中的数字提取。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C#-opencv-图像中数字提取

本人初学者,正在学习C#中的opencv操作,下述代码目的是通过图像识别对银行卡的卡号进行识别并提取,要求位置置于银行卡原图中卡号正上方;
此次学习过程中通过查询python中的轮廓排序算法,手写了一个简易算法,方能实现此次学习的目的,同时加深了解了matchtemplate与matchshapes的应用区别,希望大家在阅读期间发现的问题的,及时反馈,本人会加以修正并提升!!!
卡片图像(百度获取)
C#-opencvsharp-图像中的数字提取数字模板图像(百度获取)
C#-opencvsharp-图像中的数字提取

0.准备工作

using System;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Size = OpenCvSharp.Size;
using Point = OpenCvSharp.Point;

1.定义轮廓排序简易函数-contours_sort

排序原理简单如下:
由上到下-通过轮廓获取外边界矩形(x,y,width,height)-y坐标从小到大排序
由下到上-通过轮廓获取外边界矩形(x,y,width,height)-y坐标+height(矩形高度)从大到小排序
由左到右-通过轮廓获取外边界矩形(x,y,width,height)-x坐标从小到大排序
由右到左-通过轮廓获取外边界矩形(x,y,width,height)-x坐标+width(矩形宽度)从大到小排序
轮廓面积由小到大-cv2.contourarea获取轮廓面积
轮廓面积由大到小
轮廓周长由小到大-cv2.arclength获取轮廓周长
轮廓周长由大到小


        //轮廓排序函数简易C#版
        static private Point[][] contours_sort(Point[][] cnts,string sortMethod)
        {
            var contours = cnts;
            int cnt_num = contours.Length;
            Rect[] rects = new Rect[cnt_num];
            
            for(int i = 0; i < cnt_num; i++) rects[i] = Cv2.BoundingRect(contours[i]);
            string[] sortType = { 
                "top-to-bottom",        //0-坐标由上到下排序
                "bottom-to-top",        //1-坐标由下到上排序
                "left-to-right",        //2-坐标由左到右排序
                "right-to-left",        //3-坐标由右到左排序
                "area-min-to-max",      //4-面积-从小到大
                "area-max-to-min",      //5-面积-从大到小
                "length-min-to-max",    //6-周长-从小到达
                "length-max-to-min"     //7周长从大到小
            };
            int id = -1;
            for(int i = 0; i < sortType.Length; i++)
            {
                if (sortMethod == sortType[i]) id = i;
            }
            switch (id) {
                case 0:
                    for(int i = 0; i < cnt_num; i++)
                    {
                        for(int j = i+1; j < cnt_num; j++)
                        {
                            if (rects[j].Y <= rects[i].Y)
                            {
                                Rect tpr = rects[i];
                                rects[i] = rects[j];
                                rects[j] = tpr;
                                var temp = contours[i];
                                contours[i] = contours[j];
                                contours[j] = temp;
                            }
                        }
                    }
                    break;
                case 1:
                    for (int i = 0; i < cnt_num; i++)
                    {
                        for (int j = i + 1; j < cnt_num; j++)
                        {
                            if (rects[j].Y+ rects[j].Height >= rects[i].Y + rects[i].Height)
                            {
                                Rect tpr = rects[i];
                                rects[i] = rects[j];
                                rects[j] = tpr;
                                var temp = contours[i];
                                contours[i] = contours[j];
                                contours[j] = temp;
                            }
                        }
                    }
                    break;
                case 2:
                    for (int i = 0; i < cnt_num; i++)
                    {
                        for (int j = i + 1; j < cnt_num; j++)
                        {
                            if (rects[j].X <= rects[i].X)
                            {
                                Rect tpr = rects[i];
                                rects[i] = rects[j];
                                rects[j] = tpr;
                                var temp = contours[i];
                                contours[i] = contours[j];
                                contours[j] = temp;
                            }
                        }
                    }
                    break;
                case 3:
                    for (int i = 0; i < cnt_num; i++)
                    {
                        for (int j = i + 1; j < cnt_num; j++)
                        {
                            if (rects[j].X+rects[j].Width >= rects[i].X + rects[i].Width)
                            {
                                Rect tpr = rects[i];
                                rects[i] = rects[j];
                                rects[j] = tpr;
                                var temp = contours[i];
                                contours[i] = contours[j];
                                contours[j] = temp;
                            }
                        }
                    }
                    break;
                case 4:
                    for (int i = 0; i < cnt_num; i++)
                    {
                        for (int j = i + 1; j < cnt_num; j++)
                        {
                            if (Cv2.ContourArea(contours[j])<= Cv2.ContourArea(contours[j]))
                            {
                                var temp = contours[i];
                                contours[i] = contours[j];
                                contours[j] = temp;
                            }
                        }
                    }
                    break;
                case 5:
                    for (int i = 0; i < cnt_num; i++)
                    {
                        for (int j = i + 1; j < cnt_num; j++)
                        {
                            if (Cv2.ContourArea(contours[j]) >= Cv2.ContourArea(contours[j]))
                            {
                                var temp = contours[i];
                                contours[i] = contours[j];
                                contours[j] = temp;
                            }
                        }
                    }
                    break;
                case 6:
                    for (int i = 0; i < cnt_num; i++)
                    {
                        for (int j = i + 1; j < cnt_num; j++)
                        {
                            if (Cv2.ArcLength(contours[j],false) <= Cv2.ArcLength(contours[j], false))
                            {
                                var temp = contours[i];
                                contours[i] = contours[j];
                                contours[j] = temp;
                            }
                        }
                    }
                    break;
                case 7:
                    for (int i = 0; i < cnt_num; i++)
                    {
                        for (int j = i + 1; j < cnt_num; j++)
                        {
                            if (Cv2.ArcLength(contours[j], false) >= Cv2.ArcLength(contours[j], false))
                            {
                                var temp = contours[i];
                                contours[i] = contours[j];
                                contours[j] = temp;
                            }
                        }
                    }
                    break;
            }
            return contours;
        }
    

2.常规参数设置

		    //标准尺寸设定
            int stand_width = 57;
            int stand_height = 88;
            //图像路径
            string c_path = "D://Jay.Lee//Study//2023//imgs//card.png";
            string t_path = "D://Jay.Lee//Study//2023//imgs//number.png";
            //图像获取
            Mat card = Cv2.ImRead(c_path);
            Mat template = Cv2.ImRead(t_path);
            //图像显示
            Cv2.ImShow("card原图显示", card);
            Cv2.ImShow("数字模板显示", template);
            

3.数字模板处理

            //1.数字模板处理
            Mat tgray = new Mat();
            //1.1图像灰度处理
            Cv2.CvtColor(template, tgray, ColorConversionCodes.BGR2GRAY);
            //1.2图像二值化
            Cv2.Threshold(tgray, tgray, 50, 255, ThresholdTypes.BinaryInv);
            //1.3图像图像轮廓查找
            Cv2.FindContours(tgray.Clone(), out Point[][] tcnts, out HierarchyIndex[] hierarchy,
                RetrievalModes.External, ContourApproximationModes.ApproxSimple);
                //此处注意-后期依旧使用tgray图像,此处使用tgray.clone()
            //1.4轮廓从左向右排序
            tcnts = contours_sort(tcnts, "left-to-right");
            //1.5从二值化图中扣取每个存在外轮廓的矩形
            Mat[] templateImages = new Mat[tcnts.Length];
            for (int i = 0; i < tcnts.Length; i++)
            {
                Rect r = Cv2.BoundingRect(tcnts[i]);
                templateImages[i] = new Mat(tgray, new Rect(r.X , r.Y , r.Width , r.Height ));
                Cv2.Resize(templateImages[i], templateImages[i], new Size(stand_width, stand_height),0,0);
            }

4.卡片图像预处理

            //2.卡片预处理
            //2.1形态学核定义
            var rowkernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(11, 3));
            var gapkernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9, 9));
            Mat cgray = new Mat();
            //2.2图像灰度处理
            Cv2.CvtColor(card, cgray, ColorConversionCodes.BGR2GRAY);
            //2.3图像二值化(Binary和Otsu自动判断)
            Cv2.Threshold(cgray, cgray, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
            //2.4图像缩小,便于后期形态学处理
            Mat small = cgray.Clone();
            Cv2.Resize(small, small, new Size(0, 0), 0.5, 0.5);
            //2.5两次闭处理,保证数字全部提取
            Cv2.MorphologyEx(small, small, MorphTypes.Close, rowkernel);
            Cv2.MorphologyEx(small, small, MorphTypes.Close, gapkernel);
            //2.6再次二值化
            Cv2.Threshold(small, small, 2, 255, ThresholdTypes.Binary);
            //2.6二值化图像放大至原图像尺寸
            Cv2.Resize(small, small, new Size(0, 0), 2, 2);
            //2.7二值化图像中轮廓提取
            Cv2.FindContours(small.Clone(), out Point[][] ccnts, out HierarchyIndex[] chierarchy,
                RetrievalModes.External, ContourApproximationModes.ApproxSimple);
            //2.8查询待得知数字轮廓及特征并进行筛选,此处得知高度为30
            int select_parts = 0;
            for (int i = 0; i < ccnts.Length; i++)
            {
                Rect rect = Cv2.BoundingRect(ccnts[i]);
                if (rect.Height == 30) select_parts += 1; 
            }
            Point[][] sccnts = new Point[select_parts][];
            for(int i = 0; i < ccnts.Length; i++)
            {
                Rect rect = Cv2.BoundingRect(ccnts[i]);
                if (rect.Height == 30)
                //筛选高度满足卡号数字特征的轮廓
                {
                    for(int j = 0; j < select_parts; j++)
                    {
                        if (sccnts[j] == null)
                        {
                            sccnts[j] = ccnts[i];
                            break;
                        }
                    }
                }
            }
            //2.9轮廓由左向右排序
            sccnts = contours_sort(sccnts, "left-to-right");
            Rect[] rects = new Rect[select_parts];
            //3.模板中数字查询并添加至原图
            for (int i = 0; i < select_parts; i++) rects[i] = Cv2.BoundingRect(sccnts[i]);
             //3.1对上述的每个轮廓切为仅存在一个外轮廓图像
            for(int i = 0; i < select_parts; i++)
            {
                string numbers = null;//初始化待添加至图像的字符串
                Mat card_parts = new Mat(cgray, rects[i]));//初始化存在卡号的局部卡片图像
                Cv2.FindContours(card_parts.Clone(), out Point[][] partcnts, out HierarchyIndex[] part_hierarchy,
                    RetrievalModes.External, ContourApproximationModes.ApproxSimple);
                    //寻找全部外轮廓
                Cv2.Threshold(card_parts, card_parts, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
                //卡片局部图像二值化
                partcnts = contours_sort(partcnts, "left-to-right");
                Rect[] part_rects = new Rect[partcnts.Length];
                

5.模板数字与卡片扣取数字匹配

                //3.2扣取每个单个轮廓中的数字,并与模板匹配,添加至原图
                for(int j = 0; j < partcnts.Length; j++)
                {
                    part_rects[j] = Cv2.BoundingRect(partcnts[j]);
                    Mat part = new Mat(card_parts, rects[j]);
                    Cv2.Resize(part, part, new Size(stand_width, stand_height));
                    //将扣取数字图像尺寸与模板数字图像尺寸相同
                    double max_score = double.NegativeInfinity;
                    //初始化每个图像的最佳成绩
                    double max_id = -1;
                    //初始化对应最佳模板的id
                    for(int k = 0; k < templateImages.Length; k++)
                    {
                        Mat matchr = new Mat();
                        Cv2.MatchTemplate(templateImages[k], part, matchr, TemplateMatchModes.CCoeff);
                        //将图像与模板中每个图像进行模板匹配
                        Cv2.MinMaxLoc(matchr, out double minval, out double score);
                        //获取最佳成绩及相应id
                        if (score >= max_score)
                        {
                            max_score = score;
                            max_id = k;
                        }
                    }
                    numbers += max_id.ToString();//存储至字符串,以备后期添加
                  }
                  //将字符串添加至原图
                  Cv2.PutText(card, numbers, new Point(rects[i].X, rects[i].Y - 20), HersheyFonts.HersheySimplex, 1, new Scalar(0, 0, 255), 2);
            }
            Cv2.ImShow("卡片数字显示", card);
            Cv2.WaitKey();
            Cv2.DestroyAllWindows();
            Cv2.WaitKey(0);
        }
    }


图像处理的最终结果
C#-opencvsharp-图像中的数字提取文章来源地址https://www.toymoban.com/news/detail-449235.html

到了这里,关于C#-opencvsharp-图像中的数字提取的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • OpenCV-Python中的图像处理-GrabCut算法交互式前景提取

    cv2.grabCut(img: Mat, mask: typing.Optional[Mat], rect, bgdModel, fgdModel, iterCount, mode=…) img:输入图像 mask:掩模图像,用来确定那些区域是背景,前景,可能是前景/背景等。 可以设置为: cv2.GC_BGD,cv2.GC_FGD,cv2.GC_PR_BGD,cv2.GC_PR_FGD,或者直接输入 0,1,2,3 也行。 rect :包含前景的矩形,格式为

    2024年02月12日
    浏览(43)
  • OpenCV中的图像处理 —— 霍夫线 / 圈变换 + 图像分割(分水岭算法) + 交互式前景提取(GrabCut算法)

    🌎上一节我们介绍了OpenCV中傅里叶变换和模板匹配,这一部分我们来聊一聊霍夫线/圈变换的原理和应用、使用分水岭算法实现图像分割和使用GrabCut算法实现交互式前景提取 🏠哈喽大家好,这里是ErrorError!,一枚某高校大二本科在读的♂同学,希望未来在机器视觉领域能够有

    2023年04月08日
    浏览(46)
  • C#使用OpenCv(OpenCVSharp)图像全局二值化处理实例

    本文实例演示C#语言中如何使用OpenCv(OpenCVSharp)对图像进行全局二值化处理。 目录 图像二值化原理 函数原型 参数说明 实例 效果

    2024年02月13日
    浏览(48)
  • C#使用OpenCv(OpenCVSharp)图像局部二值化处理实例

      本文实例演示C#语言中如何使用OpenCv(OpenCVSharp)对图像进行局部二值化处理。 目录 图像二值化原理 局部二值化 自适应阈值 实例 效果

    2024年02月13日
    浏览(50)
  • C#使用OpenCv(OpenCVSharp)图像处理实例:亮度、对比度、灰度

    本文实例演示C#语言中如何使用OpenCv(OpenCVSharp)对图像进行亮度、对比度、灰度处理。 目录 亮度和对比度原理 灰度 实例 图像亮度通俗理解便是图像的明暗程度,数字图像 f(x,y) = i(x,y) r(x, y) ,如果灰度值在[0,255]之间,则 f 值越接近0亮度越低,f 值越接近255亮度越

    2024年02月13日
    浏览(69)
  • C#使用OpenCv(OpenCVSharp)图像直方图均衡化处理实例

    本文实例演示C#语言中如何使用OpenCv(OpenCVSharp)对图像进行直方图均衡化处理。 直方图均衡化原理 直方图均衡化(Histogram Equalization)是一种常用的图像增强技术,用于改善图像的对比度和亮度分布。它通过重新分配图像灰度级的像素值,使得图像的直方图在灰度范围内更加

    2024年02月07日
    浏览(87)
  • OpenCV数字图像处理——检测出图像中的几何形状并测量出边长、直径、内角

    在传统的自动化生产尺寸测量中,常用的方法是利用卡尺或千分尺对被测工件的某个参数进行多次测量,并取这些测量值的平均值。然而,这些传统的检测设备或手动测量方法存在着一些问题:测量精度不高、测量速度缓慢,以及测量数据无法及时处理等。这些局限性导致无

    2024年02月04日
    浏览(45)
  • Opencv图像特征点提取(

            目录 特征点分类 1 ORB ①特征点检测 ②计算特征描述 2 SIFT 1 SIFT特征检测的步骤 ①.在DOG尺度空间中获取极值点,即关键点。 ②.特征点方向估计 ③生成特征描述 ④.代码实现 3.SURF ①.SURF的介绍 ②.SURF算法步骤 ③. SIFT与SURF效果比较 ④代码实现 4 FAST角点检测且阈值可

    2024年02月14日
    浏览(44)
  • opencv 图像分割与提取(python)

    图像分割与提取 图像中将前景对象作为目标图像分割或者提取出来。 对背景本身并无兴趣 分水岭算法及GrabCut算法对图像进行分割及提取。 用分水岭算法实现图像分割与提取 分水岭算法将图像形象地比喻为地理学上的地形表面,实现图像分割,该算法非常有效。 算法原理

    2024年02月04日
    浏览(46)
  • c++ OpenCV——提取图像的局部区域

    有时候整幅图像需要采取局部,如何进行采取呢。方案如下: 确定裁剪区域的大下 将原图copy一份,原图备用,防止损坏 将copy的图进行裁剪 原图: copy图及需要裁剪的部分: 裁剪图:

    2024年02月09日
    浏览(41)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包