基于投影和众数特点的粘连sku分割
2016-04-19 19:31
211 查看
首先是基本的投影:
然后是基于基本投影的图像分割(割线集合可以用容器,这里不改了):
但是有时候图像的sku是粘连的,可以利用图像中sku的特点(每行的宽度相似,比较规范,那么只要不是超过50%粘连,众数就必定是区分的合理阈值,再利用极值点作为分割点,以及众数作为校验参数)
众数查找:
极值点查找
/** * 图像向x轴做投影后的数组 * * @param imagedata * @param w * 宽 * @param h * 高 * @return */ public static int[] xpro(BitSet bitSet, int width, int height) { int xpro[] = new int[width]; for (int j = 0; j < width; j++) { for (int i = 0; i < height; i++) { if (bitSet.get(i * width + j) == true) xpro[j]++; } } return xpro; } public static int[] xpro(ImageData image) { return xpro(image.getBitSet(), image.getWidth(), image.getHeight()); } /** * 图像向y轴做投影后的数组 * * @param imagedata * @param w * @param h * @return */ public static int[] ypro(BitSet bitSet, int width, int height) { int ypro[] = new int[height]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (bitSet.get(i * width + j) == true) ypro[i]++; } } return ypro; } public static int[] ypro(ImageData image) { return ypro(image.getBitSet(), image.getWidth(), image.getHeight()); }
然后是基于基本投影的图像分割(割线集合可以用容器,这里不改了):
public static Rectangle[] yproSegment(int[] ypro, int width, int height) { int[] L = new int[height - 1];// 左割线集合,最多n-1条分割线,且左分割第一项取0,即图片第一行做起点(需要a行位置没有太多空白噪声) int[] R = new int[height - 1];// 右割线集合 // 两种情况:sku区域起始位置元素为空白区域;起始位置含字符元素 int k1 = 0; int k2 = 0; if (ypro[0] != 0) { k1 = 1; L[0] = 0; } for (int i = 4; i < height; i++) { if (ypro[i] > 0 && ypro[i - 1] > 0 && ypro[i - 2] > 0 && ypro[i - 3] > 0 && ypro[i - 4] == 0) { L[k1] = i - 4; k1++; } else if (ypro[i] == 0 && ypro[i - 1] > 0 && ypro[i - 2] > 0 && ypro[i - 3] > 0 && ypro[i - 4] > 0) { R[k2] = i; k2 += 1; } } if (ypro[ypro.length - 1] != 0) { R[k2] = height; } List<Rectangle> c = new ArrayList<Rectangle>(); for (int i = 0; i < R.length; i++) { if (R[i] != 0 && L[i] < R[i]) { c.add(new Rectangle(0, L[i], width, R[i] - L[i])); } else { break; } } Rectangle[] children = new Rectangle[c.size()]; for (int i = 0; i < children.length; i++) { children[i] = c.get(i); } return children; }
但是有时候图像的sku是粘连的,可以利用图像中sku的特点(每行的宽度相似,比较规范,那么只要不是超过50%粘连,众数就必定是区分的合理阈值,再利用极值点作为分割点,以及众数作为校验参数)
/** * 纵向自动版面分析(众数参考分析) * * @param ypro * @param im * @param h * @param w * @return */ public static int[] ylinelayout(int[] ypro, int width, int height) { // 投影分割图片 boolean flag = false; for (int i : ypro) { if (i == 0) { flag = true; break; } } if (flag == false) { int[] result = { 0, ypro.length }; return result; } int[] L = new int[height - 1];// 左割线集合,最多n-1条分割线,且左分割第一项取0,即图片第一行做起点(需要a行位置没有太多空白噪声) int[] R = new int[height - 1];// 右割线集合 // 两种情况:sku区域起始位置元素为空白区域;起始位置含字符元素 int k1 = 0; int k2 = 0; if (ypro[0] != 0) { k1 = 1; L[0] = 0; } for (int i = 4; i < height; i++) { if (ypro[i] > 0 && ypro[i - 1] > 0 && ypro[i - 2] > 0 && ypro[i - 3] > 0 && ypro[i - 4] == 0) {//左边界特征 L[k1] = i - 4; k1++; } else if (ypro[i] == 0 && ypro[i - 1] > 0 && ypro[i - 2] > 0 && ypro[i - 3] > 0 && ypro[i - 4] > 0) {//右边界特征 R[k2] = i; k2 += 1; } } if (ypro[ypro.length - 1] != 0) { R[k2 + 1] = ypro.length - 1; } ArrayList<Integer> c = new ArrayList<Integer>(); for (int i = 0; i < R.length; i++) { if (R[i] != 0 && L[i] < R[i]) { c.add(L[i]); c.add(R[i]); } else { break; } } int[] gap = new int[c.size() / 2];// 间隙 for (int i = 0; i < gap.length; i++) { gap[i] = c.get(i * 2 + 1) - c.get(i * 2); } // 得到初次分割的所有“字符”的高度 if (gap.length == 1) { int[] result = { L[0], R[0] }; return result; } if (gap.length == 2) { int[] result = { L[0], R[0], L[1], R[1] }; return result; } int Te = (int) (catchE(gap) + 0.5); ArrayList<Integer> newc = new ArrayList<Integer>(); for (int i = 0; i < gap.length; i++) { if (gap[i] >= (int) (Te * 1.5 + 0.5)) { // 对异常gap进行二次分割(粘连字符二次分割函数) log.info("发现异常点:" + gap[i]); int[] newline = improveSegment(c.get(i * 2), c.get(i * 2 + 1), ypro, gap[i], Te); if (newline != null) { for (int j : newline) { newc.add(j); log.info("newline:" + j); } } } } int begin = 0; ArrayList<Integer> allline = new ArrayList<Integer>(); allline.addAll(c); int time = 0; for (int i = 0; i < newc.size(); i++) { int th = newc.get(i); for (int j = begin; j < c.size() - 1; j++) { if (c.get(j) < th && c.get(j + 1) > th) { allline.add(j + 1 + time * 2, th); allline.add(j + 2 + time * 2, th + 1); begin = j; time++; break; } } } return ArrayUtils.toPrimitive(allline.toArray(new Integer[0])); }
众数查找:
/** * 找出众数范围(无补偿众数) * * @param gap * @return */ public static float catchE(int[] gap) { float Te = 0; int[] g = gap.clone(); Arrays.sort(g); int[] times = new int[g.length]; for (int i = 0; i < gap.length; i++) { for (int j = 0; j < g.length; j++) { if (g[j] == gap[i]) { times[j]++; } } } // 得到各gap的出现次数 int tt = 0; int num = 0; for (int i = 0; i < times.length; i++) { if (times[i] > tt) { tt = times[i]; num = i; } } Te = g[num]; return Te; }
极值点查找
/** * 二次分割(找到粘连中的k个线,k》=2) * * @param localypro * @param begin * @param t1 * @return */ public static int findline(int[] localypro, int begin, int t1) { int findline = 0; int len = localypro.length - t1; for (int i = begin; i < len; i++) { int kL = 0; int kR = 0; for (int j = 1; j < t1; j++) { if (localypro[i] <= localypro[i - j]) { kL++; } else { break; } if (localypro[i] <= localypro[i + j]) { kR++; } else { break; } } if (kL == t1 - 1 && kR == t1 - 1) { findline = i; break; } } return findline; } /** * 二次分割 * * @param a * @param b * @param ypro * @param gapE * @param Te * @return */ public static int[] improveSegment(int a, int b, int[] ypro, float gapE, int Te) { if (Te <= 8) return null; int[] localypro = Arrays.copyOfRange(ypro, a, b + 1); // 以t2作为跃迁步长,避免同一区域出现多条分割线,以t1作为分割线阈值,以找到精确分割线 ArrayList<Integer> c = new ArrayList<Integer>(); int t1 = Te - 8; int t2 = Te - 5; for (int i = t2; i < localypro.length - t2; i = i + t2) { int findline = findline(localypro, i, t1); c.add(a + findline); } return ArrayUtils.toPrimitive(c.toArray(new Integer[0])); }
相关文章推荐
- qjson解析和构建
- GUI实现万年历
- 2013(跟2014一样的)
- 如何给你的ASP.NET页面添加HelpPage
- 一些概念
- 如何给你的ASP.NET页面添加HelpPage
- 关于 overridePendingTransition()使用
- [Sicily 1090 Highways] 求最小生成树的两种算法(普里姆算法/克鲁斯卡尔算法)
- 浮点数比较大小
- 拷贝构造函数
- 每日站立会议(二)
- 如何在PADS的封装中做非金属化孔
- zoj2770 差分约束系统
- 广义表(非线性结构)
- php的laravel数据库版本管理器migration
- java事务(一)——事务特性
- MongoDB 命令行操作
- Understanding and Analyzing iOS Application Crash Reports
- 前置++,后置++与运算符计算顺序问题
- 【接口测试】jmeter的使用