filtre dithering

Pour discuter de l'assembleur
manababel
Messages : 135
Inscription : jeu. 14/mai/2020 7:40

filtre dithering

Message par manababel »

Bonjour

Voici quelques filtres de "dithering".
Se type de filtre permet de diminuer le nombre de couleurs dans une image en créant des "trames de points"donnant l'impression d'avoir plus de couleur qu'il n'y en a.

Dans le programme, vous pouvez choisir le nombre de couleurs par canal (r, g, b).
Il se peut que le nombre de couleurs sélectionnées soit déférent de la réalité.

Il y a 12 filtres écrits en purebasic, le 13e n'est qu'une conversion du filtre "Fake-Floyd" en ASM.

Code : Tout sélectionner

EnableExplicit

Global Dim Reg_memory.q(4*344)

; charge une image et la convertie en 32bit
;-------------------------------------------------------------------
Procedure load_image(nom,file$)
  Protected source_p , cible_p , s.q
  Protected lg.q , ht.q , taille.q , depth.q

  LoadImage(nom,file$)
  If Not IsImage(nom) : ProcedureReturn 0 : EndIf
   
  StartDrawing(ImageOutput(nom))
  source_p = DrawingBuffer()
  ht = ImageHeight(nom)
  lg = ImageWidth(nom)
  Depth=OutputDepth()
  StopDrawing()

  If Depth=24
    taille=lg*ht
    cible_p=AllocateMemory(taille*4)
    Dim save.q(4)
    s=@save()
    EnableASM
      !mov rax,[p.v_s]
      !mov [rax],rcx
      !mov [rax+8],rdx
      !mov [rax+16],r8
      !mov rcx,[p.v_source_p]
      !mov rdx,[p.v_cible_p]
      !mov r8,[p.v_taille]
      !sub r8,1 ; <---------------- ????
      !copy_boucle24:
        !mov eax,[rcx]     
        !mov [rdx],eax
        !add rcx,3
        !add rdx,4
        !dec r8
       !jnz copy_boucle24
      !mov rax,[p.v_s]
      !mov rcx,[rax]
      !mov rdx, [rax+8]
      !mov r8,[rax+16]
    DisableASM
    FreeArray(save())
   
    FreeImage(nom) ; supprime l'image 24bits
    CreateImage(nom,lg,ht,32)
    StartDrawing(ImageOutput(nom))
    source_p = DrawingBuffer()
    StopDrawing()
    CopyMemory( cible_p , source_p , taille*4 )
    FreeMemory(cible_p)
  EndIf
 
  ProcedureReturn 1
EndProcedure




; partie du programme à modifier pour adapter se programme au votre
; convertie les "IDs" des images en pointer d'adresse
; test si les images sont en 32bits et de la meme taille
;-------------------------------------------------------------------

Macro sp(source,cible)
  Protected Depth.q , lg.q , ht.q , lg1.q , ht1.q , taille.q
  Protected cible_p.q , source_p.q

  StartDrawing(ImageOutput(cible))
  cible_p = DrawingBuffer()
  ht1 = ImageHeight(cible)
  lg1 = ImageWidth(cible)
  Depth=OutputDepth()
  StopDrawing()
  If depth<>32 : ProcedureReturn : EndIf

  StartDrawing(ImageOutput(source))
  source_p = DrawingBuffer()
  ht = ImageHeight(source)
  lg = ImageWidth(source)
  Depth=OutputDepth()
  StopDrawing()
  If depth<>32 : ProcedureReturn : EndIf

  If lg<>lg1 Or ht<>ht1 : ProcedureReturn : EndIf

  taille = lg * ht
EndMacro

Macro clampRGB(r,g,b)
  If r<0:r=0:EndIf
  If g<0:g=0:EndIf
  If b<0:b=0:EndIf
  If r>255:r=255:EndIf
  If g>255:g=255:EndIf
  If b>255:b=255:EndIf
EndMacro

