3

BMP ファイルの内容を読み取り、画像に対して滑らかなデジタル フィルターを実行するプロジェクトに取り組んでいます。以下の私のコードはほとんど仕事をします。処理されたピクセルをどこに保存する必要があるのか​​ 、処理された画像をファイルに書き込む方法がわかりません。以下の私のコードはコメントアウトされているので、助けていただければ幸いです。

        .586
        .model      flat, stdcall
        option      casemap :none
        include     ..\masm32\include\windows.inc
        include     ..\masm32\include\user32.inc
        include     ..\masm32\include\kernel32.inc
        include     ..\masm32\macros\macros.asm
        include     ..\masm32\include\masm32.inc

        includelib  ..\masm32\lib\user32.lib
        includelib  ..\masm32\lib\kernel32.lib
        includelib  ..\masm32\lib\masm32.lib

        .data
FileName    db  "bitmap2.bmp", 0
filename    db  "bitmap_fil.bmp",0
errMsg      BYTE    "Cannot create file",0dh,0ah,0

hFile       HANDLE  ?
hwFile      HANDLE  ?

hMemory     HANDLE  ?       ;incoming data
pMemory     DWORD   ?

hMemory_o   HANDLE  ?       ;outgoing data
pMemory_o   DWORD   ?

ReadSize    DWORD   ?

bytesWritten    DWORD   ?
firstLine   DWORD   ?
FileSize    DWORD   ?
BDoff       DWORD   ?
BHSize      DWORD   ?
szTemp      byte    16 dup (0)  ;buffer for messages
szPrime     byte    "%08i", 0   ;message format string
szPrimeH    byte    "%08lx",0   ;message hexa format string
signature   DD  0
MEMORYSIZE      equ 65535   ;This is how much memory allocated
                        ; to store the file.
im_offset   dd  ?
im_width    dd  ?
im_height   dd  ?
bits_pix    dd  ?





    .code
;................................
show    MACRO   caption, value      
    print   SADD(caption)
    mov eax, value
    invoke  wsprintf, offset szTemp, offset szPrime, eax    ;converts eax into string
    print   offset szTemp                   ;print string
    print   SADD(13,10) 
    ENDM
;..................................

start:  

    invoke      CreateFile, addr FileName,GENERIC_READ,FILE_SHARE_READ,NULL, OPEN_EXISTING,     FILE_ATTRIBUTE_NORMAL, NULL
    mov      hFile, eax

;Allocate and lock the memory for incoming file.
    invoke      GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, MEMORYSIZE
    mov         hMemory, eax
    invoke      GlobalLock, hMemory
    mov         pMemory, eax

;Allocate and lock the memory for outgoing file.
    invoke      GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, MEMORYSIZE
    mov         hMemory_o, eax
    invoke      GlobalLock, hMemory_o
    mov         pMemory_o, eax


;Read file and save image parameters
    invoke      ReadFile, hFile, pMemory, MEMORYSIZE-1, addr ReadSize, NULL
    mov     esi, pMemory

    add     esi, 02     ;get filesize
    mov     edi, [esi]
    mov     FileSize,edi
    invoke      wsprintf, offset szTemp, offset szPrime, edi
    print       offset szTemp
    print       SADD(10,13)

    add         esi, 8      ; jump 8 bytes to get image offset
    mov     edi, [esi]  ; get image offset
    mov         im_offset,edi
    invoke      wsprintf, offset szTemp, offset szPrimeH, edi
    print       offset szTemp
    print       SADD(10,13)

    add     esi,8       ;jump 8 bytes to get image width
    mov     edi, [esi]  ; get image width       
    mov     im_width, edi   
    invoke      wsprintf, offset szTemp, offset szPrime, edi
    print       offset szTemp
    print       SADD(10,13)

    add     esi,4       ;jump 4 bytes to get image height
    mov     edi, [esi]  ; get image height
    mov     im_height, edi  
    invoke      wsprintf, offset szTemp, offset szPrime, edi
    print       offset szTemp
    print       SADD(10,13)

    add     esi,4       ;jump 4 bytes to get color plane
    mov     ebx, [esi]  
    shr     ebx,16      ; get color plane and bit-pix
    mov     bits_pix,ebx ;
    print       SADD("bit-per-pix ")
    invoke      wsprintf, offset szTemp, offset szPrime, ebx
    print       offset szTemp
    print       SADD(10,13)

    mov     ebp, pMemory    ; get ready to start processing the image
    add     ebp, im_offset  ; esi now points to the first pix

;filtering process
;leave first row and first column and last row and last column untouched.

    mov     esi,1       ; esi is the row counter
    mov     edi,1       ; edi is the column counter


