delphi驗證碼識別學習之映像的灰階化、二值化及反色

來源:互聯網
上載者:User

映像的灰階化、二值化和反色是些較簡單的映像像素處理過程,我在《GDI+ 在Delphi程式的應用 -- ColorMatrix與映像灰階化》和《GDI+ 在Delphi程式的應用 -- 映像二值化》二篇文章中講了如何利用GDI+的ColorMatrix實現映像灰階化和二值化,但是那種處理只適合GDI+的映像類,本文的方法同時適用於GDI+映像和Delphi的TGraphic映像。

流程定義:  // 映像求反  procedure ImageInvert(var Data: TImageData);  // 灰階化映像  procedure ImageGray(var Data: TImageData);  // 灰階統計。GrayData為灰階統計結構;預設統計彩色圖灰階,  procedure ImageGrayStat(const Data: TImageData; var GrayData: TGrayStatData;    IsGrayImage: Boolean = False);  // 二值化映像。Threshold閥值,需要32位灰階圖資料  procedure ImageTwoValues(var Data: TImageData; Threshold: LongWord = 127);  // 動態閥值(子圖灰階平均值)二值化映像,SubSize子圖大小,需要32位灰階圖資料  procedure ImageDynamTwoValues(var Data: TImageData; SubSize: Integer);實現代碼:procedure ImageInvert(var Data: TImageData);asm    push    edi    push    ebx    call    IsValid32    jc      @@Exit    call    SetDataRegs32    mov     eax, 0ffffffh@@yLoop:    push    ecx@@xLoop:    xor     [edi], eax    add     edi, 4    loop    @@xLoop    pop     ecx    add     edi, ebx    dec     edx    jnz     @@yLoop@@Exit:    pop     ebx    pop     ediend;procedure ImageGray(var Data: TImageData);asm    push    ebp    push    esi    push    edi    push    ebx    call    IsValid32    jc      @@Exit    call    SetDataRegs32@@yLoop:    push    ecx@@xLoop:    movzx   eax, [edi].TARGBQuad.Blue    movzx   esi, [edi].TARGBQuad.Green    movzx   ebp, [edi].TARGBQuad.Red    imul    eax, 117        // blue   0.114 * 1024    imul    esi, 601        // green  0.587 * 1024    imul    ebp, 306        // red    0.299 * 1024    add     eax, esi    add     eax, ebp    add     eax, 512        // Rounding    shr     eax, 10         // eax = Round((R * 306 + G * 601 + B * 117) / 1024)    mov     [edi].TARGBQuad.Red, al    mov     [edi].TARGBQuad.Green, al    mov     [edi].TARGBQuad.Blue, al    add     edi, 4    loop    @@xLoop    pop     ecx    add     edi, ebx    dec     edx    jnz     @@yLoop@@Exit:    pop     ebx    pop     edi    pop     esi    pop     ebpend;procedure GrayStat(const Data: TImageData; var GrayData: TGrayStatData; IsGrayImage: Boolean);asm    push    ebp    push    esi    push    edi    push    ebx    mov     edi, edx        // edi = GrayData    mov     edx, ecx    mov     esi, [eax].TImageData.Scan0    mov     ecx, [eax].TImageData.Width    mov     ebx, [eax].TImageData.Height    mov     ebp, [eax].TImageData.Stride    mov     eax, ecx    shl     eax, 2    sub     ebp, eax            // ebp = offset    mov     eax, ecx    imul    eax, ebx    push    eax                 // Total pixel count    push    ecx                 // init Grays    push    edi    mov     ecx, 256    xor     eax, eax    rep     stosd    pop     edi    pop     ecx    cmp     edx, TRUE    je      @@yGrayLoop    // 建立彩色圖的灰階數組@@yLoop:    push    ecx@@xLoop:    movzx   eax, [esi].TARGBQuad.Blue    movzx   edx, [esi].TARGBQuad.Green    imul    eax, 117            // blue   0.114 * 1024    imul    edx, 601            // green  0.587 * 1024    add     edx, eax    movzx   eax, [esi].TARGBQuad.Red    imul    eax, 306            // red    0.299 * 1024    add     eax, edx    add     eax, 512            // Rounding    shr     eax, 10             // eax = Round((R * 306 + G * 601 + B * 117) / 1024)    inc     dword ptr [edi].TGrayStatData.Grays[eax*4]// grayData.Grays[eax] ++    add     esi, 4              // esi += 4    loop    @@xLoop    pop     ecx    add     esi, ebp    dec     ebx    jnz     @@yLoop    jmp     @@SumStart    // 建立灰階圖的灰階數組@@yGrayLoop:    push    ecx@@xGrayLoop:    movzx   eax, [esi].TARGBQuad.Blue// eax = Gray = *esi    inc     dword ptr [edi].TGrayStatData.Grays[eax*4]// grayData.Grays[eax] ++    add     esi, 4              // esi +=4    loop    @@xGrayLoop    pop     ecx    add     esi, ebp    dec     ebx    jnz     @@yGrayLoop    // 計算總的灰階值、最大灰階值及最小灰階值@@SumStart:    push    edi    xor     eax, eax            // edx:eax = 0 (GrayData.Total)    xor     edx, edx    mov     esi, edi            // esi = ebx = &GrayData.Grays[0]    mov     ebx, edi    xor     ecx, ecx            // for (index = 0; index < 256; index ++)@@SumLoop:                      // {    mov     ebp, [edi]    cmp     [esi], ebp    jae     @@1    mov     esi, edi            //   if (*esi < *edi) esi = edi@@1:    cmp     [ebx], ebp    jbe     @@2    mov     ebx, edi            //   if (*ebx > *edi) ebx = edi@@2:    imul    ebp, ecx            //   ebp = *edi * index    add     eax, ebp            //   edx:eax += ebp    adc     edx, 0    add     edi, 4              //   edi += 4    inc     ecx    cmp     ecx, 255    jle     @@SumLoop           // }    pop     edi    sub     ebx, edi    shr     ebx, 2              // ebx = (ebx - &GrayData.Grays[0]) / 4    mov     [edi].TGrayStatData.MinGray, ebx// GrayData.MinGray = ebx    sub     esi, edi    shr     esi, 2              // esi = (esi - &GrayData.Grays[0]) / 4    mov     [edi].TGrayStatData.MaxGray, esi// GrayData.MaxGray = esi    pop     ebx    mov     [edi].TGrayStatData.Count, ebx // GrayData.Count = data.Width * data.Height    mov     dword ptr [edi].TGrayStatData.Total, eax // GrayData.Total = edx:eax    mov     dword ptr [edi].TGrayStatData.Total+4, edx    mov     ecx, ebx    shr     ecx, 1    add     eax, ecx    adc     edx, 0    idiv    ebx    // GrayData.Average = (GrayData.Total + GrayData.Count / 2) / GrayData.Count)    mov     [edi].TGrayStatData.Average, eax@@Exit:    pop     ebx    pop     edi    pop     esi    pop     ebpend;procedure ImageGrayStat(const Data: TImageData;  var GrayData: TGrayStatData; IsGrayImage: Boolean);begin  if not ImageEmpty(Data) then    GrayStat(Data, GrayData, IsGrayImage);end;procedure TwoValues(var Data: TImageData; Threshold: LongWord);asm    push    ebp    push    esi    push    edi    push    ebx    push    edx    call    SetDataRegs32    pop     eax    mov     esi, 000ffffffh    mov     ebp, esi    not     ebp@@yLoop:    push    ecx@@xLoop:    cmp     [edi], al    jb      @@1    or      [edi], esi    jmp     @@2@@1:    and     [edi], ebp@@2:    add     edi, 4    loop    @@xLoop    pop     ecx    add     edi, ebx    dec     edx    jnz     @@yLoop@@Exit:    pop     ebx    pop     edi    pop     esi    pop     ebpend;procedure ImageTwoValues(var Data: TImageData; Threshold: LongWord);begin  if not ImageEmpty(Data) then    TwoValues(Data, Threshold);end;procedure ImageDynamTwoValues(var Data: TImageData; SubSize: Integer);var  Sub: TImageData;  GrayData: TGrayStatData;  x, y: Integer;begin  if ImageEmpty(Data) then Exit;  if SubSize <= 0 then  begin    GrayStat(Data, GrayData, True);    TwoValues(Data, GrayData.Average);    Exit;  end;  y := 0;  while y < Data.Height do  begin    x := 0;    while x < Data.Width do    begin      Sub := GetSubData(Data, x, y, SubSize, SubSize);      GrayStat(Sub, GrayData, True);      TwoValues(Sub, GrayData.Average);      Inc(x, SubSize);    end;    Inc(y, SubSize);  end;end;

    灰階化過程還是依照大多數映像灰階處理慣例,計算YUV色彩空間的Y分量作為灰階圖,公式為:

