带有线性插值的 x86 程序集衰落 bmp

标签 x86 interpolation intel bmp fading

任务是:将 24 bpp .BMP 图像的顶部淡化为白色,以便对每个像素的颜色进行线性插值
基于其距离的原始颜色和白色之间形成顶部边缘。距离的像素 >=
dist 不会褪色。

我创建了所有代码并试图淡化某些东西。似乎它只适用于 2 的幂的距离,所以 32,64,128 等......
我正在使用线性插值方程,我不知道为什么它不适用于其他数字。
有任何想法吗 ? :)。

示例图像:

before

褪色后,我越来越...
after

global fadetop

; parm.
%define     img         [ebp+8]
%define     width       [ebp+12]
%define     height      [ebp+16]
%define     dist        [ebp+20]
; local
%define     row_bytes      [ebp-4]
%define     dist_counter   [ebp-8]

fadetop:
; create stack frame
push    ebp
mov     ebp, esp
sub     esp, 8

; push register on stack
push    ebx
push    esi
push    edi

; calculate size of row 
mov     edx, width              
lea     edx, [edx+edx*2]        
add     edx, 3                  
and     edx, 0fffffffch         
mov     row_bytes, edx          

; address of datas -calculations to write pixels from top left corner
mov eax,height
mul edx
sub eax ,row_bytes
add eax,3
mov     esi, img
add esi,eax

;line couter 

xor edx, edx
mov dist_counter , edx
line:    
; pixel counter in line 
mov     edi, width

; index rexister 
xor     ebx, ebx

; INTERPOlATION STARTS NOW !!!


convert:                                  
movzx   eax, byte [esi+ebx+0]   ; take color 1
sub     eax, 255        ; sub white value
mov     ecx, dist_counter   
imul    ecx         ;color * actual position  
cdq
mov     ecx, dist       ; devide by full fade operation distance 
idiv    ecx
add     eax, 255        ; add 255 
mov     [esi+ebx+0], al     ;put in this place  

movzx   eax,byte [esi+ebx+1]    ; take color 2
sub     eax, 255
mov     ecx , dist_counter
mul     ecx
cdq
mov     ecx, dist
div     ecx
add     eax, 255
mov     [esi+ebx+1], al

movzx   eax,byte [esi+ebx+2]    ; take color 3
sub     eax, 255
mov     ecx , dist_counter
mul     ecx
cdq
mov     ecx, dist
div     ecx
add     eax, 255
mov     [esi+ebx+2], al

;________________________________________________________________
                    ;if still in one line 
    add     ebx, 3
    dec     edi
    jnz     convert

                        ; if next line 
sub     esi, row_bytes
mov     edx,dist_counter
inc     edx
mov     dist_counter,edx
mov     eax, dist
cmp     eax, edx      
jnz     line


    ; pop registers
    pop     edi
    pop     esi
    pop     ebx

    ; return trace         
    mov     esp, ebp
    pop     ebp
    ret

为那些想要运行它并尝试淡入淡出的人编写 C 代码:
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

void fadetop(void* img, int width, int height ,int dist );

int main (int argc, char** argv) {

    char* buff;

    if (argc != 3 ) {
        printf("Use file: %s [file]\n",argv[0]);
        return 1;

    }

    struct stat st;
    stat(argv[1], &st);

    buff = (char *) malloc(st.st_size);
    if (buff == NULL) {
        printf("Memory error!!\n");

        return 1;
    }

    int fd = open(argv[1], O_RDONLY, 0);
    if (fd == -1) {
        printf("File access error\n");
        free(buff);

        return 1;
    }

    int size = read(fd, buff, st.st_size);
    uint32_t offset    = *(uint32_t *) (buff + 0x0a);
    uint32_t width    = *(uint32_t *) (buff + 0x12);
    uint32_t height    = *(uint32_t *) (buff + 0x16);
    uint16_t bpp    = *(uint16_t *) (buff + 0x1c);

    if (bpp == 24) {
        int fd_out;
        printf("worked dist: %d , heigh: %d\n", atoi(argv[2]), height);
        fadetop(buff + offset, width , height , atoi(argv[2]) );
        fd_out = creat("fade.bmp", 0644);
        write(fd_out, buff, size);
        close(fd_out);

        printf("Image faded.\n");
    }
    else {
        printf("Invalid BMP\n");
    }

    close(fd);
    free(buff);

    return 0;
}

最佳答案

你的公式似乎是正确的:你有类似的东西

 color_new = (color-255)*dist_counter/dist + 255

虽然我建议更容易一些
color *= dist_counter/dist             ; scale original color over current dist
color += 256*(dist-dist_counter)/dist  ; add white, scaled over current dist

(至少在视觉上给出了相同的结果)。您的主要错误是,由于您正在添加当前值,因此您可能会溢出最大值 255。计算后,测试是否 color > 255如果是,则夹紧。

在组装中(无法测试,所以我希望我第一次就做对了):
    movzx   eax, byte [esi+ebx+0]   ; take color 1
    mov     ecx, dist_counter   
    imul    ecx         ;color * current position
    cdq
    mov     ecx, dist       ; devide by full fade operation distance 
    idiv    ecx

    mov     ebx, eax        ; save result so far

    mov     eax, dist       ; calculate 2nd half
    mov     ecx, eax
    sub     eax, dist_counter
    shl     eax, 8
    idiv    ecx

    add     eax, ebx
    test    ah, ah
    jz      skip_clamp
    mov     al, 255
skip_clamp:
    mov     [esi+ebx+0], al     ;put in this place

.. 为您的 3 个颜色组件重复。

一些可能有帮助的附加说明:
  • 我计算的第二行 color是每一行的常数。所以你只需要在你的 y 循环中计算它并将它保存在某个地方。
  • 您实际上不必为每个像素的每个颜色分量重复上述代码。只需重复 x 循环 3* width :
    mov     edi, width
    lea     edi, [edi+2*edi]
    
  • 您的起始位置似乎偏离了,不仅偏离了几行,而且偏离了几个像素。这部分是因为 add eax,3这里:
    sub eax ,row_bytes
    add eax,3
    

    但我不确定更大的错误来自哪里,因为您的填充计算是正确的。我无法测试你的实际代码,所以我用裸 C 语言实现了它,然后我得到了输入 ./a.out flower.bmp 400 的以下输出:

  • partially faded flower

    关于带有线性插值的 x86 程序集衰落 bmp,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30717303/

    相关文章:

    x86-64 - 使用索引寻址模式时的瓶颈

    virtual-machine - x86 中的 VMCALL 指令是否保存 guest CPU 状态

    c - 初学者内联程序集段错误

    linux-kernel - 如何将设备树 blob 添加到 Linux x86 内核启动?

    c++ - 我怎样才能最好地提高双三次插值算法的执行时间?

    python - 如何在 Python 中对未排序的 2D numpy 数组进行插值并将插值值与原始值进行比较?

    assembly - 近指针的隐式段寄存器是如何确定的?

    assembly - 如何设置 x86 分页?出现三重故障错误

    x86 - 模拟 x86 处理器——我应该如何开始?

    java - 处理(Java): How to make a plotted sine function look continuous instead of separate dots when the amplitude of the function increases