예제 #1
0
void GLogicProcessor::LoadFontMap(map<string,uniRecord>&fMap,string &fileName){
	
	ifstream TibetanFontMap(fileName.c_str());
	if( !TibetanFontMap ){
		cout<<fileName<<" not found"<<END;  return;
	}
	
	vector<string> srcStrings;
	string tString;
	vector<string>lineStrings;
	//short i=0;
	uniRecord record;
	vector<string> value;
	vector<string>::size_type d;
	wstring wstr;
	unsigned short data;
	        //cout_<<"load map "<<fileName<<END; 
	maxUniRecord=0;
	
	while (getline(TibetanFontMap, tString,'\n')){
		srcStrings.push_back(tString);    //cout<<"vector count="<<srcStrings.size()<<endl;
		lineStrings=explode(":|:",tString); //for(int i=0;i<lineStrings.size();i++)cout<<lineStrings[i]<<" ";
		wstr=L"";
		
        wstr+=UTF_to_Unicode(lineStrings[0]);
		//cout<<"lineStrings="<<tString<<" wstr.size()="<<wstr.size()<<" wstr="<<Unicode_to_UTF(wstr)<<END;
		record.OCRKey=lineStrings[0];
		record.Wylie=lineStrings[1]; 
		if(lineStrings.size()>2){
			//cout_<<"lineStrings.size()="<<lineStrings.size()<<" v="<<lineStrings[2]<<endl;
			record.keyUTF=lineStrings[2];
			if(record.keyUTF.size()/3>maxUniRecord)maxUniRecord=(int)record.keyUTF.size()/3;
			//cout_<<" wstr="<<Unicode_to_UTF(wstr)<<" value.size()="<<value.size()<<END;
 		    //cout_<<" str="<<record.keyUTF<<" hex="<<lineStrings[0]<<"key="<<record.OCRKey<<"//"<<END;
		}
		if(lineStrings.size()>3){
			//cout_<<"lineStrings.size()="<<lineStrings.size()<<" v="<<lineStrings[3]<<"/"<<endl;
				record.letterUTF=lineStrings[3];
				//cout_<<" wstr="<<Unicode_to_UTF(wstr)<<END;
		}		
		
		fMap[record.OCRKey]=record;
		//cout<<"fMap["<<record.OCRKey<<"]="<<fMap[record.OCRKey].keyUTF<<"//"<<END; exit(0);
	}
	//cout_<<"fontMap[str][letter].OCRKey"<<fontMap["Dederis-a"][" "].keyUTF<<"//"<<END;
	//cout_<< "fMap.size()="<<fMap.size()<<" maxUniRecord="<<maxUniRecord<<endl;
	return;
};//____________________________________________________________________________
예제 #2
0
void GLogicProcessor::buildOpenType(vector<OCRMatch>&line,vector<OCRMatch>&letterLine){

    //формируем массив букв OpenType с координатами соответсвующими позиции элемента стековой буквы
    //относительно родительской буквы
    int print=0;
        
    for(int i=0;i<line.size();i++){
        //cout<<"i="<<i<<" c="<<line[346].correlation<<endl;
        if(!line[i].correlation)continue;
        string name=line[i].name;
        line[i].setSize();
        //print=0; if(i==112)print=1; if(!print)continue;
        
        DR("line["<<i<<"].name="<<line[i].name<<"/ OCRIndex="<<line[i].OCRIndex<<endl)
        
        wstring wName=UTF_to_Unicode(line[i].name);
        if(line[i].OCRIndex=='Z'||line[i].OCRIndex=='S'){
            line[i].uni=wName[0];
            line[i].status=0;
            line[i].Character=0;
            letterLine.push_back(line[i]);
            continue;
        }
        
        int index=fontGMap->getHKey(name,8);
        
        TString strT; fontTable->getTStr(index,&strT);
        DR("name="<<strT[8]<<" OCRIndex = "<<strT[4]<<endl)
        if(strT.size()<5||(strT[1]!="tib"&&strT[1]!="eng"&&strT[1]!="skt")){continue; }
        string OCRIndex=strT[4];
        if(line[i].OCRIndex=='S')OCRIndex="S";
        if(wName.size()==1||OCRIndex=="Z"){
            //переводим все буквы в верхний регистр
            wName[0]=UniBigLetters[wName[0]];
            line[i].name=Unicode_to_UTF(wName);  DR("n="<<line[i].name<<" i="<<letterLine.size()<<endl)
            line[i].uni=wName[0];
            line[i].status=0;
            line[i].Character=0;
            line[i].OCRIndex=OCRIndex[0];
            letterLine.push_back(line[i]);
        }else{
        
            for(int j=0;j<wName.size();j++){
                OCRMatch match;
                wstring w;  w=wName[j];
                //переводим все буквы в верхний регистр
                w[0]=UniBigLetters[w[0]];
                DR("    OCRLetter  =  "<<Unicode_to_UTF(w)<<" / "<<OCRIndex[j])
                DR(" x0="<<line[i].x0<<" x1="<<line[i].x1<<" y0="<<line[i].y0<<" y1="<<line[i].y1<<endl)
                match.name=Unicode_to_UTF(w);
                match.correlation=line[i].correlation;
                match.letterIndex=line[i].letterIndex;
                match.OCRIndex=OCRIndex[j];
                match.uni=w[0];
                match.status=1;                     //помечаем букву как строительный элемент OpenType
                match.Character=100;                //помечаем букву как строительный элемент OpenType
                if(wName.size()==1){match.status=0; match.Character=0;} //помечаем букву как одиночную
                
                if(OCRIndex[j]=='A'&&OCRIndex.size()==1){
                    match.x0=line[i].xCenter-line[i].letterW/2;
                    match.x1=line[i].xCenter+line[i].letterW/2;
                    match.y0=line[i].yCenter-line[i].letterH/2;
                    match.y1=line[i].yCenter+line[i].letterH/2;
                    match.letterH=line[i].letterH;
                    match.letterW=line[i].letterW;
                }
                if(OCRIndex=="S"){   //режим распознавания в котором стеки не разбираем на OpenType
                    match.x0=line[i].x0;
                    match.x1=line[i].x1;
                    match.y0=line[i].y0;
                    match.y1=line[i].y1;
                    match.letterH=line[i].letterH;
                    match.letterW=line[i].letterW;
                    match.name=line[i].name;
                    match.wName=wName;
                    match.Character=0;
                    match.OCRIndex='S';
                    match.status=0;
                    for(int j=0;j<wName.size();j++){
                        wstring w;  w=wName[j];
                        //переводим все буквы в верхний регистр
                        w[0]=UniBigLetters[w[0]];
                        match.uni+=w[0];
                    }
                    match.setSize();
                    letterLine.push_back(match);
                    break;
                }
                if(OCRIndex[j]=='A'&&OCRIndex.size()>1){
                    match.x0=line[i].xCenter-line[i].letterW/2;
                    match.x1=line[i].xCenter+line[i].letterW/2;
                    if(OCRIndex[OCRIndex.size()-1]=='V'){
                        match.y0=line[i].yCenter-line[i].letterH/2+line[i].letterW*0.75;
                        match.y1=match.y0+line[i].letterH/(int)OCRIndex.size();
                    }else{
                        if((OCRIndex[1]=='W'||OCRIndex[1]=='R')&&OCRIndex.size()==2){
                            match.y0=line[i].yCenter-line[i].letterH/2;
                            match.y1=match.y0+line[i].letterH-20;
                        }else{
                            match.y0=line[i].yCenter-line[i].letterH/2;
                            match.y1=match.y0+line[i].letterH/(int)OCRIndex.size();                
                        }    
                    }
                    match.letterH=line[i].letterW;
                    match.letterW=line[i].letterW;
                }
                if(OCRIndex[j]=='B'||
                   OCRIndex[j]=='C'||
                   OCRIndex[j]=='D'||
                   OCRIndex[j]=='E'||
                   OCRIndex[j]=='F'||
                   OCRIndex[j]=='G'||
                   OCRIndex[j]=='H'){
                    
                    match.x0=line[i].xCenter-line[i].letterW/2;
                    match.x1=line[i].xCenter+line[i].letterW/2;
                    if(OCRIndex.size()>1){
                        match.y0=letterLine[letterLine.size()-1].y0+line[i].letterH/(int)OCRIndex.size();
                    }else{
                        match.y0=line[i].y0;
                    }
                    match.y1=match.y0+line[i].letterH/(int)OCRIndex.size();
                    
                    match.letterH=match.y1-match.y0;
                    match.letterW=line[i].letterW;
                }
                if(OCRIndex[j]=='R'){
                    
                    match.x0=line[i].xCenter-line[i].letterW/2;
                    match.x1=line[i].xCenter+line[i].letterW/2;
                    if(OCRIndex.size()>1){
                        if(OCRIndex[OCRIndex.size()-1]=='R'){
                            match.y0=line[i].y1-20;
                            match.y1=match.y0+20;
                        }else{
                            match.y0=letterLine[letterLine.size()-1].y1;
                            match.y1=match.y0+20;
                        }    
                    }else{
                        match.y0=line[i].y0;
                        match.y1=line[i].y1;
                        
                    }
                    match.letterH=match.y1-match.y0;
                    match.letterW=line[i].letterW;
                }
                if(OCRIndex[j]=='W'){
                    
                    match.x0=line[i].xCenter-line[i].letterW/2;
                    match.x1=line[i].xCenter+line[i].letterW/2;
                    if(OCRIndex.size()>1){
                        if(OCRIndex[OCRIndex.size()-1]=='W'){
                            match.y0=line[i].y1-20;
                            match.y1=match.y0+20;
                        }else{
                            match.y0=letterLine[letterLine.size()-1].y1;
                            match.y1=match.y0+20;
                        }    
                    }else{
                        match.y0=line[i].y0;
                        match.y1=line[i].y1;
                        
                    }
                    match.letterH=match.y1-match.y0;
                    match.letterW=line[i].letterW;
                }
                
                
                if(OCRIndex[j]=='V'||OCRIndex[j]=='Z'||OCRIndex[j]=='X'){
                    match.x0=line[i].xCenter-line[i].letterW/2;
                    match.x1=line[i].xCenter+line[i].letterW/2;
                    match.y0=line[i].yCenter-line[i].letterH/2;
                    match.y1=match.y0+20;
                    match.letterH=match.y1-match.y0;
                    match.letterW=line[i].letterW;
                    match.name=line[i].name;
                }
                DR(" x0="<<match.x0<<" x1="<<match.x1<<" y0="<<match.y0<<" y1="<<match.y1<<endl)
                DR(" letterLine.size()="<<letterLine.size()<<" @@@"<<match.name<<endl)
                match.setSize();
                letterLine.push_back(match);
                //дополняем массив похожими по начертанию буквами
                /* if(match.name=="ཞ"){
                 OCRMatch match_=match;
                 match_.name="ན";
                 match_.wName=UTF_to_Unicode("ན");
                 match_.uni=match_.wName[0];
                 match_.correlation-=5;
                 letterLine.push_back(match_);
                 }
                 */
            }
        }
    }
    
}
예제 #3
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){
예제 #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;
 }