字符分割_字符分割代码java - CSDN
精华内容
参与话题
  • 车牌识别之二:字符分割

    万次阅读 热门讨论 2010-10-13 11:06:00
    车牌识别大概步骤可分为:车牌定位,字符分割,字符识别三个步骤。细分点可以有以下几个步骤: (1)将图片灰度化与二值化 (2)去噪,然后切割成一个一个的字符 (3)提取每一个字符的特征,生成特征矢量或特征...

    车牌识别大概步骤可分为:车牌定位,字符分割,字符识别三个步骤。

    细分点可以有以下几个步骤:

    (1)将图片灰度化与二值化

    (2)去噪,然后切割成一个一个的字符

    (3)提取每一个字符的特征,生成特征矢量或特征矩阵

    (4)分类与学习。将特征矢量或特征矩阵与样本库进行比对,挑选出相似的那类样本,将这类样本的值作为输出结果。

     

    车牌定位可以参考这里,网上也有很多关于这个问题的讨论,理论上觉得可行,但实际上没有操作过,等有空再去搞搞。
    http://blog.csdn.net/sing_sing/archive/2010/10/13/5937725.aspx

    这几天研究了一下车牌字符分割的问题,前提是已经进行了车牌定位,角度校正等预处理。

    用到的主要知识有:二值化,形态学操作,轮廓查找等。

    字符分割网上资料比较少,本人接触opencv一段时间,自己瞎搞了一下,以此抛砖引玉,希望与各位交流一下。

    以下为全部源代码:


    //==============================================

    //write by sing

    //2010-10-10

    //==============================================


    #include "stdafx.h"

    //找出含车牌文字的最左端
    void findX(IplImage* img, int* min, int* max)
    {
        int found = 0;
        CvScalar maxVal = cvRealScalar(img->width * 255);
        CvScalar val = cvRealScalar(0);
        CvMat data;
        int minCount = img->width * 255 / 5;
        int count = 0;

        for (int i = 0; i < img->width; i++) {
            cvGetCol(img, &data, i);
            val = cvSum(&data);
            if (val.val[0] < maxVal.val[0]) {
                count = val.val[0];
                if (count > minCount && count < img->width * 255) {
                    *max = i;
                    if (found == 0) {
                        *min = i;
                        found = 1;
                    }
                }
            }
        }

    }

    //找出含车牌文字的最上端,排除两颗螺丝的位置
    void findY(IplImage* img, int* min, int* max)
    {
        int found = 0;
        CvScalar maxVal = cvRealScalar(img->height * 255);
        CvScalar val = cvRealScalar(0);
        CvMat data;
        int minCount = img->width * 255 / 5;
        int count = 0;

        for (int i = 0; i < img->height; i++) {
            cvGetRow(img, &data, i);
            val = cvSum(&data);
            if (val.val[0] < maxVal.val[0]) {
                count = val.val[0];
                if (count > minCount && count < img->height * 255) {
                    *max = i;
                    if (found == 0) {
                        *min = i;
                        found = 1;
                    }
                }
            }
        }
    }

    //车牌字符的最小区域
    CvRect findArea(IplImage* img)
    {
        int minX, maxX;
        int minY, maxY;
      
        findX(img, &minX, &maxX);
        findY(img, &minY, &maxY);

        CvRect rc = cvRect(minX, minY, maxX - minX, maxY - minY);

        return rc;
    }

    int main(int argc, char* argv[])
    {
        IplImage* imgSrc = cvLoadImage("cp.jpg", CV_LOAD_IMAGE_COLOR);
        IplImage* img_gray = cvCreateImage(cvGetSize(imgSrc), IPL_DEPTH_8U, 1);
      
        cvCvtColor(imgSrc, img_gray, CV_BGR2GRAY);
        cvThreshold(img_gray, img_gray, 100, 255, CV_THRESH_BINARY);

        //寻找最小区域,并截取
        CvRect rc = findArea(img_gray);
        cvSetImageROI(img_gray, rc);
        IplImage* img_gray2 = cvCreateImage(cvSize(rc.width, rc.height), IPL_DEPTH_8U, 1);
        cvCopyImage(img_gray, img_gray2);
        cvResetImageROI(img_gray);

        IplImage* imgSrc2 = cvCreateImage(cvSize(rc.width, rc.height), IPL_DEPTH_8U, 3);
        cvSetImageROI(imgSrc, rc);
        cvCopyImage(imgSrc, imgSrc2);
        cvResetImageROI(imgSrc);

        //形态学
        cvMorphologyEx(img_gray2, img_gray2, NULL, NULL, CV_MOP_CLOSE);

        CvSeq* contours = NULL;
        CvMemStorage* storage = cvCreateMemStorage(0);
        int count = cvFindContours(img_gray2, storage, &contours,
            sizeof(CvContour), CV_RETR_EXTERNAL);

        int idx = 0;
        char szName[56] = {0};

        for (CvSeq* c = contours; c != NULL; c = c->h_next) {

            //cvDrawContours(imgSrc2, c, CV_RGB(255, 0, 0), CV_RGB(255, 255, 0), 100);
            CvRect rc = cvBoundingRect(c);
            cvDrawRect(imgSrc2, cvPoint(rc.x, rc.y), cvPoint(rc.x + rc.width, rc.y + rc.height), CV_RGB(255, 0, 0));

            if (rc.width < imgSrc2->width / 10 && rc.height < imgSrc2->height / 5) {
                continue;
            }


            IplImage* imgNo = cvCreateImage(cvSize(rc.width, rc.height), IPL_DEPTH_8U, 3);
            cvSetImageROI(imgSrc2, rc);
            cvCopyImage(imgSrc2, imgNo);
            cvResetImageROI(imgSrc2);
          
            sprintf(szName, "wnd_%d", idx++);
            cvNamedWindow(szName);
            cvShowImage(szName, imgNo);
            cvReleaseImage(&imgNo);
        }
      
        cvNamedWindow("src");
        cvShowImage("src", imgSrc2);

        cvWaitKey(0);

        cvReleaseMemStorage(&storage);
        cvReleaseImage(&imgSrc);
        cvReleaseImage(&imgSrc2);
        cvReleaseImage(&img_gray);
        cvReleaseImage(&img_gray2);

        cvDestroyAllWindows();

        return 0;
    }

     

    输入图像:



    运行结果截图如下:

     

     

    展开全文
  • 【中文OCR】中文字符图片的分割方法

    千次阅读 热门讨论 2019-01-14 21:54:25
    因为现在开源的OCR代码比较多,相对而言对字符图片的分割的方法提的比较少,尤其是中文字符图片的分割还是有一定困难在里面的。 一、普遍使用的切割方法 现在大部分开源项目上用切割方法还是基于水平、垂直投影...

    最近想做一个关于中文OCR的小系列,也是对之前做的东西的一个总结。作为这个系列的第一篇,我觉得还是有必要说一下关于中文字符图片分割的问题。因为现在开源的OCR代码比较多,相对而言对字符图片的分割的方法提的比较少,尤其是中文字符图片的分割还是有一定困难在里面的。

    一、普遍使用的切割方法

    现在大部分开源项目上用切割方法还是基于水平、垂直投影字符切割方法。

    原理比较简单容易理解,也比较容易实现。先对一个文本图片进行水平投影,得到图片在垂直方向上的像素分布,有像素存在的区域即为文本所在区域;将该行文本切割下来,再对该行文本图片进行垂直投影,得到水平方向的像素分布,同理有像素存在的区域基本字符所在区域。

    from PIL import Image
    import numpy as np
    
    min_thresh = 2 #字符上最少的像素点
    min_range = 5 #字符最小的宽度
    
    def vertical(img_arr):
        h,w = img_arr.shape
        ver_list = []
        for x in range(w):
            ver_list.append(h - np.count_nonzero(img_arr[:, x]))
        return ver_list
    
    def horizon(img_arr):
        h,w = img_arr.shape
        hor_list = []
        for x in range(h):
            hor_list.append(w - np.count_nonzero(img_arr[x, :]))
        return hor_list
    
    def OTSU_enhance(img_gray, th_begin=0, th_end=256, th_step=1):  
        max_g = 0  
        suitable_th = 0  
        for threshold in xrange(th_begin, th_end, th_step):  
            bin_img = img_gray > threshold  
            bin_img_inv = img_gray <= threshold  
            fore_pix = np.sum(bin_img)  
            back_pix = np.sum(bin_img_inv)  
            if 0 == fore_pix:  
                break  
            if 0 == back_pix:  
                continue  
    
            w0 = float(fore_pix) / img_gray.size  
            u0 = float(np.sum(img_gray * bin_img)) / fore_pix  
            w1 = float(back_pix) / img_gray.size  
            u1 = float(np.sum(img_gray * bin_img_inv)) / back_pix  
            # intra-class variance  
            g = w0 * w1 * (u0 - u1) * (u0 - u1)  
            if g > max_g:  
                max_g = g  
                suitable_th = threshold  
        return suitable_th 
    
    def cut_line(horz, pic):
        begin, end = 0, 0
        w, h = pic.size
        cuts=[]
        for i,count in enumerate(horz):
           if count >= min_thresh and begin == 0:
                begin = i
           elif count >= min_thresh and begin != 0:
                continue
           elif count <= min_thresh and begin != 0:
                end = i
                #print (begin, end), count
                if end - begin >= 2:
                    cuts.append((end - begin, begin, end))
                    begin = 0
                    end = 0
                    continue
           elif count <= min_thresh or begin == 0:
                continue
        cuts = sorted(cuts, reverse=True)
        if len(cuts) == 0:
            return 0, False
        else:
            if len(cuts) > 1 and cuts[1][0] in range(int(cuts[0][0] * 0.8), cuts[0][0]):
                return 0, False
            else:
                crop_ax = (0, cuts[0][1], w, cuts[0][2])
        img_arr = np.array(pic.crop(crop_ax))
        return img_arr, True
    
    def simple_cut(vert):
        begin, end = 0,0
        cuts = []
        for i,count in enumerate(vert):
           if count >= min_thresh and begin == 0:
                begin = i
           elif count >= min_thresh and begin != 0:
                continue
           elif count <= min_thresh and begin != 0:
                end = i
                #print (begin, end), count
                if end - begin >= min_range:
                    cuts.append((begin, end))
                    
                    begin = 0
                    end = 0
                    continue
           elif count <= min_thresh or begin == 0:
                continue
        return cuts
    
    pic_path = './test.jpg'
    save_path = './SplitChar/'
    
    src_pic = Image.open(pic_path).convert('L')
    src_arr = np.array(src_pic)
    threshold = OTSU_enhance(src_arr)
    bin_arr = np.where(src_arr < threshold, 0, 255) #先用大津阈值将图片二值化处理
    
    horz = horizon(bin_arr) #获取到文本 水平 方向的投影
    line_arr, flag = cut_line(horz, src_pic) #把文字(行)所在的位置切割下来
    if flag == False: #如果flag==False 说明没有切到一行文字
        exit()
    line_arr = np.where(line_arr < threshold, 0, 255)
    line_img = Image.fromarray((255 - line_arr).astype("uint8"))
    width, height = line_img.size
    
    vert = vertical(line_arr) #获取到该行的 垂直 方向的投影
    cut = simple_cut(vert) #直接对目标行进行切割
    
    for x in range(len(cut)):
        ax = (cut[x][0] - 1, 0, cut[x][1] + 1, height)
        temp = line_img.crop(ax)
        temp = image_unit.resize(temp, save_size)
        temp.save('{}/{}.jpg'.format(save_path, x))

    因为在切割的时候,根据手动设置的字符宽度和、字符间隙宽度的阈值进行分割,所以存在以下几个的问题:

      1、对字符排列密集的图片分割效果差

      2、对左右结构的字,且左右结构缝隙比较大如“川”

      3、对一部分垂直投影占得像素点比较少的字符,可以会认为是噪声,比如“上”

      4、需要手动设置阈值,阈值不能对所有文本适用

      5、对中英文、标点、数字的混合文本处理十分不好

    二、统计分割

    上面的方法的缺陷在于它的阈值选择上,如何分割字符的问题就变成了,选择什么样的阈值去判断字符宽度和两个字符的间隙。其实一开始我也想到过用网络直接去定位一块一块字符,但实际操作了一下,精确度着实不高,而且会影响速度。

    所以有如下几个任务:

      1、自动选择阈值去判断什么样的宽度是一个完整的字,什么样的宽度是一个偏旁部首

      2、如果是偏旁,如何与另一个偏旁相连

      3、如何是标点或是数字、英文怎么办呢?它们的宽度和偏旁是类似的

    那么只需要在上面的基础上稍作一下修改,找出特定的阈值,从而判断是什么部分,作出什么操作就OK

    from sklearn.cluster import KMeans
    
    def isnormal_width(w_judge, w_normal_min, w_normal_max):
        if w_judge < w_normal_min:
            return -1
        elif w_judge > w_normal_max:
            return 1
        else:
            return 0
    
    def cut_by_kmeans(pic_path, save_path, save_size):
        src_pic = Image.open(pic_path).convert('L') #先把图片转化为灰度
        src_arr = np.array(src_pic)
        threshold = OTSU_enhance(src_arr) * 0.9 #用大津阈值
        bin_arr = np.where(src_arr < threshold, 0, 255) #二值化图片
        
        horz = horizon(bin_arr) #获取到该行的 水平 方向的投影
        line_arr, flag = cut_line(horz, src_pic) #把文字(行)所在的位置切割下来
        if flag == False:
            return flag
    
        line_arr = np.where(line_arr < threshold, 0, 255)
        line_img = Image.fromarray((255 - line_arr).astype("uint8"))
        width, height = line_img.size
        
        vert = vertical(line_arr) #获取到该行的 垂直 方向的投影
        cut = simple_cut(vert) #先进行简单的文字分割(即有空隙就切割)
        
        #cv.line(img,(x1,y1), (x2,y2), (0,0,255),2)    
        width_data = []
        width_data_TooBig = []
        width_data_withoutTooBig = []
        for i in range(len(cut)):
            tmp = (cut[i][1] - cut[i][0], 0) 
            if tmp[0] > height * 1.8:     #比这一行的高度大两倍的肯定是连在一起的
                temp = (tmp[0], i)
                width_data_TooBig.append(temp)
            else:
                width_data_withoutTooBig.append(tmp)
            width_data.append(tmp)
        kmeans = KMeans(n_clusters=2).fit(width_data_withoutTooBig)
        #print "聚簇中心点:", kmeans.cluster_centers_
        #print 'label:', kmeans.labels_ 
        #print '方差:', kmeans.inertia_
        
        label_tmp = kmeans.labels_
        label = []
        j = 0
        k = 0
        for i in range(len(width_data)):        #将label整理,2代表大于一个字的
            if j != len(width_data_TooBig) and k != len(label_tmp):
                if i == width_data_TooBig[j][1]:
                    label.append(2)
                    j = j + 1
                else:
                    label.append(label_tmp[k])
                    k = k + 1
            elif j == len(width_data_TooBig) and k != len(label_tmp):
                label.append(label_tmp[k])
                k = k + 1
            elif j != len(width_data_TooBig) and k == len(label_tmp):
                label.append(2)
                j = j + 1
                
        label0_example = 0
        label1_example = 0
        for i in range(len(width_data)):
            if label[i] == 0:
                label0_example = width_data[i][0]
            elif label[i] == 1:
                label1_example = width_data[i][0]
        if label0_example > label1_example:    #找到正常字符宽度的label(宽度大的,防止切得太碎导致字符宽度错误)
            label_width_normal = 0
        else:
            label_width_normal = 1
        label_width_small = 1 - label_width_normal
            
        cluster_center = []
        cluster_center.append(kmeans.cluster_centers_[0][0])
        cluster_center.append(kmeans.cluster_centers_[1][0])
        for i in range(len(width_data)):
            if label[i] == label_width_normal and width_data[i][0] > cluster_center[label_width_normal] * 4 / 3: 
                label[i] = 2
                temp = (width_data[i][0], i)
                width_data_TooBig.append(temp)        
        max_gap = get_max_gap(cut) 
        for i in range(len(label)):
            if i == max_gap[1]:
                label[i] = 3
        
        width_normal_data = []      #存正常字符宽度
        width_data_TooSmall = []
        for i in range(len(width_data)):
            if label[i] == label_width_normal:
                width_normal_data.append(width_data[i][0])
            elif label[i] != label_width_normal and label[i] != 2 and label[i] != 3:  #切得太碎的
                #box=(cut[i][0],0,cut[i][1],height)
                #region=line_img.crop(box) #此时,region是一个新的图像对象。
                #region_arr = 255 - np.array(region)
                #region = Image.fromarray(region_arr.astype("uint8"))
                #name = "single"+str(i)+".jpg"
                #region.save(name)
                tmp = (width_data[i][0], i)
                width_data_TooSmall.append(tmp)
        width_normal_max = max(width_normal_data)
        width_normal_min = min(width_normal_data)       #得到正常字符宽度的上下限
        
        if len(width_data_TooBig) != 0:   
            for i in range(len(width_data_TooBig)):
                index = width_data_TooBig[i][1]
                mid = (cut[index][0] + cut[index][1]) / 2
                tmp1 = (cut[index][0], int(mid))
                tmp2 = (int(mid)+1, cut[index][1])
                del cut[index]
                cut.insert(index, tmp2)
                cut.insert(index, tmp1)
                del width_data[index]
                tmp1 = (tmp1[1] - tmp1[0], index)
                tmp2 = (tmp2[1] - tmp2[0], index+1)
                width_data.insert(index, tmp2)
                width_data.insert(index, tmp1)
                label[index] = label_width_normal
                label.insert(index, label_width_normal)
                
                
        if len(width_data_TooSmall) != 0:               #除':'以外有小字符,先找'('、')'label = 4                             
            for i in range(len(width_data_TooSmall)):
                index = width_data_TooSmall[i][1]
                border_left = cut[index][0] + 1
                border_right = cut[index][1]
                RoI_data = line_arr[:,border_left:border_right]
                
                #RoI_data = np.where(RoI_data < threshold, 0, 1)
                horz = horizon(RoI_data)
            
                up_down = np.sum(np.abs(RoI_data - RoI_data[::-1]))
                left_right = np.sum(np.abs(RoI_data - RoI_data[:,::-1]))
                vert = vertical(RoI_data)
            
                if up_down <= left_right * 0.6 and np.array(vert).var() < len(vert) * 2:    
                    #print i, up_down, left_right,
                    #print vert, np.array(vert).var()
                    label[index] = 4
        
            index_delete = [] #去掉这些index右边的线
            cut_final = []
            width_untilnow = 0
            for i in range(len(width_data)):
                if label[i] == label_width_small and width_untilnow == 0:
                    index_delete.append(i)
                    cut_left = cut[i][0]
                    width_untilnow = cut[i][1] - cut[i][0]
                    #print cut_left,width_untilnow,i
                elif label[i] != 3 and label[i] != 4 and width_untilnow != 0:
                    width_untilnow = cut[i][1] - cut_left
                    if isnormal_width(width_untilnow, width_normal_min, width_normal_max) == -1: #还不够长
                        index_delete.append(i)
                        #print cut_left,width_untilnow,i
                    elif isnormal_width(width_untilnow, width_normal_min, width_normal_max) == 0: #拼成一个完整的字
                        width_untilnow = 0
                        cut_right = cut[i][1]
                        tmp = (cut_left, cut_right)
                        cut_final.append(tmp)
                        #print 'complete',i
                    elif isnormal_width(width_untilnow, width_normal_min, width_normal_max) == 1:   #一下子拼多了
                        #print 'cut error!!!!',cut_left,width_untilnow,i 
                        width_untilnow = 0
                        cut_right = cut[i-1][1]
                        tmp = (cut_left, cut_right)
                        cut_final.append(tmp)
                        #print 'cut error!!!!',i 
                        index_delete.append(i)
                        cut_left = cut[i][0]
                        width_untilnow = cut[i][1] - cut[i][0]
                        if i == len(width_data):
                            tmp = (cut[i][0], cut[i][1])
                            cut_final.append(tmp)
                            #print i
                else:
                    tmp = (cut[i][0], cut[i][1])
                    cut_final.append(tmp)
            i1 = len(cut_final) - 1
            i2 = len(cut) - 1
            if cut_final[i1][1] != cut[i2][1]:
                tmp = (cut[i2][0], cut[i2][1])
                cut_final.append(tmp)
                    
        else:
            cut_final = cut
                                 
        for x in range(len(cut_final)):
            ax = (cut_final[x][0] - 1, 0, cut_final[x][1] + 1, height)
            temp = line_img.crop(ax)
            temp = image_unit.resize(temp, save_size)
            temp.save('{}/{}.jpg'.format(save_path, x))
        return flag

    这里用了一下sklearn这个机器学习库里面的Kmeans来进行分类。

                   

            (a)直接分割的结果                                                                         (b)用Kmeans分割的结果

    展开全文
  • Java字符分割的三种方法

    万次阅读 2015-07-10 21:19:21
    Java中分解字符
    

    一、StringTokenizer方法

    Java中substring方法可以分解字符串,返回的是原字符串的一个子字符串。如果要讲一个字符串分解为一个一个的单词或者标记,StringTokenizer可以帮你。

    先看个例子:


    public static void main(String[] args) {  

    StringTokenizer st = new StringTokenizer("www.ooobj.com"".b");  

     while(st.hasMoreElements()){  

    System.out.println("Token:" + st.nextToken());  

     }  

     }  

    <span style="font-size:14px;">public static void main(String[] args) {
     StringTokenizer st = new StringTokenizer("www.ooobj.com", ".b");
     while(st.hasMoreElements()){
     System.out.println("Token:" + st.nextToken());
     }
     }
    </span>


    输出:
    Token:www
    Token:ooo
    Token:j
    Token:com

    StringTokenizer有两个常用的方法:

    1.hasMoreElements()。这个方法和hasMoreElements()方法的用法是一样的,只是StringTokenizer为了实现Enumeration接口而实现的方法,从StringTokenizer的声明可以看到:class StringTokenizer implements Enumeration<Object>。

    2.nextElement()。这个方法和nextToken()方法的用法是一样的,返回此 StringTokenizer 的下一个标记。

    StringTokenizer的三个构造方法:

    1.StringTokenizer(String str)。默认以” \t\n\r\f”(前有一个空格,引号不是)为分割符。
    源码:
    public StringTokenizer(String str) {
    this(str, ” \t\n\r\f”, false);
    }

    实例:

    public static void main(String[] args) {  

     StringTokenizer st = new StringTokenizer("www ooobj com");  

     while(st.hasMoreElements()){  

     System.out.println("Token:" + st.nextToken());  

     }  

     }  

    <span style="font-size:14px;">public static void main(String[] args) {
     StringTokenizer st = new StringTokenizer("www ooobj com");
     while(st.hasMoreElements()){
     System.out.println("Token:" + st.nextToken());
     }
     }
    </span>


    输出:
    Token:www
    Token:ooobj
    Token:com

    2.StringTokenizer(String str, String delim)。指定delim为分割符,看第一个例子。

    3.StringTokenizer(String str, String delim, boolean returnDelims)。returnDelims为true的话则delim分割符也被视为标记。

    实例:

      public static void main(String[] args) { 

      StringTokenizer st = new StringTokenizer("www.ooobj.com", ".", true); 

      while(st.hasMoreElements()){ 

      System.out.println("Token:" + st.nextToken()); 

      } 

      }

    输出:
    Token:www
    Token:.
    Token:ooobj
    Token:.
    Token:com


    二、String.split()方法

    在java.lang包中有String.split()方法,返回是一个数组。
     1、“.”和“|”都是转义字符,必须得加"\\";
      如果用“.”作为分隔的话,必须是如下写法:
    String.split("\\."),这样才能正确的分隔开,不能用String.split(".");
        如果用“|”作为分隔的话,必须是如下写法:
    String.split("\\|"),这样才能正确的分隔开,不能用String.split("|");

      2、如果在一个字符串中有多个分隔符,可以用“|”作为连字符,比如:“acount=? and uu =? or n=?”,把三个都分隔出来,可以用
      String.split("and|or");

      3、public String[] split(String regex,int limit)根据匹配给定的正则表达式来拆分此字符串。
      此方法返回的数组包含此字符串的每个子字符串,这些子字符串由另一个匹配给定的表达式的子字符串终止或由字符串结束来终止。数组中
      的子字符串按它们在此字符串中的顺序排列。如果表达式不匹配输入的任何部分,则结果数组只具有一个元素,即此字符串。

      4、public string[] split(string regex)
      这里的参数的名称是 regex ,也就是 regular expression (正则表达式)。这个参数并不是一个简单的分割用的字符,而是一个正则表达式,
    他对一些特殊的字符可能会出现你预想不到的结果,比如测试下面的代码:

    (1) 用竖线 | 分隔字符串,你将得不到预期的结果

    String[] aa="aaa|bbb|ccc".split("|"); 
    //String[] aa = "aaa|bbb|ccc".split("\\|"); 这样才能得到正确的结果 
    for(int i=0; i<aa.length; i++){ 
    System.out.println("--"+aa); 
    }



    (2)用竖 * 分隔字符串运行将抛出java.util.regex.PatternSyntaxException异常,用加号 + 也是如此。

    String[] aa="aaa*bbb*ccc".split("*"); 
    //String[] aa = "aaa|bbb|ccc".split("\\*"); 这样才能得到正确的结果    
    for(int i=0; i<aa.length; i++){ 
    System.out.println("--"+aa); 
    }



    (3)显然,+ * 不是有效的模式匹配规则表达式,用"\\*" "\\+"转义后即可得到正确的结果。 
    (4) "|" 分隔串时虽然能够执行,但是却不是预期的目的,"\\|"转义后即可得到正确的结果。 
    (5)还有如果想在串中使用""字符,则也需要转义.首先要表达"aaaa\bbbb"这个串就应该用"aaaa\\bbbb",如果要分隔就应该这样才能得到正确结果: 
    String[] aa = "aaa\\bbb\\bccc".split(\\\\); 
    (6) 还有就是点号".",也要首先转义才能得到正确的结果。


    第一种方法:

    string s="abcdeabcdeabcde";
    string[] sArray=s.Split('c');
    foreach(string iin sArray)Console.WriteLine(i.ToString());

    输出下面的结果:
     ab
    deab
    deab
    de

    第二种方法:
    我们看到了结果是以一个指定的字符进行的分割。使用另一种构造方法对多个字符进行分割:

    string s="abcdeabcdeabcde";
    string[] sArray1=s.Split(newchar[3]{'c','d','e'});
    foreach(string iin sArray1)Console.WriteLine(i.ToString());

    可以输出下面的结果:
    ab
    ab
    ab

    第三种方法:
    除了以上的这两种方法以外,第三种方法是使用正则表达式。新建一个控制台项目。
    然后先添加 using System.Text.RegularExpressions;

    using System.Text.RegularExpressions
    string content=agcsmallmacsmallgggsmallytx;
    string[] resultString=Regex.Split(content,small,RegexOptions.IgnoreCase)
    foreach(string iin resultString)
         Console.WriteLine(i.ToString());

    输出下面的结果:
    agc
     mac
     ggg
    ytx

    第四种方法:

     string str1="我*****是*****一*****个*****教*****师";
    string[] str2; str1=str1.Replace("*****","*");
    str2=str1.Split(’*‘);foreach(string i in str2)
    Console.WriteLine(i.ToString());



    第五种方法:
    string str1=”我**是*****一*****个*****教*****师“;
    我希望显示的结果为:我是一个教师。 我如果采用上面的第四种方法来做就会产生下面的错误:我 是一个教师。中间有空格输出,所以输出结果并不是希望的结果,这就又回到了正则表达式了,这时可以采用下面的第五种方法:

    string str1=‘我**是*****一*****个*****教*****师“;
    string[] str2=System.Text.RegularExpressions.Regex.Split(str1,@[*]+);
    foreach(string iin str2)
    Console.WriteLine(i.ToString());

    这里通过[*]+ 巧妙的完成了我们的目标。

    三、substring方法

    java字符串分解 substring用法


    单参数形式:
    substring(int beginIndex)
    该子字符串从beginIndex处的字符开始,直到此字符串末尾。


    双参数形式:
    substring(int beginIndex, int endIndex)
    该子字符串从指定的 beginIndex 处开始,直到索引 endIndex – 1 处的字符。注意:其它一些语言第二个参数往往代表长度,JAVA不一样。该子字符串的长度为 endIndex-beginIndex。


    String a = "www.ooobj.com";


    03 System.out.println(a);


    04 String b = a.substring(2);


    05 System.out.println(b);


    06 String c = a.substring(1,10);


    07 System.out.println(c);


    08 String d = a.substring(6, a.length());


     

    09 System.out.println(d);

     

    输出:

    www.ooobj.com
    w.ooobj.com
    ww.ooobj.
    obj.com

    注:beginIndex不能为负数,endIndex不能超出字符串长度,否则会抛出StringIndexOutOfBoundsException异常

    四,Js的substring()

    语法:

    程序代码
    String.substring(start, end)

    说明:
    返回一个从start开始到end(不包含end)的子字符串。

    示例:

    程序代码
    var str="abcdefgh";
    document.write(str.substring(0,1));//return:a
    document.write(str.substring(2,5));//return:cde
    document.write(str.substring(7,8));//return:h

    js的substring()方法与java的比较相似,但js的substring()需要注意一下几点:

    1.start不一定就是第一个参数,end也不一定就是第二个参数,substring(3,1)时,开始位置是1,结束位置是3;
    2.当要返回的子字符串是从开始位置到结束时,end的值必须大于等于字符串的长度,如上边的str.substring(7,8),按照索引从0开始算的话end的最大值为7,但这边却用8,当然,使用大于8的数返回的结果也是一样的.


    展开全文
  • 字符分割算法及代码

    千次阅读 2019-06-21 21:15:59
    由于印刷体版式工整,加之彝语的结构较为简单,遂采取了单字符分割+识别的流程来进行彝语的识别工作。(其实主要还是因为训练样本不够啊,外加“某局”希望能得到单字符的坐标,不然直接用CRNN来做序列识别可能会更...

    之前一段时间做了一个少数民族语言的文字检测与识别的项目,一共有6种语言,其中的彝语的识别相对简单,部分彝语文档图片如下。由于印刷体版式工整,加之彝语的结构较为简单,遂采取了单字符分割+识别(此算法同样可适用于汉字韩语日语等类似结构文字的单字符分割部分)的流程来进行彝语的识别工作。(其实主要还是因为训练样本不够啊,外加甲方希望能得到单字符的坐标,不然直接用CRNN来做序列识别可能会更简单一点,卒。。。)
    在这里插入图片描述

    上图所示为彝语打印文档的一张扫描件示例图。由图可见彝语的结构跟汉字在某些程度上有些相似之处,比如都属于方块字,存在上下结构和左右结构等。由图可发现彝语的识别可以采用单字符分割+识别的方式来进行处理。下面是我对这部分(单字符分割)的处理代码。(此代码经修改后同样可适用于汉字韩语日语等类似结构文字的单字符分割部分)

    import cv2    # 版本为3.3.10,安装4.0及以上版本可能会不兼容
    import os
    import numpy as np
    
    
    def display(img):
        cv2.imshow("1", img)
        cv2.waitKey(0)
    
    
    def get_split_line(img, projection_row):
        split_line_list = []
        flag = False
        start = 0
        end = 0
        for i in range(0, len(projection_row)):
            if flag == False and projection_row[i] > 0:
                flag = True
                start = i
            elif flag and (projection_row[i] == 0 or i == len(projection_row) - 1):
                flag = False
                end = i
                if end - start < 15:  # need specify or rewrite
                    flag = True
                    continue
                else:
                    split_line_list.append((start, end))
        return split_line_list
    
    
    def get_contours(img):
        contour_list = []
        contours = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        for i in range(0, len(contours[1])):
            x, y, w, h = cv2.boundingRect(contours[1][i])
            contour_list.append((x, y, w, h))
            # cv2.rectangle(img_input, (x,y), (x+w, y+h), (0,0,255))
        return contour_list
    
    
    def sort_merge(contour_row):
        contour_row = sorted(contour_row, key=lambda x: x[0])  # sort by x
        # print(contour_row)
        i = 0
        for _ in contour_row:    # 这部分的合并规则用的是刘成林老师paper中的方法
            if i == len(contour_row) - 1 or contour_row[i][0] == -1:
                break
            # print(contour_row[i])
            rectR = contour_row[i + 1]
            rectL = contour_row[i]
            ovlp = rectL[0] + rectL[2] - rectR[0]
            dist = abs((rectR[0] + rectR[2] / 2) - (rectL[0] - rectL[2] / 2))
            w_L = rectL[0] + rectL[2]
            w_R = rectR[0] + rectR[2]
            span = (w_R if w_R > w_L else w_L) - rectL[0]
            nmovlp = (ovlp / rectL[2] + ovlp / rectR[2]) / 2 - dist / span / 8
            if nmovlp > 0:
                x = rectL[0]
                y = (rectL[1] if rectL[1] < rectR[1] else rectR[1])
                w_L = rectL[0] + rectL[2]
                w_R = rectR[0] + rectR[2]
                w = (w_R if w_R > w_L else w_L) - x
                h_L = rectL[1] + rectL[3]
                h_R = rectR[1] + rectR[3]
                h = (h_R if h_R > h_L else h_L) - y
                contour_row[i] = (x, y, w, h)
                contour_row.pop(i + 1)  # after pop , index at i
                contour_row.append((-1, -1, -1, -1))  # add to fix bug(the better way is use iterator)
                i -= 1
            i += 1
        # print(contour_row)
        return contour_row
    
    
    def combine_verticalLine(contour_row):
        i = 0
        pop_num = 0
        for _ in contour_row:
            rect = contour_row[i]
            if rect[0] == -1:
                break
    
            if rect[2] == 0:
                i += 1
                continue
    
    
            if rect[3] * 1.0 / rect[2] > 4:
                if i != 0 and i != len(contour_row) - 1:
                    rect_left = contour_row[i - 1]
                    rect_right = contour_row[i + 1]
                    left_dis = rect[0] - rect_left[0] - rect_left[2]
                    right_dis = rect_right[0] - rect[0] - rect[2]
                    # if left_dis <= right_dis:
                    if left_dis <= right_dis and rect_left[2] < rect_right[2]:
                        x = rect_left[0]
                        y = (rect_left[1] if rect_left[1] < rect[1] else rect[1])
                        w = rect[0] + rect[2] - rect_left[0]
                        h_1 = rect_left[1] + rect_left[3]
                        h_2 = rect[1] + rect[3]
                        h_ = (h_1 if h_1 > h_2 else h_2)
                        h = h_ - y
                        contour_row[i - 1] = (x, y, w, h)
                        contour_row.pop(i)
                        contour_row.append((-1, -1, -1, -1))
                        pop_num += 1
                        # don't need recursive merge, causing it's left and right merge
                    else:
                        x = rect[0]
                        y = (rect[1] if rect[1] < rect_right[1] else rect_right[1])
                        w = rect_right[0] + rect_right[2] - rect[0]
                        h_1 = rect_right[1] + rect_right[3]
                        h_2 = rect[1] + rect[3]
                        h_ = (h_1 if h_1 > h_2 else h_2)
                        h = h_ - y
                        contour_row[i] = (x, y, w, h)
                        contour_row.pop(i + 1)
                        contour_row.append((-1, -1, -1, -1))
                        pop_num += 1
            i += 1
        for i in range(0, pop_num):
            contour_row.pop()
        return contour_row
    
    
    def split_oversizeWidth(contour_row):
        i = 0
        for _ in contour_row:
            rect = contour_row[i]
            if rect[2] * 1.0 / rect[3] > 1.2:  # height/width>1.2 -> split
                x_new = int(rect[0] + rect[2] / 2 + 1)
                y_new = rect[1]
                w_new = rect[0] + rect[2] - x_new
                h_new = rect[3]
                contour_row[i] = (rect[0], rect[1], int(rect[2] / 2), rect[3])
                contour_row.insert(i + 1, (x_new, y_new, w_new, h_new))
            i += 1
        return contour_row
    
    
    def image_preprocess(img_input):
        gray_img = cv2.cvtColor(img_input, cv2.COLOR_BGR2GRAY)
        gray_img = cv2.GaussianBlur(gray_img, (3, 3), 3)
        _, img = cv2.threshold(gray_img, 0, 255, cv2.THRESH_OTSU)  # 将一幅灰度图二值化 input-one channel
    
        _, img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV)
        kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
        img = cv2.erode(img, kernel)
        # height,width=img.shape[:2]
        # img=cv2.resize(img,(int(width/2),int(height/2)),interpolation=cv2.INTER_CUBIC)
        # display(img)
        return img
    
    
    def get_segmentation_result(img):  # has been eroded
        projection_row = cv2.reduce(img, 1, cv2.REDUCE_SUM, dtype=cv2.CV_32S)  # projection
        split_line_list = get_split_line(img, projection_row)  # split image as row
        segmentation_result = []
        for i in split_line_list:
            img_row = img[i[0]:i[1], :]
            contour_row = get_contours(img_row)
            contour_row = sort_merge(contour_row)
            contour_row = split_oversizeWidth(contour_row)
            contour_row = combine_verticalLine(contour_row)
            segmentation_result.append(contour_row)
            for (x, y, w, h) in contour_row:  # draw
                y += i[0]
                cv2.rectangle(img_input, (x, y), (x + w, y + h), (0, 0, 255))
        # cv2.imwrite("./test1/n003.jpg",img_input)
        return segmentation_result
    
    
    pic_path = './img003.jpg'
    
    img_input = cv2.imread(pic_path, 1)  # (2975, 1787, 3)   但是图片查看器显示的是  1787 * 2975
    img = image_preprocess(img_input)  # erode
    segmentation_result = get_segmentation_result(img)  # store segmentation result : [(x,y,w,h),(),...]
    
    # cv2.imwrite("./save.jpg", img_input)
    display(img_input)
    

    代码运行结果如下:
    在这里插入图片描述
    此代码经过一定的修改可适用于很多的场景,大家有需要可以尝试一下。

    下面大致说一下代码的流程(关注get_segmentation_result部分),字符分割的代码部分主要是采用“投影+连通域”的方式来实现。首先对图像进行二值化与腐蚀(断开印刷过程中可能存在的粘连)的操作,之后对预处理后的图片进行水平投影,得到图片中所有的文本行。然后分别对图片中的每一个文本行进行一系列操作,得到其连通域,然后再对连通域进行合并(合并规则是刘成林老师的一篇paper中的方法,代码中已经注释,具体操作步骤见下图),针对合并错的部分进行切分操作(针对过宽的部分),最后再对没有合并的部分高宽比很大的竖形字符进行单独的合并。进行完上述操作之后,就可以得到不错的分割效果。(具体流程和操作步骤仅供参考)
    在这里插入图片描述
    有问题欢迎多交流,共同进步~

    展开全文
  • 【1】单个符号作为分隔符   String address="上海|上海市|闵行区|吴中路";  String[] splitAddress=address.split("\\|"); //如果以竖线为分隔符,则split的时候需要加上两个斜杠【\\】...
  • 字符串中的截取,分割,转换方法

    万次阅读 2018-07-09 23:58:45
    /*字符串的截取方法(根据一个大字符串,截取得到小字符串,其中一部分)public String substring(int beginIndex):截取字符串,从指定的索引位置一直到字符串末尾。public String substring(int beginIndex, ...
  • 字符串以.作为split()的分割

    万次阅读 2018-07-17 14:08:31
    当以.(点号)作为String.split()的分割符时,表达式不应该写成String.split("."),因为点号在正则表达式中由特殊含义,所以此处应该用转义字符String.split("\\.")。...
  • 分割字符串,逗号分隔

    千次阅读 2018-09-01 09:19:49
    字符串切割的使用频率还是挺高的,string本身没有提供切割的方法,但可以使用stl提供的封装进行实现或者通过c函数strtok()函数实现。 1、通过stl实现 涉及到string类的两个函数find和substr: 1、find函数 原型...
  • 字符串的切割

    千次阅读 2019-07-09 08:43:57
    开发工具与关键技术:...一、public String[] split(String regex):将regex作为标记进行切刀,返回切分之后的若干字符串(字符串数组)(根据给定正则表达式的匹配拆分此字符串。) 例如: 1、声明一个String字符...
  • 字符分割

    2019-06-03 21:30:26
    用STL进行字符串的分割 涉及到string类的两个函数find和substr: 1、find函数 原型:size_t find ( const string& str, size_t pos = 0 ) const; 功能:查找子字符串第一次出现的位置。 参数说明:str为子字符...
  • String字符分割

    千次阅读 2019-03-02 18:41:33
    String类型数据进行字符分割: 1:按指定字符比如“@”分割: 例如:String str=“a@abf@shu@hfdj”; String [ ] s=str.split(’@’); 注意:指定用“.”和"|"分割时,要写成str.split(’\.’)或者str....
  • 在日常交互过程中经过常会有字符分割的方法,分割字符串的时候通常会想到String类的split方法,很少会用到StringTokenizer类。 关于split方法分割字符串再次不做赘述,值得注意的是,有些字符串是用“,”分割,...
  • Java使用String对象的split()方法分割字符

    万次阅读 多人点赞 2018-01-14 20:18:52
    Java中,按某个字符分割字符串使用的是String对象的split()方法,返回的是分割之后的String数组,值得注意的是分割符。当分割符是 . 或者是 | 时,必须使用 \\ 进行转义。 没有加转义符按 . 分割字符串,返回值是一...
  • 函数原型:char * strtok (char *str, const char * delimiters); ...参数str指向欲分割字符串,参数delimiters则为分割字符串中包含的所有字符。当strtok()在参数s的字符串中发现参数delimi
  • shell 如何来分割字符串让结果为一个字符串串数组
  • Date: 2018.5.30 https://www.cnblogs.com/2bjiujiu/p/7254085.html
  • JAVA 一个或多个空格分割字符

    万次阅读 多人点赞 2016-10-08 23:01:45
    一、待分割字符串待分割字符串为如下:String str = "a b c d e f g"其中,字符串中的的空白分别为:单个空格,多个空格,tab制表符。二、使用一个或多个空格分割字符串正确代码如下:String []
  • js split分割字符串成数组

    万次阅读 2017-03-22 16:08:43
    str="2,2,3,5,6,6"; //这是一字符串 var strs= new Array(); //定义一数组 ... //字符分割 for (i=0;i;i++ ) { document.write(strs[i]+""); //分割后的字符输出 } 输出结果就是 2 2 3 5 6 6
  • Excel分割字符

    万次阅读 2016-12-13 13:49:31
    在数据处理中我们经常会遇到分割字符的情况,比如读取csv文件。Excel提供了可视化的字符分割方法。 1.按分隔符,分割字符串 2.选择用“逗号”分割 3.结果如图
  • JS之字符分割方法split

    万次阅读 2017-06-06 16:47:17
    JavaScript
1 2 3 4 5 ... 20
收藏数 388,512
精华内容 155,404
关键字:

字符分割