proc_pix:
    ;show       "current column is: ",edi
    ;show       "current row is: ",esi
    xor     ebx,ebx     ; ebx = 0 ebx will accumulate intermediate values for averaging
    mov     eax, im_width   ; eax is the pointer to the pixel
    mul     esi
    add     eax,edi     
    add     ebx, [ebp+eax]  ;get the pixel(I,J) 

    mov     eax, im_width
    add     esi,1       ;next row (I+1)
    mul     esi
    add     eax,edi     
    add     ebx, [ebp+eax]  ;get the pixel(I+1,J) 


    mov     eax, im_width
    sub     esi,2       ; prev row (I-1)
    mul     esi
    add     eax,edi     
    add     ebx, [ebp+eax]  ;get the pixel(I-1,J) 

    add     esi,1       ;back to the current row

    add     edi,1       ;get next column (J+1)
    mov     eax, im_width
    mul     esi
    add     eax,edi     
    add     ebx, [ebp+eax]  ;get the pixel(I,J+1) 


    sub     edi,2       ; get prev column (J-1)
    mov     eax, im_width
    mul     esi
    add     eax,edi     
    add     ebx, [ebp+eax]  ;get the pixel(I,J-1) 

    add     edi,1       ;back current column
    xor     edx, edx    ;clear upper part dividend
    mov     eax, ebx    ; move data to eax to divide
    mov     ecx, 5  
    div     ecx     ;do the average (div 5)>>> result in eax

; where should I store the processed pixels?

    inc     edi     ; do the next column
    cmp     edi, im_width   
    jl      proc_pix

    inc             esi     ; do the next row
    mov     edi,1       ; skip the first column 
    cmp     esi, im_height  
    jl      proc_pix

;....................................................................................


new_file: 
    invoke      CreateFile,ADDR filename, GENERIC_WRITE, NULL, NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0
    mov         hwFile,eax      ; save file handle

; handling of error if invalid file handle
    cmp         eax,INVALID_HANDLE_VALUE
    jne     writef
    invoke      StdOut, addr errMsg ; Display error message
    jmp         QuitNow

writef: invoke      WriteFile, hwFile, pMemory_o, FileSize, ADDR bytesWritten, 0        


QuitNow:
    invoke      GlobalUnlock, pMemory
    invoke      GlobalUnlock, pMemory_o
    invoke      GlobalFree, hMemory
    invoke      CloseHandle, hFile
    invoke      CloseHandle, hwFile
    invoke      ExitProcess, NULL
    end         start

;finish
4

1 に答える 1

2

出力用のバッファーは既にあります。それを保存するには、そのバッファへのオフセットを把握する必要があるだけのようです。フィルタリングしたピクセルが (I, J) で、 から読み取った場合pMemory + im_offset + J * im_width + I、それを に書き出す必要がありますpMemory_o + im_offset + J * im_width + I。(余談ですが、コードはピクセルあたり 8 ビットを想定しているようです。8bpp 以外の画像ファイルで予期しない動作を避けるために、それを明示的に確認し、そうでない場合はエラーで終了することをお勧めします。)

宛先ピクセルを正しく書き込むには、読み取りと同じ行/列の乗算を実行して、 でオフセットを取得しeax、 add im_offset、および add に追加しますpMemory_o(読み取りの場合のように使用する代わりに、最後の 2 つebp)。

ただし、ピクセルを新しい画像に書き込むだけでなく、ソース ファイルからヘッダーをコピーすることも必要です (これにより、ビューアなどがビットマップとして表示されます)。それを行うには、memcpy(または適切なrep movsb) from pMemoryto pMemory_o、 lengthim_offsetを実行します。また、最初の行と列をコピーする必要があります (そして、最後の行と列もコピーする必要があります。これには、最初と同じ問題があります。一部の側面の周囲のピクセルを取得できません)。「ばかげた」が効果的な方法は、古い画像の内容全体を新しいヘッダー、ピクセル、およびすべてにコピーし、フィルターで内部のピクセルを変更することです。

出力バッファを作成して書き込むコードは正しいようです。おそらく、正しい長さのゼロ/ランダムで満たされたファイルを書き出すようになりました。

余談ですが、一度正しく理解できれば、多くの作業を節約できます (おそらく、最初にアセンブリで記述する理由の 1 つは効率性でしょうか?)。乗算の代わりに加算と減算を使用しますim_width。行、前の行からの減算など (im_width直接使用する代わりにストライドを計算し、最も近い 32 ビットに切り上げる必要がある場合があります。サンプル画像の幅が 4 ピクセルの倍数でない場合は、正しいストライドを使用していないため、奇妙な結果になります)。

後続の他のユーザーにとって有用なリファレンス:署名、ファイル サイズ (your )、およびイメージ オフセット ( ) を含むBITMAPFILEHEADER (ファイル オフセット 0 から開始)。その後に、幅、高さなどの情報を含むBITMAPINFOHEADERが続きます。ビット深度。FileSizeim_offset

于 2012-12-04T22:31:50.533 に答える