首頁>Program>source

我正在對轮胎进行文字識別。 為了使用OCR,我必须首先获得一个清晰的二进製圖。

我已经處理過圖像,並且文字出現了斷邊和不连續的邊缘。 我已经在MATLAB中使用圆盤和線元素尝試了標準腐蚀/膨脹,但這並没有真正的帮助。

Pr1-關於如何重建這些字元並填補字元笔画之間的空白的任何想法?

Pr2-上面的圖像具有更高的分辨率和良好的照明條件。 但是,如果照明不佳且分辨率相對较低,如下圖所示,那麼可行的處理方法是什麼?

尝試的解決方案:

S1:這是對Spektre共享的已處理圖像應用中值濾镜的結果.為了消除噪声,我應用了中值濾波器(5x5),隨後使用線元(5,11)进行了圖像放大.即使是現在,OCR(Matlab 2014b)也只能識別某些字元

無論如何,到目前為止非常感谢您的建議.我仍將拭目以待,看看有人是否可以提出一些不同的建議,也许就是開箱即用的想法:)。

Matlab執行以下Spektre的代碼的步骤的結果(不进行笔划膨脹(以1,2,3,4的角进行归一化:

且阈值tr0 = 400和tr1 = 180以及用於規範化1,3,2,4的角點順序

最好的問候

wajahat

最新回復
  • 5月前
    1 #

    I have played a bit with your input

    照明的归一化+動態範圍归一化可以帮助获得更好的結果,但是距离所需的距离還很远.我想尝試锐化偏匯數以增強背景中的字母並消除小凸起,然後再整合並重新着色以掩盖圖像(我不確定是否可能明天)我將對此进行編輯(並評論/通知) 您)

    normalized lighting

    計算平均角強度並双線性重新調整強度以匹配平均颜色

    edge detection

    強度 i的偏匯數 由 xy ...

      i=|i(x,y)/dx|+|i(x,y)/dy|

      然後被 treshold=13占据

      [notes]

      為消除大多數噪声,我在邊缘檢測之前應用了平滑濾波

      [edit1] after some analysis I found your image has poor edges for sharpening integration

      這裏是在圖像的中線通過x首次求匯後的強度圖的示例

      如您所见,黑色區域很好,但白噪声几乎無法从背景噪声中識別出来.因此,您唯一的希望是使用 min max filtering 作為 @Daniel 建議答案,並在黑色邊缘區域加重(白色不可靠)

      min max濾镜強調黑色(蓝色蒙版)和白色(红色蒙版)區域.如果展位區域可靠,那麼您只需填充它们之間的空間,但這不是您的選擇,而是我將擴大區域(在蓝色蒙版上加權更多),並使用针對3種颜色輸入而定製的OCR對結果进行OCR.

        You can make your own custom OCR for this see OCR and character similarity

      you could also take 2 images 具有不同的光線位置和固定的摄像頭,並將它们組合起来可以从各个方向覆盖可識別的黑色區域

      [edit2] C++ source code for the last method

      //---------------------------------------------------------------------------
      typedef union { int dd; short int dw[2]; byte db[4]; } color;
      picture pic0,pic1,pic2; // pic0 source image,pic1 normalized+min/max,pic2 enlarge filter
      //---------------------------------------------------------------------------
      void filter()
          {
          int sz=16;          // [pixels] square size for corner avg color computation (c00..c11)
          int fs0=5;          // blue [pixels] font thickness
          int fs1=2;          // red  [pixels] font thickness
          int tr0=320;        // blue min treshold
          int tr1=125;        // red  max treshold
          int x,y,c,cavg,cmin,cmax;
          pic1=pic0;          // copy source image
          pic1.rgb2i();       // convert to grayscale intensity
          for (x=0;x<5;x++) pic1.ui_smooth();
          cavg=pic1.ui_normalize();
          // min max filter
          cmin=pic1.p[0][0].dd; cmax=cmin;
          for (y=0;y<pic1.ys;y++)
           for (x=0;x<pic1.xs;x++)
              {
              c=pic1.p[y][x].dd;
              if (cmin>c) cmin=c;
              if (cmax<c) cmax=c;
              }
          // treshold min/max
          for (y=0;y<pic1.ys;y++)
           for (x=0;x<pic1.xs;x++)
              {
              c=pic1.p[y][x].dd;
                   if (cmax-c<tr1) c=0x00FF0000; // red
              else if (c-cmin<tr0) c=0x000000FF; // blue
              else                 c=0x00000000; // black
              pic1.p[y][x].dd=c;
              }
          pic1.rgb_smooth();  // remove single dots
          // recolor image
          pic2=pic1; pic2.clear(0);
          pic2.bmp->Canvas->Pen  ->Color=clWhite;
          pic2.bmp->Canvas->Brush->Color=clWhite;
          for (y=0;y<pic1.ys;y++)
           for (x=0;x<pic1.xs;x++)
              {
              c=pic1.p[y][x].dd;
              if (c==0x00FF0000)
                  {
                  pic2.bmp->Canvas->Pen  ->Color=clRed;
                  pic2.bmp->Canvas->Brush->Color=clRed;
                  pic2.bmp->Canvas->Ellipse(x-fs1,y-fs1,x+fs1,y+fs1); // red
                  }
              if (c==0x000000FF)
                  {
                  pic2.bmp->Canvas->Pen  ->Color=clBlue;
                  pic2.bmp->Canvas->Brush->Color=clBlue;
                  pic2.bmp->Canvas->Ellipse(x-fs0,y-fs0,x+fs0,y+fs0); // blue
                  }
              }
          }
      //---------------------------------------------------------------------------
      int  picture::ui_normalize(int sz=32)
          {
          if (xs<sz) return 0;
          if (ys<sz) return 0;
          int x,y,c,c0,c1,c00,c01,c10,c11,cavg;
          // compute average intensity in corners
          for (c00=0,y=         0;y<     sz;y++) for (x=         0;x<     sz;x++) c00+=p[y][x].dd; c00/=sz*sz;
          for (c01=0,y=         0;y<     sz;y++) for (x=xs-sz;x<xs;x++) c01+=p[y][x].dd; c01/=sz*sz;
          for (c10=0,y=ys-sz;y<ys;y++) for (x=         0;x<     sz;x++) c10+=p[y][x].dd; c10/=sz*sz;
          for (c11=0,y=ys-sz;y<ys;y++) for (x=xs-sz;x<xs;x++) c11+=p[y][x].dd; c11/=sz*sz;
          cavg=(c00+c01+c10+c11)/4;
          // normalize lighting conditions
          for (y=0;y<ys;y++)
           for (x=0;x<xs;x++)
              {
              // avg color = bilinear interpolation of corners colors
              c0=c00+(((c01-c00)*x)/xs);
              c1=c10+(((c11-c10)*x)/xs);
              c =c0 +(((c1 -c0 )*y)/ys);
              // scale to avg color
              if (c) p[y][x].dd=(p[y][x].dd*cavg)/c;
              }
          // compute min max intensities
          for (c0=0,c1=0,y=0;y<ys;y++)
           for (x=0;x<xs;x++)
              {
              c=p[y][x].dd;
              if (c0>c) c0=c;
              if (c1<c) c1=c;
              }
          // maximize dynamic range <0,765>
          for (y=0;y<ys;y++)
           for (x=0;x<xs;x++)
            c=((p[y][x].dd-c0)*765)/(c1-c0);
          return cavg;
          }
      //---------------------------------------------------------------------------
      void picture::rgb_smooth()
          {
          color   *q0,*q1;
          int     x,y,i;
          color   c0,c1,c2;
          if ((xs<2)||(ys<2)) return;
          for (y=0;y<ys-1;y++)
              {
              q0=p[y  ];
              q1=p[y+1];
              for (x=0;x<xs-1;x++)
                  {
                  c0=q0[x];
                  c1=q0[x+1];
                  c2=q1[x];
                  for (i=0;i<4;i++) q0[x].db[i]=WORD((WORD(c0.db[i])+WORD(c0.db[i])+WORD(c1.db[i])+WORD(c2.db[i]))>>2);
                  }
              }
          }
      //---------------------------------------------------------------------------
      

      我將自己的圖片類用於圖片,因此一些成員是:

        xs,ys 圖片尺寸(以畫素為單位)

        p[y][x].dd(x,y)的畫素 位置為32位整數型別

        clear(color) -清除整个圖像

        resize(xs,ys) -將圖像調整為新分辨率

        bmp -具有Canvas訪問權限的VCL封裝的GDI位圖

        我仅為2个相關成員函式添加了源代碼(無需在此處複製整个類)

        [edit3] LQ image

        我發現的最佳設置(代碼相同):

        int sz=32;          // [pixels] square size for corner avg color computation (c00..c11)
        int fs0=2;          // blue [pixels] font thickness
        int fs1=2;          // red  [pixels] font thickness
        int tr0=52;         // blue min treshold
        int tr1=0;          // red  max treshold
        

        由於光照條件,红色區域不可用(關闭)

  • 5月前
    2 #

    您可以先應用最大濾镜(將新圖像中每个畫素的最大值分配给新圖像中的每个畫素) 畫素),然後是最小濾镜(在最大圖像中从邻域分配最小值).尤其是如果您將邻域的形狀設置得比其高一點(例如,左右2或3畫素,頂部/底部1畫素),則應该能够获得一些字元(您的圖像似乎主要顯示了 在水平方向上的間隙)。

    最佳邻域大小和形狀取決於您的特定問题,因此您必须进行一些實驗.通過此操作,您可能会遇到將字元粘在一起的情况-如果与其他Blob相比,Blob的宽度太大,則可能必须檢測這些Blob並將其拆分。

    edit:同樣,二值化設置绝對是關键.尝試几種不同的二值化演算法(Otsu,Sauvola等),以查看哪種演算法(和哪些引數)最適合您。

  • asp.net web api:構造函式依赖註入webApi屬性
  • c#:SqlDataSourceEnumeratorInstanceGetDataSources()找不到本地SQL Server 2008例項