Macro returnRGB(pixel,r,g,b)
    r=(pixel & $ff0000)>>16
    g=(pixel & $ff00)>>8
    b=(pixel & $ff)
  EndMacro

;-------------------------------------------------------------------
; sauvegarde de registres
Macro Save_reg()
  s=@reg_memory()
  EnableASM
  !mov rax,[p.v_s]
  !mov [rax+000],rbx
  !mov [rax+008],rcx ;
  !mov [rax+016],rdx ;
  !mov [rax+024],rsi
  !mov [rax+032],rdi
  !mov [rax+040],r8 ;
  !mov [rax+048],r9 ;
  !mov [rax+056],r10
  !mov [rax+064],r11
  !mov [rax+072],r12
  !mov [rax+080],r13
  !mov [rax+088],r14
  !mov [rax+096],r15

  !movdqu [rax+104],xmm0 ;
  !movdqu [rax+120],xmm1 ;
  !movdqu [rax+136],xmm2 ;
  !movdqu [rax+152],xmm3 ;
  !movdqu [rax+168],xmm4
  !movdqu [rax+184],xmm5
  !movdqu [rax+200],xmm6
  !movdqu [rax+216],xmm7
  !movdqu [rax+232],xmm8
  !movdqu [rax+248],xmm9
  !movdqu [rax+264],xmm10
  !movdqu [rax+280],xmm11
  !movdqu [rax+296],xmm12
  !movdqu [rax+312],xmm13
  !movdqu [rax+328],xmm14
  !movdqu [rax+344],xmm15
  DisableASM
EndMacro

Macro Rest_Reg()
; restore les registres
  s=@reg_memory()
  EnableASM
  !mov rax,[p.v_s]
  !mov rbx,[rax+000]
  !mov rcx,[rax+008]
  !mov rdx,[rax+016]
  !mov rsi,[rax+024]
  !mov rdi,[rax+032]
  !mov r8,[rax+040]
  !mov r9,[rax+048]
  !mov r10,[rax+056]
  !mov r11,[rax+064]
  !mov r12,[rax+072]
  !mov r13,[rax+080]
  !mov r14,[rax+088]
  !mov r15,[rax+096]

  !movdqu xmm0,[rax+104] ;
  !movdqu xmm1,[rax+120] ;
  !movdqu xmm2,[rax+136] ;
  !movdqu xmm3,[rax+152] ;
  !movdqu xmm4,[rax+168]
  !movdqu xmm5,[rax+184]
  !movdqu xmm6,[rax+200]
  !movdqu xmm7,[rax+216]
  !movdqu xmm8,[rax+232]
  !movdqu xmm9,[rax+248]
  !movdqu xmm10,[rax+264]
  !movdqu xmm11,[rax+280]
  !movdqu xmm12,[rax+296]
  !movdqu xmm13,[rax+312]
  !movdqu xmm14,[rax+328]
  !movdqu xmm15,[rax+344]
  DisableASM

EndMacro
;-------------------------------------------------------------------





Macro Filter_Floyddither_Macro_read(pos)
  var=PeekL(pos)
  returnRGB(var,r,g,b)
  nr = tab(r)
  ng = tab(g)
  nb = tab(b)
  PokeL(pos,(nr<<16+ng<<8+nb))
  err=(r-nr)
  erg=(g-ng)
  erb=(b-nb)
EndMacro

Macro Filter_Floyddither_Macro_write(npos,v1,v2)
  var=PeekL(npos)
  returnRGB(var,r,g,b)
  r=(r+((err*v1)>>v2))
  g=(g+((erg*v1)>>v2))
  b=(b+((erb*v1)>>v2))
  ClampRGB(r,g,b)
  PokeL(npos,(r<<16+g<<8+b))
EndMacro


