我正在开发一个项目,该项目读取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
答案 0 :(得分:2)
您已有输出缓冲区;看来,你只需要找出存储它的缓冲区。如果您过滤的像素是(I,J),您从pMemory + im_offset + J * im_width + I
读取,则需要将其写入pMemory_o + im_offset + J * im_width + I
。 (顺便说一句,你的代码似乎假定每像素8位;你可能想要明确地检查它,如果不是这样就退出并且错误,以避免非8bpp图像文件出现意外行为。)
要正确写入目标像素,您可以执行与读取相同的行/列乘法,以获得eax
中的偏移量,添加im_offset
,并将其添加到pMemory_o
(最后两个而不是像阅读案例中那样使用ebp
。
除了将像素写入新图像之外,您还希望从源文件中复制标题(以便查看器等将其视为位图);从memcpy
到rep movsb
{长度pMemory
执行pMemory_o
(或适当的im_offset
)来做到这一点。您还需要复制第一行和第一行(并且,我希望,最后一行和列也会出现问题,这与第一行和第一行的问题相同:您无法获得某些边的周围像素)。一个“愚蠢”但有效的方法就是将旧图像的全部内容复制到新的,标题,像素和所有内容,然后只需用过滤器更改内部像素。
创建和编写输出缓冲区的代码似乎是正确的;据推测,它现在会写出一个正确长度的零/随机填充文件。
顺便说一句,一旦你弄清楚它,你可以节省大量的工作(可能效率是首先在汇编中写入的原因之一?),使用加法和减法而不是相乘:添加{ {1}}跳转到下一行,将其减去前一行,等等(您可能需要计算一个步幅而不是直接使用im_width
,向上舍入到最近的32位;如果您的样本图像不是4像素宽的倍数,由于没有使用正确的步幅,您可能会看到奇怪的结果。)
跟随其他人的有用参考:BITMAPFILEHEADER(从文件偏移0开始),其中包含签名,文件大小(您的im_width
)和图像偏移(FileSize
),其后是BITMAPINFOHEADER,其中包含宽度,高度和位深度等信息。