Y = 0.299 * R + 0.587 * G + 0.114 * B

    本文灰階過程使用了定點數處理,將上面公式中的常數乘上1024,加快了處理過程,虛擬碼為:

       Y = (306 * R + 601 * G + 117 * B + 512) >> 10

    代碼中的+512是做四捨五入,右移10位等於除以1024。

    映像灰階統計過程和映像灰階化過程採用了相同的原理和計算過程,只不過沒有改變映像,而是以計算結果作為256色灰階階數組的下標,增加該灰階階的個數而已。所有映像灰階統計指標都存放在TGrayStatData類型的結構中。見《Delphi影像處理 -- 資料類型及內部過程》。

    映像二值化過程是在映像灰階處理基礎上進行的,由於R、G、B三個分量相等,所以只要把任何其中一個與閥值比較即可:大於閥值為255,否則為0。因灰階映像素格式是32位的,所以過程中直接以0x00FFFFFF或RGB三個分量為255,以0xFF000000與RGB三個分量為0,映像二值化的黑白效果取決於閥值的大小。

    因有些映像的灰階分布不太均勻,為了加強映像的二值特徵,本文嘗試寫了一個映像動態分組二值化過程ImageDynamTwoValues,即將映像分組為一定大小的子圖,對各子圖分別進行灰階統計後,以該子圖的灰階平均值為閥值進行子圖的二值化,不過在測試過程中,發現如果子圖尺寸確定的不合適,各子圖之間有很明顯的區別,這對映像的二值分析顯然是不利的。

    至於映像的反色處理更簡單,直接用0xFFFFFF和RGB異或就成。

映像動態分組二值化例子:

var  jpg: TJPEGImage;  Data: TImageData;  GrayData: TGrayStatData;begin  jpg := TJPEGImage.Create;  jpg.LoadFromFile('D:\VclLib\GdiplusDemo\Media\20041001.jpg');  Canvas.Draw(0, 0, jpg);  Data := GetImageData(jpg);  ImageGray(Data);//  ImageTwoValues(Data);  ImageDynamTwoValues(Data, 128);  ImageDataAssignTo(Data, jpg);  Canvas.Draw(0, 0, jpg);  FreeImageData(Data);  jpg.Free;end;

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.