精华内容
下载资源
问答
  • Java基于opencv实现图像数字识别(四)—图像降噪 我们每一步的工作都是基于前一步的,我们先把我们前面的几个函数封装成一个工具类,以后我们所有的函数都基于这个工具类 这个工具类呢,就一个成员变量Mat,非常的简单...

    Java基于opencv实现图像数字识别(四)—图像降噪

    我们每一步的工作都是基于前一步的,我们先把我们前面的几个函数封装成一个工具类,以后我们所有的函数都基于这个工具类

    这个工具类呢,就一个成员变量Mat,非常的简单,这里给出代码

    public class ImageUtils {
        private static final int BLACK = 0;
        private static final int WHITE = 255;
    
        private Mat mat;
    
        /**
         * 空参构造函数
         */
        public ImageUtils() {
    
        }
    
        /**
         * 通过图像路径创建一个mat矩阵
         * 
         * @param imgFilePath
         *            图像路径
         */
        public ImageUtils(String imgFilePath) {
            mat = Imgcodecs.imread(imgFilePath);
        }
    
        public void ImageUtils(Mat mat) {
            this.mat = mat;
        }
    
        /**
         * 加载图片
         * 
         * @param imgFilePath
         */
        public void loadImg(String imgFilePath) {
            mat = Imgcodecs.imread(imgFilePath);
        }
    
        /**
         * 获取图片高度的函数
         * 
         * @return
         */
        public int getHeight() {
            return mat.rows();
        }
    
        /**
         * 获取图片宽度的函数
         * 
         * @return
         */
        public int getWidth() {
            return mat.cols();
        }
    
        /**
         * 获取图片像素点的函数
         * 
         * @param y
         * @param x
         * @return
         */
        public int getPixel(int y, int x) {
            // 我们处理的是单通道灰度图
            return (int) mat.get(y, x)[0];
        }
    
        /**
         * 设置图片像素点的函数
         * 
         * @param y
         * @param x
         * @param color
         */
        public void setPixel(int y, int x, int color) {
            // 我们处理的是单通道灰度图
            mat.put(y, x, color);
        }
    
        /**
         * 保存图片的函数
         * 
         * @param filename
         * @return
         */
        public boolean saveImg(String filename) {
            return Imgcodecs.imwrite(filename, mat);
        }
    }
    
    

    灰度化和二值化的代码我没有贴出来,因为代码实在有点长

    我们接着上一步的成果,来开始我们的降噪

    一、8邻域降噪

    我感觉9宫格降噪更形象一点;即9宫格中心被异色包围,则同化
    8邻域降噪

    降噪效果还是蛮好的,这个方法对小噪点比较好

    /**
         * 8邻域降噪,又有点像9宫格降噪;即如果9宫格中心被异色包围,则同化
         * @param pNum 默认值为1
         */
        public void navieRemoveNoise(int pNum) {
            int i, j, m, n, nValue, nCount;
            int nWidth = getWidth(), nHeight = getHeight();
    
            // 对图像的边缘进行预处理
            for (i = 0; i < nWidth; ++i) {
                setPixel(i, 0, WHITE);
                setPixel(i, nHeight - 1, WHITE);
            }
    
            for (i = 0; i < nHeight; ++i) {
                setPixel(0, i, WHITE);
                setPixel(nWidth - 1, i, WHITE);
            }
    
            // 如果一个点的周围都是白色的,而它确是黑色的,删除它
            for (j = 1; j < nHeight - 1; ++j) {
                for (i = 1; i < nWidth - 1; ++i) {
                    nValue = getPixel(j, i);
                    if (nValue == 0) {
                        nCount = 0;
                        // 比较以(j ,i)为中心的9宫格,如果周围都是白色的,同化
                        for (m = j - 1; m <= j + 1; ++m) {
                            for (n = i - 1; n <= i + 1; ++n) {
                                if (getPixel(m, n) == 0) {
                                    nCount++;
                                }
                            }
                        }
                        if (nCount <= pNum) {
                            // 周围黑色点的个数小于阀值pNum,把该点设置白色
                            setPixel(j, i, WHITE);
                        }
                    } else {
                        nCount = 0;
                        // 比较以(j ,i)为中心的9宫格,如果周围都是黑色的,同化
                        for (m = j - 1; m <= j + 1; ++m) {
                            for (n = i - 1; n <= i + 1; ++n) {
                                if (getPixel(m, n) == 0) {
                                    nCount++;
                                }
                            }
                        }
                        if (nCount >= 7) {
                            // 周围黑色点的个数大于等于7,把该点设置黑色;即周围都是黑色
                            setPixel(j, i, BLACK);
                        }
                    }
                }
            }
    
        }
    
    
    
    
    
    二、连通域降噪

    floodFill函数

    我们先介绍一个函数(floodFill)

    floodFill就是把一个点x的所有相邻的点都涂上x点的颜色,一直填充下去,直到这个区域内所有的点都被填充完为止

    在计算的过程中,每扫描到一个黑色(灰度值为0)的点,就将与该点连通的所有点的灰度值都改为1,因此这一个连通域的点都不会再次重复计算了。下一个灰度值为0的点所有连通点的颜色都改为2,这样依次递加,直到所有的点都扫描完。接下来再次扫描所有的点,统计每一个灰度值对应的点的个数,每一个灰度值的点的个数对应该连通域的大小,并且不同连通域由于灰度值不同,因此每个点只计算一次,不会重复。这样一来就统计到了每个连通域的大小,再根据预设的阀值,如果该连通域大小小于阀值,则其就为噪点。这个算法比较适合检查大的噪点,与上个算法正好相反。

    连通域降噪

    因为我找的图像关系,效果可能不咋明显;

    /**
         * 连通域降噪
         * @param pArea 默认值为1
         */
        public void contoursRemoveNoise(double pArea) {
            int i, j, color = 1;
            int nWidth = getWidth(), nHeight = getHeight();
    
            for (i = 0; i < nWidth; ++i) {
                for (j = 0; j < nHeight; ++j) {
                    if (getPixel(j, i) == BLACK) {
                        //用不同颜色填充连接区域中的每个黑色点
                        //floodFill就是把一个点x的所有相邻的点都涂上x点的颜色,一直填充下去,直到这个区域内所有的点都被填充完为止
                        Imgproc.floodFill(mat, new Mat(), new Point(i, j), new Scalar(color));
                        color++;
                    }
                }
            }
    
            //统计不同颜色点的个数
            int[] ColorCount = new int[255];
    
            for (i = 0; i < nWidth; ++i) {
                for (j = 0; j < nHeight; ++j) {
                    if (getPixel(j, i) != 255) {
                        ColorCount[getPixel(j, i) - 1]++;
                    }
                }
            }
    
            //去除噪点
            for (i = 0; i < nWidth; ++i) {
                for (j = 0; j < nHeight; ++j) {
    
                    if (ColorCount[getPixel(j, i) - 1] <= pArea) {
                        setPixel(j, i, WHITE);
                    }
                }
            }
    
            for (i = 0; i < nWidth; ++i) {
                for (j = 0; j < nHeight; ++j) {
                    if (getPixel(j, i) < WHITE) {
                        setPixel(j, i, BLACK);
                    }
                }
            }
    
        }
    
    

    注:
    本文章参考了很多博客,感谢;主要是跟着一个博客来实现的https://blog.csdn.net/ysc6688/article/category/2913009(也是基于opencv来做的,只不过他是用c++实现的)感谢

    展开全文
  • Java基于opencv实现图像数字识别(一)

    千次阅读 2018-06-09 21:12:36
    Java基于opencv实现图像数字识别(一) 最近分到了一个任务,要做数字识别,我分配到的任务是把数字一个个的分开;当时一脸懵逼,直接百度java如何分割图片中的数字,然后就百度到了用BufferedImage这个类进行操作;...

    Java基于opencv实现图像数字识别(一)

    最近分到了一个任务,要做数字识别,我分配到的任务是把数字一个个的分开;当时一脸懵逼,直接百度java如何分割图片中的数字,然后就百度到了用BufferedImage这个类进行操作;尝试着做了一下,做到灰度化,和二值化就做不下去了;然后几乎就没有啥java的资料了,最多的好像都是c++,惹不起、惹不起……

    我也想尝试着用c++做一下,百度到了c++基于opencv来做图像识别的;但是要下vs啊,十几个g呢,我内存这么小,配置这么麻烦,而且vs各个版本又有自己的特色;百度了以下,java基于opencv来做图像识别,发现也很少,但是有资料啊,而且配置也很简单啊,能做到就做到哪,慢慢学;现在我已经做到切割图片了,用的是投影法,效果还可以。可以先看以下
    Java基于opencv实现图像数字识别

    我们来一步步实现,先从下载opencv、配置java环境、写一个测试用例开始;肯定比你想象中的要简单

    一、下载opencv,我用的是windows系统,这个应该没啥区别吧,java跨平台的

    直接百度搜索opencv,建议去opencv中文网站下载吧;我刚开始下载的时候,下到一大半的时候突然停了,就这样停了;明明中文网站啊,还需要梯子吗;算了,我还是翻墙吧,然后就下好了,一步步安装,就好了,没啥难的。安装好后,就长这样,我也没有配置环境;
    安装opencv

    二、配置java开发环境

    也很简单,就是把F:\openCv\opencv\build\java这个目录下的一个jar添加到环境变量,然后看你是系统是多少位的,把相应目录下的文件拷贝到你的项目中
    opencv配置java开发环境
    空项目大概就是这样
    opencv-java空项目

    三、我们测试一下,就用opencv二值化处理一张图片

    我们来看一下代码

    public static void main(String[] args) {
            // 这个必须要写,不写报java.lang.UnsatisfiedLinkError
             System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    
            File imgFile = new File("C:/Users/admin/Desktop/open/test.png");
            String dest = "C:/Users/admin/Desktop/open";
            Mat src = Imgcodecs.imread(imgFile.toString(), Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
    
            Mat dst = new Mat();
    
            Imgproc.adaptiveThreshold(src, dst, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 13, 5);
            Imgcodecs.imwrite(dest + "/AdaptiveThreshold" + imgFile.getName(), dst);
        }
    
    

    我们来看一下效果图
    opencv二值化处理图片

    展开全文
  • Java基于opencv实现图像数字识别(二)—基本流程 做一个项目之前呢,我们应该有一个总体把握,或者是进度条;来一步步的督促着我们来完成这个项目,在我们正式开始前呢,我们先讨论下流程。 我做的主要是表格中数字...

    Java基于opencv实现图像数字识别(二)—基本流程

    做一个项目之前呢,我们应该有一个总体把握,或者是进度条;来一步步的督促着我们来完成这个项目,在我们正式开始前呢,我们先讨论下流程。

    我做的主要是表格中数字的识别,但这个不是重点。重点是通过这个我们可以举一反三,来实现我们自己的业务。

    图像的识别主要分为两步:图片预处理和图像识别;这两步都很重要

    图像预处理:
    1、 图像灰度化;二值化
    2、 图像降噪,去除干扰线
    3、 图像腐蚀、膨胀处理
    4、 字符分割
    5、 字符归一化

    图像识别:
    1、 特征值提取
    2、 训练
    3、 测试

    灰度化:

    在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值;因此,灰度图像每个像素点只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。一般常用的是加权平均法来求像素点的灰度值

    常见的加权方法如下:
    1:)Gray = B ; Gray = G ; Gray = R
    2:)Gray = max({B , G , R})
    3:)Gray = (B + G + R) / 3
    4:)Gray = 0.072169 * B + 0.715160 * G + 0.212671 * R
    5:)Gray = 0.11 * B + 0.59 * G + 0.3 * R

    这几种方法中,第一为分量法,即用RGB三个分量的某一个分量作为该点的灰度值;第二种方法为最大值法,将彩色图像中的三个分量亮度的最大值作为灰度图的灰度值;第三种方法是将彩色图像中的三分量求平均得到一个灰度图;后两种都属于加权平均法,其中第四种是opencv开发库所采用的一种求灰度值算法;第五种为从人体生理学角度所提出的一种求灰度值算法(人眼对绿色的敏感最高,对蓝色敏感最低)

    二值化:

    图像的二值化,就是将图像上的像素点的灰度值设置位0或255这两个极点,也就是将整个图像呈现出明显的只有黑和白的视觉效果

    图像降噪:

    就是处理掉一些干扰因素;

    主要的降噪算法

    滤波类:通过设计滤波器对图像进行处理。特点是速度往往比较快,很多卷积滤波可以借助快速傅里叶变化来加速

    稀疏表达类:自然图片之所以看起来不同于随机噪音/人造结构,是因为大家发现他们总会在某一个横型下存在稀疏表达。而我们想排除的噪音往往无法被稀疏化。基于这个判别式模型,用稀疏性来约束自然图像,在很多逆问题里取得了拔群的效果

    外部先验:如果从有噪音的图片本身无法找到规律,我们也可以借助其他类似但又没有噪音的图片,来总结图片具有的固有属性。这一类方法利用的外部图片来创造先验条件,然后用于约束需要预测的图片。最有代表性就是混合高斯模型

    聚类低秩:除了可稀疏性,低秩性也是自然图片常见的一个特性。数学上,可稀疏表达的数据可以被认为是在Union of low-dimensional subspaces;而低秩数据则是直接存在于一个Low-dimensional subspace。这个更严格的限制往往也可以取得很好的降噪效果。

    深度学习(Deep Learning):这类可以归于外部先验的子类,如果说解决逆问题的关键,是寻找一个好的图像约束器,那么我们为什么不用一个最好的约束器?深度学习方法的精髓,就在于通过大量的数据,学习得到一个高复杂度(多层网络结构)的图片约束器,从而将学习外部先验条件这一途径推到极限。近期的很多这类工作,都是沿着这一思路,取得了非常逆天的效果。

    字符分割:就是把图片有用的部分一个个分割下来;字符分割有很多方法,但并不是每一种方法都是万能的,我们需要根据自己的业务来调整;常见的就是投影法和连通域法

    投影法:就是分析每一维上黑色像素点的个数(假设是二值化的图像),然后设置一个阙值,根据这个阙值来分割图片

    图像腐蚀、膨胀处理

    腐蚀:图像的一部分区域与指定的核进行卷积,求核的最小值并赋值给指定区域。 腐蚀可以理解为图像中高亮区域的领域缩小。

    膨胀:图像的一部分区域与指定的核进行卷积,求核的最大值并赋值给指定区域。 膨胀可以理解为图像中高亮区域的领域扩大。

    字符的归一化:

    就是将分割好的图像内的字符归一化到一个标准模板大小;归一化的理想结果就是:归一化到标准模板大小;倾斜校正;笔画宽度归一化;字形归一化。

    注:
    本文章参考了很多博客,感谢;主要是跟着一个博客来实现的https://blog.csdn.net/ysc6688/article/category/2913009(也是基于opencv来做的,只不过他是用c++实现的)感谢

    展开全文
  • Java基于opencv实现图像数字识别(五)—投影法分割字符 水平投影法 1、水平投影法就是先用一个数组统计出图像每行黑色像素点的个数(二值化的图像); 2、选出一个最优的阀值,根据比这个阀值大或小,用一个数组记录...

    Java基于opencv实现图像数字识别(五)—投影法分割字符

    水平投影法

    1、水平投影法就是先用一个数组统计出图像每行黑色像素点的个数(二值化的图像);

    2、选出一个最优的阀值,根据比这个阀值大或小,用一个数组记录相应Y轴的坐标;

    3、因为是水平切割我们只需要Y轴的切割点即可,宽度默认图像的宽,高度可以用相邻的切割点相减得到;

    4、优化切割点,把切割点靠近的都清除掉

    5、设置感应区的区域,切割图片

    垂直投影法和水平投影法类似,对比思考一下

    因为我做的是表格的切割,你如果想实现验证码的切割,或者其他的类比这个,我想也是很容易实现的

    我们先看一下,效果,还是很不错的
    投影法分割字符

    水平切割代码

    // 图像切割,水平投影法切割
    public List<Mat> cutImgX() {
        int i, j;
        int nWidth = getWidth(), nHeight = getHeight();
        int[] xNum = new int[nHeight], cNum;
        int average = 0;// 记录像素的平均值
        // 统计出每行黑色像素点的个数
        for (i = 0; i < nHeight; i++) {
            for (j = 0; j < nWidth; j++) {
                if (getPixel(i, j) == BLACK) {
                    xNum[i]++;
                }
    
            }
        }
    
        // 经过测试这样得到的平均值最优
        cNum = Arrays.copyOf(xNum, xNum.length);
        Arrays.sort(cNum);
        for (i = 31 * nHeight / 32; i < nHeight; i++) {
            average += cNum[i];
        }
        average /= (nHeight / 32);
    
        // 把需要切割的y点都存到cutY中
        List<Integer> cutY = new ArrayList<Integer>();
        for (i = 0; i < nHeight; i++) {
            if (xNum[i] > average) {
                cutY.add(i);
            }
        }
    
        // 优化cutY把
        if (cutY.size() != 0) {
    
            int temp = cutY.get(cutY.size() - 1);
            // 因为线条有粗细,优化cutY
            for (i = cutY.size() - 2; i >= 0; i--) {
                int k = temp - cutY.get(i);
                if (k <= 8) {
                    cutY.remove(i);
                } else {
                    temp = cutY.get(i);
    
                }
    
            }
        }
    
        // 把切割的图片都保存到YMat中
        List<Mat> YMat = new ArrayList<Mat>();
        for (i = 1; i < cutY.size(); i++) {
            // 设置感兴趣的区域
            int startY = cutY.get(i - 1);
            int height = cutY.get(i) - startY;
            Mat temp = new Mat(mat, new Rect(0, startY, nWidth, height));
            Mat t = new Mat();
            temp.copyTo(t);
            YMat.add(t);
        }
    
        return YMat;
    }
    

    垂直投影法

    // 图像切割,垂直投影法切割
    public List<Mat> cutImgY() {
    
        int i, j;
        int nWidth = getWidth(), nHeight = getHeight();
        int[] xNum = new int[nWidth], cNum;
        int average = 0;// 记录像素的平均值
        // 统计出每列黑色像素点的个数
        for (i = 0; i < nWidth; i++) {
            for (j = 0; j < nHeight; j++) {
                if (getPixel(j, i) == BLACK) {
                    xNum[i]++;
                }
    
            }
        }
    
        // 经过测试这样得到的平均值最优 , 平均值的选取很重要
        cNum = Arrays.copyOf(xNum, xNum.length);
        Arrays.sort(cNum);
        for (i = 31 * nWidth / 32; i < nWidth; i++) {
            average += cNum[i];
        }
        average /= (nWidth / 28);
    
        // 把需要切割的x点都存到cutY中,
        List<Integer> cutX = new ArrayList<Integer>();
        for (i = 0; i < nWidth; i += 2) {
            if (xNum[i] >= average) {
                cutX.add(i);
            }
        }
    
        if (cutX.size() != 0) {
    
            int temp = cutX.get(cutX.size() - 1);
            // 因为线条有粗细,优化cutY
            for (i = cutX.size() - 2; i >= 0; i--) {
                int k = temp - cutX.get(i);
                if (k <= 10) {
                    cutX.remove(i);
                } else {
                    temp = cutX.get(i);
    
                }
    
            }
        }
    
        // 把切割的图片都保存到YMat中
        List<Mat> XMat = new ArrayList<Mat>();
        for (i = 1; i < cutX.size(); i++) {
            // 设置感兴趣的区域
            int startX = cutX.get(i - 1);
            int width = cutX.get(i) - startX;
            Mat temp = new Mat(mat, new Rect(startX, 0, width, nHeight));
            Mat t = new Mat();
            temp.copyTo(t);
            XMat.add(t);
        }
    
        return XMat;
    }

    注:本文章参考了很多博客,感谢;主要是跟着一个博客来实现的https://blog.csdn.net/ysc6688/article/category/2913009(也是基于opencv来做的)感谢

    展开全文
  • Java基于opencv实现图像数字识别(三)—灰度化和二值化 一、灰度化 灰度化:在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值;因此,灰度图像每个像素点只需一个字节存放灰度值(又称强度值、...
  • 我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。 扫描二维码或搜索下图红色VX号,...Java基于opencv实现图像数字识别(一) 最近分到了一个任务,要做数字...
  • 利用OpenCV实现实时图像识别和图像跟踪图像识别什么是图像识别图像识别的研究现状Android图像识别相关技术基于OpenCV实现实现思路代码部分权限设置AndroidMainifest.xml权限提示方法界面设计activity_img_...
  • opencv英文数字检测识别 python3.x opencv4.x 效果看博客地址:https://blog.csdn.net/qq_26696715/article/details/109898886
  • 腐蚀:去除图像表面像素,将图像逐步缩小,以达到消去点状图像的效果;作用就是将图像边缘的毛刺剔除掉 膨胀:将图像表面不断扩散以达到去除小孔的效果;作用就是将目标的边缘或者是内部的坑填掉 使用相同次数的...
  • digits图像分割后的手写数字图像集,可用于数字识别的练习
  • 和之前的博客C++ 纯 OpenCV 实现扑克牌实时识别步骤一样。 完成电表数字识别主要步骤有: 从摄像头获取电表图片,调整图片大小 二值化后执行闭运算,去除散乱的孤立点 找轮廓,包含数字的矩形轮廓区域,可通过...
  • [图像处理] Python+OpenCV实现车牌区域识别及Sobel算子

    万次阅读 多人点赞 2018-08-06 22:17:16
    由于最近太忙,这篇文章只给出相关代码供大家学习,过一段时间会详细的写一些列Python图像处理的文章,包括各种算法原理、图像识别、图像增强、图像分类、深度学习等。本篇文章主要调用OpenCV库(cv2)进行车牌区域...
  • 数字识别可以应用在许多领域,如数字型验证码的识别,车牌识别等领域。下面借我之前完成的一个数字验证码识别的小项目来简单认识一下图象识别领域的知识。  如果在阅读这篇文章时有什么疑问,可以参考一下之前的...
  • 正在用opencv3做一个数字图像识别的小项目,要用到KNN,但是不熟悉它的接口,因此,借鉴了大佬的博客,基本照搬了代码,代码如下: 大佬的链接如下:http://www.cnblogs.com/denny402/p/5033898.html // ...
  • 本文是本系列的第8篇文章,也是终结篇章。在本文中我们主要讲5层卷积神经网络参数更新和训练的代码实现,以及如何使用5层卷积神经网络来实现0~9的手写数字图像识别。首先还是列出本系列其它博文...
  • 利用OpenCV图像处理技术,对图像进行灰度处理,二值分析,降噪,滤波等,识别照片中的数字,完美精确, C++ VS2015代码,有详细的代码注释,完整源码。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,486
精华内容 4,994
关键字:

opencv实现数字图像识别