• 基于投影和众数特点的粘连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]));
        }
  • 相关阅读:
    2018第一发:记一次【Advanced Installer】打包之旅
    Nginx 实现端口转发
    php支付宝手机网页支付类实例
    磁盘阵列操作实战
    错误修改/etc/fstab,导致系统无法开机
    linux 查看机器的cpu,操作系统等命令
    shell实现https登录
    linux tomcat配置https
    ArrayList和Vector以及synchronizedList
    java synchronized修饰普通方法,修饰静态方法,修饰代码块,修饰线程run方法 比较
  • 原文地址:https://www.cnblogs.com/zhangdebin/p/5567904.html
Copyright © 2020-2023  润新知