Exemplo n.º 1
0
//новая версия грамматического анализатора.
//текст реконструируется на основе вероятностного анализа результатов распознавания
//с применением взаимной корреляции частей разных букв. Слоги и слова реконструируются
//на основе вероятносного анализа корпуса тибетских текстов и правил построения тибетского шрифта.
void GLogicProcessor::letterAssociation(vector<stringOCR>*strArray,
                                      vector<OCRMatch>&matchLine,
                                      vector<OCRMatch>&dLine,
                                      GBitmap* lineImg32,
                                      string &mainString,
                                      int sizeLine,
                                      int lineIndex,
                                      int OCRMode){

    int print=0;
    TIME_START
    y0Base=strArray[0][lineIndex].LimY0;
    y1Base=strArray[0][lineIndex].LimY1;
    DR("@@@y0Base"<<y0Base<<" y1Base="<<y1Base<<" s="<<matchLine.size())
    
    GBitmap *letterAImg=GBitmap::create(lineImg32->columns(),lineImg32->rows(),BITMAP_32);
    GBitmap *letterBImg=GBitmap::create(lineImg32->columns(),lineImg32->rows(),BITMAP_32);

    
    
#ifdef MAIN_MODE
    
    //for(int i=0;i<matchLine.size();i++)if(matchLine[i].letterIndex==15650){cout<<"@@@@@";exit(0);}
    
    //drawGrapeLine(matchLine); exit(0);
    
    
    sort(matchLine.begin(),matchLine.end(),sortMatchX0);
    
    //cout<<"strArray[0].size()="<<strArray[0].size()<<" matchLine.size()="<<matchLine.size()<<endl;
    
    if(!matchLine.size()||!strArray[0].size())return;   //
    
    int count=0;
    //int maxH=45;
    //int maxCor=97;
    for(int i=0;i<matchLine.size();i++){
        matchLine[i].setSize();
        count=0;
        matchLine[i].correlationNew=0;
        /*
        if((matchLine[i].OCRIndex=='A'&&
           abs(matchLine[i].y0-y0Base)>3&&
           matchLine[i].correlation>maxCor&&
           matchLine[i].letterH>maxH)||
           (matchLine[i].OCRIndex=='A'&&
            matchLine[i].y0<y0Base-3&&
            matchLine[i].correlation>98)
           ){
            maxH=matchLine[i].letterH;
            maxCor=matchLine[i].correlation;
            y0Base=matchLine[i].y0; y1Base=y0Base+32;
        }
        */
        if(!matchLine[i].correlation)continue;
        matchLine[i].status=0;
    }
    //drawGrapeLine(matchLine); exit(0);
    
    compressMatch(matchLine);
    
    //drawGrapeLine(matchLine); exit(0);
    

    //на этом этапе в matchLine записано около 50 результатов на одну букву текста
    //заменяем одинаковые буквы на букву с наибольшей корреляцией и наибольшей общей площадью совпадающей с изображением на странице.
    //также для каждой гипотезы распознанной буквы проверяем перекрытие с соседними буквами
    //оставляем только те буквы, которые лучше описывают соответствующие площади буквы области изображения.
    letterNeighborsNew(matchLine,lineImg32,letterAImg,letterBImg);
    
    
    //drawGrapeLine(matchLine); exit(0);
    
#ifdef STACK_MODE    
    //saveMatch(matchLine,"/2_2.match");
#endif
    

    for(int i=0;i<matchLine.size();i++){
        if(matchLine[i].correlation){
          matchLine[i].status=0;
          if(matchLine[i].OCRIndex!=3&&matchLine[i].correlationNew)matchLine[i].correlation=matchLine[i].correlationNew;
          dLine.push_back(matchLine[i]);
        }
    }
    
    DR("done match processing line.size()="<<dLine.size())
    sort(dLine.begin(),dLine.end(),sortMatchX0);
    DR("@@@@@ SAVE MATCH")
#ifdef STACK_MODE    
    //saveMatch(dLine,"/2.match");
#endif    
#endif
    
#ifdef STACK_MODE    
    //readMatch(dLine,"/2.match");
#endif    
    
    //компрессия. Все одинаковые буквы в пределах габарита буквы
    //заменяются на одну букву с макcмимальной корреляцией
    compressMatch(dLine);

    //drawGrapeLine(dLine); exit(0);

    collectStackLetter(strArray,dLine, matchLine,lineImg32,letterAImg,letterBImg,lineIndex);
    //cout<<"COLLECT"; TIME_PRINT_
     //exit(0);
    //drawGrapeLine(dLine);exit(0);

    compressMatch(dLine);
    //drawGrapeLine(dLine);exit(0);

    //анализ готовых стеков.
    //проверяем есть ли над или под одиночной буквой коренные буквы или огласовки с высокой корреляцией.
    //если есть, то букву считаем частью стека и убираем как строительный блок OpenType.
    testStackLetter(dLine,lineImg32,letterAImg,letterBImg);
    
    //drawGrapeLine(dLine); exit(0);
    
    letterAImg->destroy();
    letterBImg->destroy();
    
#ifdef STACK_MODE    
    //saveMatch(line,"/2_1.match");
#endif    
    
    if(print){TIME_PRINT_}
    return;
 }
