2016-08-30 49 views
2

我試圖爲OCR準備圖像,至今這裏是我一直在使用信息完成從Extracting text OpenCVOpenCV進行OCR:如何計算閾值水平爲灰度圖像OCR

從得到的圖像我使用已過濾的輪廓,使口罩如下:

//this is the mask of all the text 
Mat maskF = Mat::zeros(rgb.rows, rgb.cols, CV_8UC1); 
// CV_FILLED fills the connected components found - CV_FILLED to fill 
drawContours(maskF, letters, -1, Scalar(255), CV_FILLED); 
cv::imwrite("noise2-Mask.png", maskF); 

所產生的IMG是有希望的:enter image description here

考慮,這是我原來的IMG:enter image description here

不幸的是,在它上面運行Tesseract會產生一些問題,我認爲你在詞語上的字母之間看到的灰色級別混淆了tesseract - 所以,你在考慮耶,讓我們做一個二元變換,好吧,只是錯過了下半部分頁面,所以我嘗試應用大津閾值以及文本變得像素化和字符失去其形狀。

我試圖從CalcBlockMeanVariance但OpenCV Adaptive Threshold OCR無法得到它來編譯(而且我不能肯定我明白這一切TBH)上

res=1.0-res; 
res=Img+res; 

總之編譯扼流圈,如果任何人有任何建議,我會感激它!請注意,Tesseract很少識別這些分數,但是我正在編寫一個新的訓練集,希望能夠提高回覆率)

回答

0

您可以嘗試清除所有帶有侵蝕的文本,然後從灰度圖像中減去結果或者使用tophat變換代替全局閾值的背景! Here你可以找到一個示例代碼!爲什麼不使用現有的adaptiveThreshold功能?