Procedure Filter_Floyddither(source,cible,opt1,opt2)
  
  Define m,i,lg2,x,y,pos
  Define var,r,g,b,nr,ng,nb,err,erg,erb
  Define pix,taille2,s
  
  sp(source,cible)

  If opt2<1 : opt2=1: EndIf ; evite une division par 0
  If opt2>16 : opt2=16:EndIf
  m=256/opt2
  opt2=opt2+1
  Dim tab.q(256)
  For i=0 To 255
    tab(i) = ((i*opt2)>>8)*m
    If tab(i)>255 : tab(i) = 255:EndIf
    ;if tab(i)>127 : tab(i)=255 : Else : tab(i)=0 : EndIf
  Next
  
  lg1 = lg * 4
  lg2 = lg1 * 2
  
  ;copy(source_p,cible_p,long*4)
  CopyMemory(source_p, cible_p, taille*4)
  Select opt1
      
      ;-- method Floyd-Steinberg
      Case 0
        For y=0 To ht-2
          For x=1 To lg-2
            pos=cible_p+((lg*y)+x)*4
            Filter_Floyddither_Macro_read(pos)
            Filter_Floyddither_Macro_write(pos+4,7,4)
            Filter_Floyddither_Macro_write(pos+lg1-4,3,4)
            Filter_Floyddither_Macro_write(pos+lg1,5,4)
            Filter_Floyddither_Macro_write(pos+lg1+4,1,4)
          Next
        Next 
        
        ;-- method Fake-Floyd
        Case 1
          For y=0 To ht-2
            For x=1 To lg-2
              pos=cible_p+((lg*y)+x)*4
              Filter_Floyddither_Macro_read(pos)
              Filter_Floyddither_Macro_write(pos+4,3,3)
              Filter_Floyddither_Macro_write(pos+lg1-4,3,3) 
              Filter_Floyddither_Macro_write(pos+lg1+0,2,3)             
            Next
          Next    
        
        ;-- method Sierra Lite
        Case 2
          For y=0 To ht-2
            For x=1 To lg-2
              pos=cible_p+((lg*y)+x)*4
              Filter_Floyddither_Macro_read(pos) 
              Filter_Floyddither_Macro_write(pos+4,2,2)
              Filter_Floyddither_Macro_write(pos+lg1-4,1,2)
              Filter_Floyddither_Macro_write(pos+lg1,1,2)             
            Next
          Next 
          
        ;-- method Atkinson
        Case 3
          For y=0 To ht-3
            For x=1 To lg-3
              pos=cible_p+((lg*y)+x)*4
              Filter_Floyddither_Macro_read(pos)
              Filter_Floyddither_Macro_write(pos+4,1,3)
              Filter_Floyddither_Macro_write(pos+8,1,3)
              Filter_Floyddither_Macro_write(pos-4+lg1,1,3)
              Filter_Floyddither_Macro_write(pos+lg1,1,3)
              Filter_Floyddither_Macro_write(pos+4+lg1,1,3)
              Filter_Floyddither_Macro_write(pos+lg2,1,3)
            Next
          Next
          
        ;-- method Two Sierra
        Case 4
          For y=0 To ht-3
            For x=2 To lg-2
              pos=cible_p+((lg*y)+x)*4
              Filter_Floyddither_Macro_read(pos)
              Filter_Floyddither_Macro_write(pos+4,4,4)
              Filter_Floyddither_Macro_write(pos+8,3,4)
              Filter_Floyddither_Macro_write(pos-8+lg1,1,4)
              Filter_Floyddither_Macro_write(pos-4+lg1,2,4)
              Filter_Floyddither_Macro_write(pos+lg1,3,4)
              Filter_Floyddither_Macro_write(pos+4+lg1,2,4)
              Filter_Floyddither_Macro_write(pos+8+lg1,1,4)
            Next
          Next
          
        ;-- method Burves
        Case 5
          For y=0 To ht-3
            For x=2 To lg-2 
              pos=cible_p+((lg*y)+x)*4
              Filter_Floyddither_Macro_read(pos)
              Filter_Floyddither_Macro_write(pos+4,8,5)
              Filter_Floyddither_Macro_write(pos+8,4,5)
              Filter_Floyddither_Macro_write(pos-8+lg1,2,5)
              Filter_Floyddither_Macro_write(pos-4+lg1,4,5)
              Filter_Floyddither_Macro_write(pos+lg1,8,5)
              Filter_Floyddither_Macro_write(pos+4+lg1,4,5)
              Filter_Floyddither_Macro_write(pos+8+lg1,2,5)
            Next
          Next
                    
        ;-- method Sierra
        Case 6
          For y=0 To ht-3
            For x=2 To lg-3 
              pos=cible_p+((lg*y)+x)*4
              Filter_Floyddither_Macro_read(pos)
              Filter_Floyddither_Macro_write(pos+4,5,5)
              Filter_Floyddither_Macro_write(pos+8,3,5)
              Filter_Floyddither_Macro_write(pos-8+lg1,2,5)
              Filter_Floyddither_Macro_write(pos-4+lg1,4,5)
              Filter_Floyddither_Macro_write(pos+lg1,8,5)
              Filter_Floyddither_Macro_write(pos+4+lg1,4,5)
              Filter_Floyddither_Macro_write(pos+8+lg1,2,5)
              Filter_Floyddither_Macro_write(pos+lg2-4,2,5)
              Filter_Floyddither_Macro_write(pos+lg2,3,5)
              Filter_Floyddither_Macro_write(pos+lg2+4,2,5)
            Next
          Next 
          
      
        ;-- method Jarvis ( approx )
        Case 7
          For y=0 To ht-3
            For x=2 To lg-3
              pos=cible_p+((lg*y)+x)*4
              Filter_Floyddither_Macro_read(pos)
              Filter_Floyddither_Macro_write(pos+4,2387,14) ;7/48 ( 2387 = 7 x 341 )
              Filter_Floyddither_Macro_write(pos+8,1705,14) ;5/48
              Filter_Floyddither_Macro_write(pos-8+lg1,1023,14);3/48
              Filter_Floyddither_Macro_write(pos-4+lg1,1705,14);5/48
              Filter_Floyddither_Macro_write(pos+lg1,7*390,14);7/48
              Filter_Floyddither_Macro_write(pos+4+lg1,1705,14);5/48
              Filter_Floyddither_Macro_write(pos+8+lg1,1023,14);3/48
              Filter_Floyddither_Macro_write(pos+lg2-8,341,14);1/48
              Filter_Floyddither_Macro_write(pos+lg2-4,1023,14);3/48
              Filter_Floyddither_Macro_write(pos+lg2,1705,14);5/48
              Filter_Floyddither_Macro_write(pos+lg2+4,1023,14);3/48
              Filter_Floyddither_Macro_write(pos+lg2+8,341,14);1/48
            Next
          Next 
          
        ;-- method Stuki ( approx )
        Case 8
          For y=0 To ht-3
            For x=2 To lg-3
              pos=cible_p+((lg*y)+x)*4
              Filter_Floyddither_Macro_read(pos)
              Filter_Floyddither_Macro_write(pos+4,3120,14) ;8/42 ( 3120 = 7 x 390 )
              Filter_Floyddither_Macro_write(pos+8,1560,14) ;4/42
              Filter_Floyddither_Macro_write(pos-8+lg1,780,14);2/42
              Filter_Floyddither_Macro_write(pos-4+lg1,1560,14);4/42
              Filter_Floyddither_Macro_write(pos+lg1,3120,14);8/42
              Filter_Floyddither_Macro_write(pos+4+lg1,1560,14);4/42
              Filter_Floyddither_Macro_write(pos+8+lg1,780,14);2/42
              Filter_Floyddither_Macro_write(pos+lg2-8,390,14);1/42
              Filter_Floyddither_Macro_write(pos+lg2-4,780,14);2/42
              Filter_Floyddither_Macro_write(pos+lg2,1560,14);4/42
              Filter_Floyddither_Macro_write(pos+lg2+4,780,14);2/42
              Filter_Floyddither_Macro_write(pos+lg2+8,390,14);1/42
            Next
          Next 
          
        ;-- method Shiau Fan V1
        Case 9
          For y=0 To ht-2
            For x=3 To lg-2
              pos=cible_p+((lg*y)+x)*4
              Filter_Floyddither_Macro_read(pos) 
              Filter_Floyddither_Macro_write(pos+4,8,4)
              Filter_Floyddither_Macro_write(pos+lg1-12,1,4)
              Filter_Floyddither_Macro_write(pos+lg1-8,1,4)  
              Filter_Floyddither_Macro_write(pos+lg1-4,2,4) 
              Filter_Floyddither_Macro_write(pos+lg1,4,4)
            Next
          Next 
          
        ;-- method Shiau Fan V2 
        Case 10
          For y=0 To ht-2
            For x=2 To lg-2
              pos=cible_p+((lg*y)+x)*4
              Filter_Floyddither_Macro_read(pos) 
              Filter_Floyddither_Macro_write(pos+4,4,3)
              Filter_Floyddither_Macro_write(pos+lg1-8,1,3)  
              Filter_Floyddither_Macro_write(pos+lg1-4,1,3) 
              Filter_Floyddither_Macro_write(pos+lg1,2,3)
            Next
          Next 
          
        ;-- method omni directional ( approx )
        Case 11
          For y=1 To ht-2
            For x=1 To lg-2
              pos=cible_p+((lg*y)+x)*4
              Filter_Floyddither_Macro_read(pos) 
              Filter_Floyddither_Macro_write(pos-lg1-4,1638,14);1/10
              Filter_Floyddither_Macro_write(pos-lg1,3277,14);2/10
              Filter_Floyddither_Macro_write(pos-lg1+4,1638,14);1/10
              Filter_Floyddither_Macro_write(pos-4,1638,14);1/10
              Filter_Floyddither_Macro_write(pos+4,1638,14);1/10
              Filter_Floyddither_Macro_write(pos+lg1-4,1638,14);1/10
              Filter_Floyddither_Macro_write(pos+lg1,3277,14);2/10
              Filter_Floyddither_Macro_write(pos+lg1+4,1638,14);1/10
            Next
          Next 
          
       
          
          
        ;-- ASM  method Fake-Floyd
        Case 12
          pix=@tab()
          taille2=(taille*4)-lg1
          EnableASM 
          Save_Reg()
          !mov rdi,[p.v_cible_p]
          !mov r10,[p.v_taille2]
          !mov rcx,[p.v_pix]
          
          !xor r9,r9
          !pxor xmm15,xmm15
                    
          !Filter_Floyddither_saut:          
            
            !movd xmm2,[rdi] ; var=PeekL(pos)
            !xor rax,rax
            !xor rbx,rbx
            !mov bl,[rdi+2]
            !mov al,[rcx+rbx*8] ; nr = tab(r)
            !shl rax,8
            !mov bl,[rdi+1]
            !mov al,[rcx+rbx*8] ; ng = tab(g)
            !shl rax,8
            !mov bl,[rdi+0]
            !mov al,[rcx+rbx*8] ; nb = tab(b)
            !mov [rdi],eax ; PokeL(pos,(nr<<16+ng<<8+nb))
            
            !movd xmm1,eax
            !punpcklbw xmm2,xmm15 ; 8 -> 16 ; rgb
            !punpcklbw xmm1,xmm15 ; 8 -> 16 ; new_rgb
            
            !psubsw xmm2,xmm1 ; err=(r-nr) ; err_rgb
            
            !movdqu xmm3,xmm2
            !paddsw xmm3,xmm3
            !paddsw xmm3,xmm2; err*3
            !psraw xmm3,3 ; / 8
            
            !movd xmm1,[rdi+4]
            !punpcklbw xmm1,xmm15
            !paddsw xmm1 , xmm3 ; r=r+(err*3)/8
            !packuswb xmm1,xmm15
            !movd [rdi+4],xmm1
            
            !add rdi,[p.v_lg1]
            
            !movd xmm1,[rdi-4]
            !punpcklbw xmm1,xmm15
            !paddsw xmm1 , xmm3 ; r=r+(err*3)/8
            !packuswb xmm1,xmm15
            !movd [rdi-4],xmm1
            
            !movd xmm1,[rdi]
            !punpcklbw xmm1,xmm15
            !paddsw xmm2,xmm2 ; err*2
            !psraw xmm2,3 ; / 8
            !paddsw xmm1 , xmm2 ; r=r+(err*2)/8
            !packuswb xmm1,xmm15
            !movd [rdi],xmm1
            
            !sub rdi,[p.v_lg1]
            !add rdi,4
            
            !add r9,4
            !cmp r9,r10
          !jb Filter_Floyddither_saut
            
          DisableASM
          Rest_Reg()
      EndSelect
      FreeArray(tab())
      
    EndProcedure
    
