[笔记]图像处理基础知识-学习EasyPR-java

刚刚接触车牌识别,希望能通过一个完整的程序理解车牌识别的具体实现流程。

借助于java基础,只能选择EasyPR的java版本作为研究对象。希望通过此篇记录下我的问题与学习经验,也希望与所有学习的小伙伴们共同讨论其中的问题。

EasyPR的学习博客:https://blog.csdn.net/liuuze5/article/details/46290455

EasyPR-java的博客及源码:https://blog.csdn.net/lgcjava/article/details/52319146

配置环境:jdk1.8   openCV2.4.11   maven工程   JUnit 4(不知道是否必须,还不太懂JUnit的应用)

附上原图:

[笔记]图像处理基础知识-学习EasyPR-java_第1张图片

一、先来测试运行一下:

(1)第一次尝试调用EasyPrTest.java,但不知道具体如何调用那么多方法。失败。

(2)第二次尝试调用GeneralTest.java,还好,这个只需要调用一个方法,成功运行。

[笔记]图像处理基础知识-学习EasyPR-java_第2张图片

但是会报如下错误:

[笔记]图像处理基础知识-学习EasyPR-java_第3张图片

网上查询,应该是内存溢出的问题。有时候检测到第11张照片后出错,现在第5张照片就会出错。解决方法还没找到,有没有知道解决方法的小伙伴,欢迎留言告知,多谢。

二、学习源码(分析GeneralTest测试的debug)

1、Mat src = imread(file.getPath());      

// Mat   (openCV提供的类,用于存储图像)

[笔记]图像处理基础知识-学习EasyPR-java_第4张图片

附地址:http://lib.csdn.net/article/opencv/42000

2、  PlateDetect plateDetect = new PlateDetect();

plateDetect.setPDLifemode(true);

        //调用PlatDetect(车牌检测)中的setPDLifemode()方法

2.1 setPDLifemode()方法

    看到注释:生活模式\工业模式。当前设置为生活模式。(此处的生活模式应该是日常人为照相采集图片,车牌照射角度较小。个人猜测)

        2.1.1 setLifemode()方法

            [笔记]图像处理基础知识-学习EasyPR-java_第5张图片

            设置各项参数。详细参数还不懂,暂时搁置。

3  Vector matVector = new Vector();  //创建一个对象数组,存储图片

