本文主要是介绍基于投影和众数特点的粘连sku分割,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
首先是基本的投影:
/*** 图像向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]));}
这篇关于基于投影和众数特点的粘连sku分割的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!