基于投影和众数特点的粘连sku分割

来源:互联网 发布:淘宝上架虚拟宝贝教程 编辑:程序博客网 时间:2024/04/29 05:22

首先是基本的投影:

/**     * 图像向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]));    }
0 0
原创粉丝点击