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、 addim_offset和 add中获得偏移量pMemory_o(最后两个而不是ebp在 read 情况下使用 as)。

但是,除了将像素写入新图像之外,您还希望从源文件中复制标题(以便查看者等将其视为位图);做一个memcpy(或适当的rep movsb) from pMemoryto pMemory_o, lengthim_offset来做到这一点。您还需要将第一行和第一列(我希望最后一行和最后一列也复制到它,这与第一行和第一列存在相同的问题:您无法获取某些边的周围像素)。一种“愚蠢”但有效的方法就是将旧图像的全部内容复制到新图像、标题、像素等,然后使用过滤器更改内部像素。

您创建和写入输出缓冲区的代码似乎是正确的;大概它现在写出一个正确长度的零/随机填充文件。

顺便说一句,一旦你做对了,你可以节省很多工作(大概效率是首先用汇编编写的原因之一?)使用加法和减法而不是乘法这么多:添加im_width跳转到下一个行,将其减去上一行,依此类推(您可能必须计算步幅而不是im_width直接使用,四舍五入到最接近的 32 位;如果您的示例图像不是 4 像素宽的倍数,您可能会看到由于未使用正确的步幅而导致的奇怪结果)。

其他人的有用参考:BITMAPFILEHEADER(从文件偏移量 0 开始)包含签名、文件大小(您的FileSize)和图像偏移量(im_offset),后面是BITMAPINFOHEADER,它包含宽度、高度和位深度。

于 2012-12-04T22:31:50.533 回答