2
  1. Enhancing dynamic range and normalizing illumination

    要點是第一正常化背景無縫顏色。有很多方法可以做到這一點。以下是我爲您的圖像所嘗試的內容:

    爲圖像創建紙張/墨水單元表(與鏈接答案中的方式相同)。所以你選擇足夠大的網格單元來清楚背景中的字符特徵。對於您的圖像,我選擇8x8像素。因此,將圖像分成正方形並計算每種顏色的平均顏色和絕對差。然後標記飽和度(小絕對差),並將其設置爲紙張或墨水單元,與整幅圖像平均顏色相比,根據平均顏色。

    現在只需處理圖像的所有行,併爲每個像素獲取左右紙盒。並在這些值之間進行線性插值。這應該會引導您使用該像素的實際背景顏色,所以只需從圖像中減去它。

    我給這家C++實現看起來是這樣的:

    color picture::normalize(int sz,bool _recolor,bool _sbstract) 
        { 
        struct _cell { color col; int a[4],da,_paper; _cell(){}; _cell(_cell& x){ *this=x; }; ~_cell(){}; _cell* operator = (const _cell *x) { *this=*x; return this; }; /*_cell* operator = (const _cell &x) { ...copy... return this; };*/ }; 
        int i,x,y,tx,ty,txs,tys,a0[4],a1[4],n,dmax; 
        int x0,x1,y0,y1,q[4][4][2],qx[4],qy[4]; 
        color c; 
        _cell **tab; 
        // allocate grid table 
        txs=xs/sz; tys=ys/sz; n=sz*sz; c.dd=0; 
        if ((txs<2)||(tys<2)) return c; 
        tab=new _cell*[tys]; for (ty=0;ty<tys;ty++) tab[ty]=new _cell[txs]; 
        // compute grid table 
        for (y0=0,y1=sz,ty=0;ty<tys;ty++,y0=y1,y1+=sz) 
        for (x0=0,x1=sz,tx=0;tx<txs;tx++,x0=x1,x1+=sz) 
         { 
         for (i=0;i<4;i++) a0[i]=0; 
         for (y=y0;y<y1;y++) 
         for (x=x0;x<x1;x++) 
          { 
          dec_color(a1,p[y][x],pf); 
          for (i=0;i<4;i++) a0[i]+=a1[i]; 
          } 
         for (i=0;i<4;i++) tab[ty][tx].a[i]=a0[i]/n; 
         enc_color(tab[ty][tx].a,tab[ty][tx].col,pf); 
    
         tab[ty][tx].da=0; 
         for (i=0;i<4;i++) a0[i]=tab[ty][tx].a[i]; 
         for (y=y0;y<y1;y++) 
         for (x=x0;x<x1;x++) 
          { 
          dec_color(a1,p[y][x],pf); 
          for (i=0;i<4;i++) tab[ty][tx].da+=abs(a1[i]-a0[i]); 
          } 
         tab[ty][tx].da/=n; 
         } 
        // compute max safe delta dmax = avg(delta) 
        for (dmax=0,ty=0;ty<tys;ty++) 
        for (tx=0;tx<txs;tx++) 
         dmax+=tab[ty][tx].da; 
         dmax/=(txs*tys); 
    
        // select paper cells and compute avg paper color 
        for (i=0;i<4;i++) a0[i]=0; x0=0; 
        for (ty=0;ty<tys;ty++) 
        for (tx=0;tx<txs;tx++) 
         if (tab[ty][tx].da<=dmax) 
         { 
         tab[ty][tx]._paper=1; 
         for (i=0;i<4;i++) a0[i]+=tab[ty][tx].a[i]; x0++; 
         } 
         else tab[ty][tx]._paper=0; 
        if (x0) for (i=0;i<4;i++) a0[i]/=x0; 
        enc_color(a0,c,pf); 
        // remove saturated ink cells from paper (small .da but wrong .a[]) 
        for (ty=1;ty<tys-1;ty++) 
        for (tx=1;tx<txs-1;tx++) 
         if (tab[ty][tx]._paper==1) 
         if ((tab[ty][tx-1]._paper==0) 
         ||(tab[ty][tx+1]._paper==0) 
         ||(tab[ty-1][tx]._paper==0) 
         ||(tab[ty+1][tx]._paper==0)) 
         { 
         x=0; for (i=0;i<4;i++) x+=abs(tab[ty][tx].a[i]-a0[i]); 
         if (x>dmax) tab[ty][tx]._paper=2; 
         } 
        for (ty=0;ty<tys;ty++) 
        for (tx=0;tx<txs;tx++) 
         if (tab[ty][tx]._paper==2) 
         tab[ty][tx]._paper=0; 
    
        // piecewise linear interpolation H-lines 
        int ty0,ty1,tx0,tx1,d; 
        if (_sbstract) for (i=0;i<4;i++) a0[i]=0; 
        for (y=0;y<ys;y++) 
         { 
         ty=y/sz; if (ty>=tys) ty=tys-1; 
         // first paper cell 
         for (tx=0;(tx<txs)&&(!tab[ty][tx]._paper);tx++); tx1=tx; 
         if (tx>=txs) continue; // no paper cell found 
         for (;tx<txs;) 
          { 
          // fnext paper cell 
          for (tx++;(tx<txs)&&(!tab[ty][tx]._paper);tx++); 
          if (tx<txs) 
           { 
           tx0=tx1; x0=tx0*sz; 
           tx1=tx; x1=tx1*sz; 
           d=x1-x0; 
           } 
          else x1=xs; 
    
          // interpolate 
          for (x=x0;x<x1;x++) 
           { 
           dec_color(a1,p[y][x],pf); 
           for (i=0;i<4;i++) a1[i]-=tab[ty][tx0].a[i]+(((tab[ty][tx1].a[i]-tab[ty][tx0].a[i])*(x-x0))/d)-a0[i]; 
           if (pf==_pf_s ) for (i=0;i<1;i++) clamp_s32(a1[i]); 
           if (pf==_pf_u ) for (i=0;i<1;i++) clamp_u32(a1[i]); 
           if (pf==_pf_ss ) for (i=0;i<2;i++) clamp_s16(a1[i]); 
           if (pf==_pf_uu ) for (i=0;i<2;i++) clamp_u16(a1[i]); 
           if (pf==_pf_rgba) for (i=0;i<4;i++) clamp_u8 (a1[i]); 
           enc_color(a1,p[y][x],pf); 
           } 
          } 
         } 
    
        // recolor paper cells with avg color (remove noise) 
        if (_recolor) 
        for (y0=0,y1=sz,ty=0;ty<tys;ty++,y0=y1,y1+=sz) 
         for (x0=0,x1=sz,tx=0;tx<txs;tx++,x0=x1,x1+=sz) 
         if (tab[ty][tx]._paper) 
         for (y=y0;y<y1;y++) 
         for (x=x0;x<x1;x++) 
          p[y][x]=c; 
    
        // free grid table 
        for (ty=0;ty<tys;ty++) delete[] tab[ty]; delete[] tab; 
        return c; 
        } 
    

    見鏈接的回答更多的細節。切換到灰度<0,765>和使用pic1.normalize(8,false,true);

    normalize

  2. 二值化

    我第一次嘗試幼稚簡單範圍tresholding後這裏導致您的輸入圖像,所以如果所有色彩通道值(R,G ,B)在範圍<min,max>它被重新着色到c1別的c0

    void picture::treshold_AND(int min,int max,int c0,int c1) // all channels tresholding: c1 <min,max>, c0 (-inf,min)+(max,+inf) 
        { 
        int x,y,i,a[4],e; 
        for (y=0;y<ys;y++) 
        for (x=0;x<xs;x++) 
         { 
         dec_color(a,p[y][x],pf); 
         for (e=1,i=0;i<3;i++) if ((a[i]<min)||(a[i]>max)){ e=0; break; } 
         if (e) for (i=0;i<4;i++) a[i]=c1; 
         else for (i=0;i<4;i++) a[i]=c0; 
         enc_color(a,p[y][x],pf); 
         } 
        } 
    

    應用pic1.treshold_AND(0,127,765,0);和轉換回RGBA後,我得到了這樣的結果:

    binarise

    灰色的噪聲是由於JPEG壓縮(PNG會過大)。正如你所看到的結果或多或少是可以接受的。

    如果這還不夠,你可以將你的圖片分成幾部分。計算每個片段的直方圖(它應該是雙峯),然後找到2個最大值之間的顏色,這是您的閾值。問題是,背景涵蓋更多領域,因此油墨的峯值比較小,有時很難在直線秤當場看到完整的圖像直方圖:

    bimodal histogram

    當你這樣做的每段這將是更更好(因爲在閾值周圍會有更少的背景/文字顏色流血),所以間隙會更加明顯。此外,不要忘記忽略小間隙(缺失直方圖中的垂直線),因爲它們僅與量化/編碼/舍入(圖像中不存在所有灰度)有關,所以您應該濾除小於然後少量強度的間隔他們與最後和下一個有效直方圖條目的平均值。

+0

我會試試這個 - 沒有找到一種方法將此添加到我的obj-C項目,但會做研究,看看我可以如何添加一個方法到圖片對象。 – Xav

+0

圖片只是一個墊? – Xav

+0

@Xav如果你使用第3方圖像庫,直接混淆它不是一個好主意。你可以在圖像類之外編寫自定義函數,改變這些圖像作爲操作數。是的,我的圖像是二維數組/像素矩陣,其中像素爲32位無符號整數('DWORD'),支持編碼_pf_rgba(4x8bit uint),_ pf_u(1x32bit uint),_pf_s(1x32bit int)以及更多'dec_color/enc_color'只需在每個通道的基礎上將其打包/打包到DWORD [4]'陣列,以使代碼具有任何像素格式的通用性。因爲只有灰度,你可以忽略所有這些。 – Spektre