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来做的)感谢
作者:奇迹迪
链接:https://www.jianshu.com/p/25ac6dac1408