4  if (0 == plateDetect.plateDetect(src, matVector)) { }  //如果车牌成功检测到

       4.1 车牌检测    //plateDetect.plateDetect(src, matVector)

            (将图片src检测出车牌图片,存入matVector中)

            有些参数对于车牌定位的效果有非常明显的影响,例如高斯模糊半径、Sobel算子的水平与垂直方向权值、闭操作的矩形宽度。

             车牌检测整体流程:

            [笔记]图像处理基础知识-学习EasyPR-java_第6张图片

            4.1.1 高斯模糊  

              (1)高斯模糊/高斯平滑——用高斯滤波器来模糊一张图片,通常用它来减少图像噪声以及降低细节层次

               GaussianBlur (src, src_blur, new Size(gaussianBlurSize, gaussianBlurSize), 0, 0, BORDER_DEFAULT);

                //参数介绍(源图像,结果图像,高斯内核的大小(宽度、高度可以不同,但都要是正数和奇数,都是由sigma计算而来),高斯函数在X方向的标准偏差,高斯函数在Y方向的标准偏差,用于推断图像外部像素的某种边界模式

                (2)高斯模糊成功后,将处理后的图片写入到tmp/debug_GaussianBlur.jpg

              4.1.2  灰度化 

                (3)将高斯模糊后的彩色图像灰度化   //cvtColor(src_blur, src_gray, CV_RGB2GRAY);

                (4)灰度化成功后,将灰度化图像写入tmp/debug_gray.jpg

            4.1.3  Sobel算子

                (5)将图像进行Sobel(Sobel算子是一种常用的边缘检测算子,是一阶的梯度算法,Gx及Gy分别代表经横向及纵向边缘检测的图像)运算,包括X方向与Y方向,得到图像的一阶水平方向导数。

                (6)将16进制图像转换为8进制图像格式    //convertScaleAbs(grad_x, abs_grad_x);

                在Sobel函数的第二个参数这里使用了cv2.CV_16S。因为OpenCV文档中对Sobel算子的介绍中有这么一句:“in the case of 8-bit input images it will result in truncated derivatives”。即Sobel函数求完导数后会有负值,还有会大于255的值。而原图像是uint8,即8位无符号数,所以Sobel建立的图像位数不够,会有截断。因此要使用16位有符号的数据类型,即cv2.CV_16S。

                在经过处理后,别忘了用convertScaleAbs()函数将其转回原来的uint8形式。否则将无法显示图像,而只是一副灰色的窗口。

                附上查询地址:https://blog.csdn.net/sunny2038/article/details/9170013

                (7)将Sobel处理后的X方向的图像与Y方向的图像叠加。

                // addWeighted(abs_grad_x, SOBEL_X_WEIGHT, abs_grad_y, SOBEL_Y_WEIGHT, 0, grad);

                   (8)将叠加后的图片添加到tmp/debug_Sobel.jpg中

                4.1.4  二值化(将灰度图像转换为二值图像)

                  (9)threshold(grad, img_threshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);

                  (10)将二值化后的图像存入tmp/debug_threshold.jpg中。

                4.1.5  闭操作(先膨胀后腐蚀,排除小型黑洞,突出了比原图轮廓区域更暗的区域)

                    (11)  首先创建一个固定尺寸的矩形的矩阵     //Mat element = getStructuringElement(MORPH_RECT, new Size(morphSizeWidth, morphSizeHeight));

                     (12)进行闭操作运算    //morphologyEx(img_threshold, img_threshold, MORPH_CLOSE, element);

                     (13)将处理后的图片存到tmp/debug_morphology.jpg中

                4.1.6 求轮廓

                     (14)使用findContours()方法,提取二进制图像(上一步处理的图像)的外部轮廓,并将所有轮廓保存在contours中。

                        (15)在原图中画出轮廓    //drawContours(result, contours, -1, new Scalar(0, 0, 255, 255));

                4.1.7   筛选轮廓

                         (16)对轮廓求最小外接矩形    //RotatedRect mr = minAreaRect(contours.get(i));

                         (17)将合适大小的轮廓提取出来,添加到rects中

                4.1.8    矩形旋转

                        (18)。。。。。

                        (19)

            4.1.1   车牌定位    //Vector matVec = plateLocate.plateLocate(src);    

                

            4.1.2    SVM train

            4.1.3    Plate judge

                

                        

5  CharsRecognise cr = new CharsRecognise();   //进行字符识别

     5.1    String result = cr.charsRecognise(matVector.get(i));   //对每一个图片进行字符识别

        5.1.2   charsSegment()方法

               (1)如果数据不空,将彩色图像转换为灰度图像    cvtColor(input, input_grey, CV_RGB2GRAY);

                (2)???Mat tmpMat = new Mat(input, new Rect((int) (w * 0.1), (int) (h * 0.1), (int) (w * 0.8), (int) (h * 0.8)));

                (3)判断车牌图像的颜色      switch (getPlateType(tmpMat, true)) {   }

                (4)按照不同的车牌颜色,进行不同参数的图像二值化

                    /*

                    case BLUE:

                        threshold(input_grey, img_threshold, 10, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);
                        break;
                    case YELLOW:
                        threshold(input_grey, img_threshold, 10, 255, CV_THRESH_OTSU + CV_THRESH_BINARY_INV);

                        break;

                */

                (5)去除处理后的二值图像车牌上方的柳钉以及下方的横线等干扰    clearLiuDing(img_threshold);

                            柳丁的size=7;

                            创建一个Map(1行,与图像的行数相同的列数,CV_32F类型).asMat()

未完待续。

你可能感兴趣的:(Easy-JAVA学习笔记)