基于投影和众数特点的粘连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]));
    }

posted on 2016-04-19 19:31  决心1119  阅读(222)  评论(0编辑  收藏  举报

导航