;-------------------------------------------------------------------
    


;------------------------------------------------------------------
;-- programme
UseJPEGImageDecoder()
UsePNGImageDecoder()
Global imgx=1200
Global imgy=800


If OpenWindow(0, 0, 0, imgx, imgy, "Floyddither", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  Define source.q , cible.q , t.q , file$ , i , var1 , var2 , tx$
  
  ComboBoxGadget(1, imgx/4, 1, imgx/4, 24)
  Restore DATA_NOM
  tx$=""
  While tx$<>"***END***"
    Read.s tx$
    If tx$<>"***END***"
      AddGadgetItem(1, -1, tx$)
    EndIf
  Wend
  
  ComboBoxGadget(2, imgx/4+imgx/4, 1, imgx/4, 24)
  For i=2 To 16
    tx$=Str(i)
    AddGadgetItem(2, -1, "Nombre de couleurs par canal "+tx$)
  Next
  

   file$ = OpenFileRequester("Image","","",0)
   source=10
   cible=20
   
   If Load_Image(source,file$) = 0 ; <- commande differente de "LOADIMAGE"
     MessageRequester("erreur", "image non chargeé" ,#PB_MessageRequester_Ok )
     End
   EndIf
   
   ResizeImage(source,imgx,imgy,#PB_Image_Smooth)
   
   CreateImage(cible,imgx,imgy,32) ; l'image doit entre en mode 32bits
      
   Repeat
     Select WaitWindowEvent()

        Case  #PB_Event_CloseWindow
          End
        Case  #PB_Event_Gadget
         
          Select EventGadget()
             
            Case 1,2
              var1=GetGadgetState(1)
              var2=GetGadgetState(2)+1
              t=ElapsedMilliseconds()
              Filter_Floyddither(source,cible,var1,var2)
              t=ElapsedMilliseconds()-t
          EndSelect
      EndSelect
       
       StartDrawing(WindowOutput(0))
       DrawImage(ImageID(cible),0,50)
       DrawText(5,50,"temps : "+Str(t))
       DrawText(5,5,Str(GetGadgetState(1))+"     ")
       StopDrawing()
   
    ForEver
  EndIf
  
  ;-------------------------------------------------------------------
  DataSection
  DATA_NOM:
    Data.s "Floyd-Steinberg"
    Data.s "Fake-Floyd"
    Data.s "Sierra Lite"
    Data.s "Atkinson"
    Data.s "Two Sierra"
    Data.s "Burves"
    Data.s "Sierra"
    Data.s "Jarvis ( approx )"
    Data.s "Stuki ( approx )"
    Data.s "Shiau Fan V1"
    Data.s "Shiau Fan V2"
    Data.s "omni directional ( approx )"
    Data.s " ***ASM*** Fake-Floyd"
    Data.s "***END***"
  EndDataSection