Exemplo n.º 2
0
void GLogicProcessor::renderDictSearch(map<vector<short>,int>&searchResult,
                                       vector<OCRMatch>&dLine,
                                       vector<OCRMatch>&originalMatch,
                                       vector<OCRMatch>&pageText){
    
    int print=0;
    DR(" searchResult.size()="<<searchResult.size()<<" dLine()="<<dLine.size())
    vector<OCRMatch>wordLine;
    
    //TIME_START
    
    //в dLine[] записаны пары букв из которых словарь собирал фразы
    //для окончательной сборки фразы нужны найденные с словаре фразы, составленные из оригинальных пар букв
    //также нужны сами пары букв для частей фразы на которые не найдены ответы словаря 
    //каждый OCRMatch содержит два массива, в которые записана информация о парах букв, составляющих фразу.
    // .line[] содержит индекс пар букв и возвращается заполненным в searchResult как результат работы словаря
    // .letter[] содержит копию пары букв по индексу line[] из исходного массива dLine[]
    for(int i=0;i<originalMatch.size();i++){
        originalMatch[i].setSize();
    }
    map<vector<short>,int>::iterator it;
    for (it = searchResult.begin(); it != searchResult.end(); ++it) {
        OCRMatch word;
        int in=abs(it->first[0]);   //знаком значения записано есть ли по мнению словаря разделитель слогов в этой паре
        word.x0=dLine[in].x0;
        word.y0=dLine[in].y0;
        word.xL0C=dLine[in].letter[0].xCenter;
        int d; int sizeStr=0;
        while(sizeStr<128){    
            d=it->first[sizeStr];  DR(d<<" ")
            if(d==32767)break;  //32767 маркирует конец строки
            word.line.push_back(d);
            sizeStr++;
        }

        d=abs(word.line[word.line.size()-1]);
        word.x1=dLine[d].x1;
        word.y1=dLine[d].y1;
        word.xL1C=dLine[d].letter[1].xCenter;

        word.correlation=0;
        int n;
        for(int i=0;i<sizeStr;i++){
            //DR(searchResult[i].line[j]<<" c="<<line[searchResult[i].line[j]].correlation;
            //DR(" searchResult["<<i<<"].line.size()="<<searchResult[i].line.size()<<" ind="<<searchResult[i].line[j])
            n=abs(it->first[i]); 
            word.wName+=dLine[n].wName[0];
            word.correlation+=dLine[n].correlation;
        }
        word.wName+=dLine[n].wName[1];
        word.correlation=word.correlation/sizeStr+(float)(sizeStr*100)/50+(float)(it->second)/5000;   //учитываем длину и вероятность фразы
        //word.correlation+=it->second;   //прибавляем к кореляции количество ответов словаря
        //word.correlation=word.line.size();
        //if(word.correlation<70)continue;
        word.name=Unicode_to_UTF(word.wName);  DR("Yagpo= "<<word.name<<" "<<endl)
        word.name=YagpoToUni(word.name);       DR("xL0C="<<word.xL0C<<"xL1C="<<word.xL1C<<" n="<<word.name<<endl);
        DR(word.name<<"/"<<"c="<<word.correlation<<" x0="<<word.x0<<" x1="<<word.x1<<" y0="<<word.y0<<" y1="<<word.y1<<endl)
        wordLine.push_back(word);
    }
    //drawGrapeLine(wordLine); exit(0);        //результаты словаря с записаными в разделители букв знаками препинания и расставленными слогами
    //drawGrapeLine(originalMatch); exit(0);   //результаты распознавания
    //drawGrapeLine(dLine); exit(0);           //пары букв с записанными в разделители букв знаками препинания
    
    //print=1;
    //добавляем распознанные пары букв 
    for(int i=0;i<dLine.size();i++){
        if(!dLine[i].correlation)continue; //значение уже записано
        OCRMatch word=dLine[i];
        word.name=Unicode_to_UTF(word.wName);  //DR("Yagpo= "<<word.name<<" ")
        word.name=YagpoToUni(word.name);
        word.line=dLine[i].line;
        word.line.push_back(i);
        wordLine.push_back(word);
        
    }
    

    
    for(int i=0;i<wordLine.size();i++){
        wordLine[i].status=0;
        wordLine[i].allMatchCount=1;
        wordLine[i].setSize();
        //DR(" wordLine[i]="<<wordLine[i].name<<" w="<<wordLine[i].letterW)
        
    }
    
    sort(wordLine.begin(),wordLine.end(),sortMatchX0);
    compressMatch(wordLine);
    
    //drawGrapeLine(wordLine); exit(0);
    
    //int count=(int)wordLine.size();
    //int step=0;
    print=0;


    //проверяем ответы словаря на здравый смысл. Пары букв из которых составлен ответ словаря не должны отменять
    //уверенно распознанные буквы
    //также убираем пустые значения
    vector<OCRMatch>wLine;
    for(int i=0;i<wordLine.size();i++){
        if(!wordLine[i].correlation)continue;
        wordLine[i].status=0;
        DR("wordLine["<<i<<"].name="<<wordLine[i].name<<endl);
        if(wordLine[i].line.size()>1){
            //для полученных фраз удобнее хранить исходные пары букв внутри фразы
            for(int j=0;j<wordLine[i].line.size();j++){
                DR(" ind="<<wordLine[i].line[j]<<" size="<<wordLine[i].line.size())
                DR(" n="<<dLine[abs(wordLine[i].line[j])].name<<" d="<<dLine[abs(wordLine[i].line[j])].letter[0].delimeter<<endl)
                wordLine[i].letter.push_back(dLine[abs(wordLine[i].line[j])].letter[0]);
                //wordLine[i].letter.push_back(dLine[abs(wordLine[i].line[j])].letter[1]);
                if(wordLine[i].line[j]<0){   //если в паре по мнению словаря есть разделитель слога (минус маркирует такие пары) /@@@
                    wordLine[i].letter[wordLine[i].letter.size()-1].delimeter=dLine[abs(wordLine[i].line[j])].letter[0].delimeter;
                    if(wordLine[i].letter[wordLine[i].letter.size()-1].delimeter=="")wordLine[i].letter[wordLine[i].letter.size()-1].delimeter="་";
                }
            }
            wordLine[i].letter.push_back(dLine[abs(wordLine[i].line[wordLine[i].line.size()-1])].letter[1]);
        }
        //if(wordLine[i].letter.size()==1){  //нормализуем одиночные пары букв
        //    wordLine[i].letter[0].delimeter=wordLine[i].delimeter;
       // }
        wLine.push_back(wordLine[i]);
    }
    //drawGrapeLine(wLine); exit(0);
    //полученные в результате подготовки в  renderDictSearch части фразы собираем в целые фразы
    //на этом этапе фразы собираются вместе ограничителями слогов и знаками препинания и примечаниями внутри фразы.
    sentenceConstructur(wLine);
    
    //drawGrapeLine(wLine); exit(0);

    //расставляем ограничители слогов (точки)
    print=0;
    string str;
    wstring delimeter;
    for(int n=0;n<originalMatch.size();n++){
        originalMatch[n].setSize();
    }
    print=0;
    for(int i=0;i<wLine.size();i++){
        if(!wLine[i].correlation)continue;
        DR(wLine[i].name<<endl)
        wLine[i].wName=L"";
        for(int n=0;n<wLine[i].letter.size();n++){
            str=wLine[i].letter[n].delimeter;  //cout<<"d="<<str;
            str=UnicodeToYagpo(str);
            delimeter=UTF_to_Unicode(str);
            wLine[i].wName+=wLine[i].letter[n].wName[0]+delimeter;
            DR(" n="<<wLine[i].letter[n].name<<"d="<<str<<"/"<<endl)
        }
        wLine[i].wName+=wLine[i].letter[wLine[i].letter.size()-1].wName[1];
        wLine[i].name=Unicode_to_UTF(wLine[i].wName);
        wLine[i].name=YagpoToUni(wLine[i].name);
        DR(" n="<<wLine[i].name<<endl)
        wLine[i].correlation+=3;  //создаем приоритет над парами без расставленных ограничителей слогов
        //добавляем результат к массиву исходных букв (результат распознавания включая все распознанные буквы и символы)
        //это позволит разобрать части фразы, не закрытые словарными ответами
        //x0=wLine[i].x0; x1=wLine[i].x1;
        //for(int n=0;n<dLine.size();n++){
        //    if(dLine[n].x0>=x0&&dLine[n].x1<=x1)dLine[n].correlation=0;
        //}
        //wLine[i].correlation=100;
        dLine.push_back(wLine[i]);
        //DR(wLine[i].name)
    }
    
    //добавляем все исходные графические элементы. Это нужно для распознования отдельно стоящих букв и знаков препинания
    for(int i=0;i<originalMatch.size();i++)dLine.push_back(originalMatch[i]);
    for(int i=0;i<dLine.size();i++)dLine[i].setSize();
    sort(dLine.begin(),dLine.end(),sortMatchXCenter);
    
    //drawGrapeLine(dLine); exit(0);
    
    
    print=0;
    //убираем фразы внутри стыкованной фразы
    int limit;
    for(int n=0;n<dLine.size();n++){
        if(!dLine[n].correlation)continue;
        if(dLine[n].y0>y1Base)dLine[n].correlation=0;
        
        //print=0;if(n==13)print=1; if(!print)continue;
        DR("@@@@"<<n<<" Collect n="<<dLine[n].name<<" d="<<dLine[n].delimeter<<endl)
        
        for(int m=0;m<dLine.size();m++){
          if(!dLine[m].correlation)continue;
          //print=0;if(m==16)print=1;
          if(m==n)continue;
          limit=12; 
          
          if(dLine[n].OCRIndex!='N'&&dLine[m].OCRIndex=='N')limit=0;  
          if(dLine[n].OCRIndex!='Z'&&dLine[m].OCRIndex=='Z')limit=0;
          if(dLine[n].OCRIndex=='N'&&dLine[m].OCRIndex=='N')limit=0;
          if(dLine[n].OCRIndex=='Z'&&dLine[m].OCRIndex=='Z')limit=4;
          if(dLine[n].OCRIndex=='Z'&&dLine[m].OCRIndex!='Z')limit=0;
          if(dLine[n].OCRIndex=='S'&&dLine[m].OCRIndex=='S')limit=0;
          
          if(dLine[m].xCenter>dLine[n].x0-limit&&dLine[m].xCenter<dLine[n].x1+limit){
          
              DR("n"<<n<<"="<<dLine[n].name<<" d="<<dLine[n].delimeter<<" c="<<dLine[n].correlation<<" m"<<m<<"="<<dLine[m].name
                 <<" c="<<dLine[m].correlation<<" xmC="<<dLine[m].xCenter<<" xnC="<<dLine[n].xCenter<<" xnX0="<<dLine[n].x0<<" xnX1="<<dLine[n].x1<<" wM="<<dLine[m].letterW<<" wN="<<dLine[n].letterW<<endl);
              
                  if(dLine[n].correlation>dLine[m].correlation){
                      if(dLine[n].letterW>dLine[m].letterW-limit||(dLine[n].letterW/dLine[m].letterW)>1.3){ DR(100)
                          DR("REMOVE M "<<m<<" cM="<<dLine[m].correlation<<" wM="<<dLine[m].letterW<<" cN="<<dLine[n].correlation<<" wN="<<dLine[n].letterW<<endl)
                          dLine[m].correlation=0;
                      }else{ DR(200)
                          if(dLine[n].correlation-dLine[m].correlation>5){   //предпочтение отдаем более широким буквам
                              dLine[m].correlation=0;
                              DR("REMOVE M1 "<<m<<" cN="<<dLine[n].correlation<<endl)
                          }else{
                              DR("REMOVE N "<<m<<" cN="<<dLine[n].correlation<<endl)
                              dLine[n].correlation=0;
                              break;
                          }    
                      }    
                  }else{
                      if(dLine[m].letterW>dLine[n].letterW-limit||(dLine[n].letterW/dLine[m].letterW)<1.3){
Exemplo n.º 3
0
//новая версия грамматического анализатора.
//текст реконструируется на основе вероятностного анализа результатов распознавания
//с применением взаимной корреляции частей разных букв. Слоги и слова реконструируются
//на основе вероятносного анализа корпуса тибетских текстов и правил построения шрифта.
void GLogicProcessor::classification(vector<stringOCR>&strArray,
                                      vector<OCRMatch>&matchLine,
                                      GBitmap* lineImg32,
                                      string &mainString,
                                      int sizeLine,
                                      int lineIndex){

    int print=0;
    vector<OCRMatch>dLine;
    TIME_START
    y0Base=strArray[lineIndex].LimY0;
    y1Base=strArray[lineIndex].LimY1;
    DR("@@@y0Base"<<y0Base<<" y1Base="<<y1Base<<" s="<<matchLine.size())
    
    GBitmap *letterAImg=GBitmap::create(lineImg32->columns(),lineImg32->rows(),BITMAP_32);
    GBitmap *letterBImg=GBitmap::create(lineImg32->columns(),lineImg32->rows(),BITMAP_32);

    
    
#ifdef MAIN_MODE
    
    //for(int i=0;i<matchLine.size();i++)if(matchLine[i].letterIndex==15650){cout<<"@@@@@";exit(0);}
    
    //drawGrapeLine(matchLine); exit(0);
    
    
    sort(matchLine.begin(),matchLine.end(),sortMatchX0);
    
    //cout<<"strArray.size()="<<strArray[0].size()<<" matchLine.size()="<<matchLine.size()<<endl;
    
    if(!matchLine.size()||!strArray.size())return;   //
    
    for(int i=0;i<matchLine.size();i++){
        matchLine[i].correlationNew=0;
        if(!matchLine[i].correlation)continue;
        matchLine[i].status=0;
    }
    //drawGrapeLine(matchLine); exit(0);

    compressMatch(matchLine);
    //drawGrapeLine(matchLine); exit(0);


    //на этом этапе в matchLine записано около 50 результатов на одну букву текста
    //заменяем одинаковые буквы на букву с наибольшей корреляцией и наибольшей общей площадью совпадающей с изображением на странице.
    //также для каждой гипотезы распознанной буквы проверяем перекрытие с соседними буквами
    //оставляем только те буквы, которые лучше описывают соответствующие площади буквы области изображения.
    letterNeighborsNew(matchLine,lineImg32,letterAImg,letterBImg);

    //drawGrapeLine(matchLine); exit(0);
    
    
#ifdef STACK_MODE    
    //saveMatch(matchLine,"/2_2.match");
#endif
    

    for(int i=0;i<matchLine.size();i++){
        if(matchLine[i].correlation){
          matchLine[i].status=0;
          if(matchLine[i].OCRIndex!=3&&matchLine[i].correlationNew)matchLine[i].correlation=matchLine[i].correlationNew;
          dLine.push_back(matchLine[i]);
        }
    }
    
    DR("done match processing line.size()="<<dLine.size())
    sort(dLine.begin(),dLine.end(),sortMatchX0);
    DR("@@@@@ SAVE MATCH")
#ifdef STACK_MODE    
    //saveMatch(dLine,"/2.match");
#endif    
#endif
    
#ifdef STACK_MODE    
    //readMatch(dLine,"/2.match");
#endif    
    
    //компрессия. Все одинаковые буквы в пределах габарита буквы
    //заменяются на одну букву с макcмимальной корреляцией
    compressMatch(dLine);

    //drawGrapeLine(dLine); exit(0);

    collectStackLetter(strArray,dLine, matchLine,lineImg32,letterAImg,letterBImg,lineIndex);
    //cout<<"COLLECT"; TIME_PRINT_
     //exit(0);
    //drawGrapeLine(dLine);exit(0);

    compressMatch(dLine);
    //drawGrapeLine(dLine);exit(0);
    //анализ готовых стеков.
    //проверяем есть ли над или под одиночной буквой коренные буквы или огласовки с высокой корреляцией.
    //если есть, то букву считаем частью стека и убираем как строительный блок OpenType.
    //testStackLetter(dLine,lineImg32,letterAImg,letterBImg);
    
    //drawGrapeLine(dLine); exit(0);
    
    letterAImg->destroy();
    letterBImg->destroy();
    
    string strW;
    vector<uint>letterX;
    vector<OCRMatch>line;
    vector<OCRMatch>resultLine;
    map<vector<int>,ulong>searchResult;
    
    buildSearchString(dLine,line,letterX,strW);
    cout<<strW<<endl<<endl;
    //drawGrapeLine(line); exit(0);
    textCorpusGMap->getOCRStackKey(strW,letterX,searchResult, ANY_MATCH);
    //inputData.log<<" 2"<<endl;inputData.log.flush();
    for (int i=0;i<line.size();i++){
        if(!line[i].correlation)continue;                        //cout<<line[i].name;
        line[i].name=Unicode_to_UTF(line[i].wName);              //cout<<" -- "<<line[i].name;
        line[i].name=YagpoToUni(line[i].name);   //cout<<" -- "<<line[i].name<<endl;
        resultLine.push_back(line[i]);
    }
    //logicProcessor->drawGrapeLine(line); //exit(0);
    //inputData.log<<" 3"<<endl;inputData.log.flush();
    //renderDictSearch(searchResult,line,resultLine,matchLine);   //mainString+="<br>"+lineString+"original<br>";
    if(print){ cout<<"RENDER "; TIME_PRINT_ }
    strArray[lineIndex].line=dLine;   //сохраняем для вывода в HTML
    //logicProcessor->drawGrapeLine(dLine); //exit(0);
    //inputData.log<<" 4"<<endl;inputData.log.flush();

}
Exemplo n.º 4
0
//новая версия грамматического анализатора.
//текст реконструируется на основе вероятностного анализа результатов распознавания
//с применением взаимной корреляции частей разных букв. Слоги и слова реконструируются
//на основе вероятносного анализа корпуса тибетских текстов и правил построения тибетского шрифта.
void GLogicProcessor::letterAssociation(vector<stringOCR>&strArray,
                                      vector<OCRMatch>&matchLine,
                                      vector<OCRMatch>&dLine,
                                      GBitmap* lineImg32,
                                      GBitmap* letterAImg,
                                      GBitmap* letterBImg,
                                      string &mainString,
                                      int sizeLine,
                                      int lineIndex){

    int print=0;
    int OCRMode=inputData.OCRMode;
    TIME_START
    y0Base=strArray[lineIndex].LimY0;
    y1Base=strArray[lineIndex].LimY1;
    DR("@@@y0Base"<<y0Base<<" y1Base="<<y1Base<<" s="<<matchLine.size())
    
    //for(int i=0;i<matchLine.size();i++)if(matchLine[i].letterIndex==15650){cout<<"@@@@@";exit(0);}
    
    //drawGrapeLine(matchLine); exit(0);
    if(!matchLine.size()||!strArray.size())return;   //
 
    //для каждой буквы определяем количесво точек фокальных линий текста, совпадающих с областью ON всех масок буквы.
    //таким образом определем настолько область ON этой буквы совпадает с текстом.
    OCRBox s;
    for (int i=0;i<matchLine.size();i++){
        if(!matchLine[i].correlation)continue;
        letterAImg->fillColumns32V(0, &matchLine[i].s);  //стираем букву
        matchLine[i].drawPict32(letterAImg,0,0,XOR_MODE);
        matchLine[i].pCount=lineImg32->img32UnionLine(letterAImg, &matchLine[i].s);
        //if(i==518)cout<<i<<" "<< matchLine[i].name<<" pCount="<<matchLine[i].pCount<<endl;
    }
    
    compressMatch(matchLine);
    //drawGrapeLine(matchLine); exit(0);
    
    
    letterConstruction(matchLine,OCRMode);
    
    //drawGrapeLine(matchLine); exit(0);

//#ifndef OCR_woodblock
    
    //на этом этапе в matchLine записано около 50 результатов на одну букву текста
    //заменяем одинаковые буквы на букву с наибольшей корреляцией и наибольшей общей площадью совпадающей с изображением на странице.
    //также для каждой гипотезы распознанной буквы проверяем перекрытие с соседними буквами
    //оставляем только те буквы, которые лучше описывают соответствующие площади буквы области изображения.
//    letterNeighborsNew(matchLine,lineImg32,letterAImg,letterBImg);
//#else
    letterNeighborsNew(matchLine,lineImg32,letterAImg,letterBImg);
//#endif
    
    //drawGrapeLine(matchLine); exit(0);

    for(int i=0;i<matchLine.size();i++){
        if(matchLine[i].correlation){
          matchLine[i].status=0;
          dLine.push_back(matchLine[i]);
        }
    }

    //компрессия. Все одинаковые буквы в пределах габарита буквы
    //заменяются на одну букву с макcмимальной корреляцией
    compressMatch(dLine);
    
    for(int i=0;i<dLine.size();i++){
        if(!dLine[i].correlation||!dLine[i].name.size())continue;
        wstring w;  w=UTF_to_Unicode(dLine[i].name);
        //переводим все буквы в верхний регистр
        w[0]=UniBigLetters[w[0]];
        dLine[i].uni=w[0];
    }

    
    //drawGrapeLine(dLine); exit(0);
    
    if(print){TIME_PRINT_ DR("STACK")};

    
    
    //drawGrapeLine(dLine); exit(0);
    
    if(OCRMode==1){
        collectStackLetter(strArray,dLine, matchLine,lineImg32,letterAImg,letterBImg,lineIndex);

        //cout<<"COLLECT"; TIME_PRINT_
        //exit(0);
        //drawGrapeLine(matchLine);exit(0);
        compressMatch(matchLine);
    }else{
        matchLine=dLine;
        return;
    }
    
    
    //drawGrapeLine(matchLine);exit(0);

//#ifndef OCR_woodblock
    //анализ готовых стеков.
    //проверяем есть ли над или под одиночной буквой коренные буквы или огласовки с высокой корреляцией.
    //если есть, то букву считаем частью стека и убираем как строительный блок OpenType.
//    testStackLetter(matchLine,lineImg32,letterAImg,letterBImg);
//#endif
    
    for(int i=0;i<dLine.size();i++){
        if(!dLine[i].correlation||(dLine[i].OCRIndex!='Z'&&dLine[i].OCRIndex!='N'))continue;
        matchLine.push_back(dLine[i]);
        
    }
    
    //drawGrapeLine(matchLine); exit(0);
    
    if(print){TIME_PRINT_}
    return;
 }