Mini-cours au groupe de travail "Images"
MMI, Lyon
Arnaud Chéritat

Retour


29 janvier 2016
2e partie, suite


Adoucissement intégré
Plutôt que de passer brusquement de pixels blancs à des pixels bleus quand une certaine quantité dépasse une certaine valeur, on peut se servir du ratio quantité/valeur pour décider d'une couleur intermédiaire.

Dans l'algo ci-dessous, on décide d'utiliser cette idée pour les pixels blancs: ceux qui étaient bleus précédemment le restent. Pour ceux qui sont blancs, on détermine un pourcentage (très approximatif) de bleu probable dans le pixel, indiquée par une variable br, pour brillance. Mais on n'interrompt pas encore l'itération ! En effet, il se pourrait que l'on soit passé à côté d'une partie de J qui n'apparaît qu'avec plus d'itérations, et qui est plus proche, donc pour laquelle on veut remplir sensiblement plus le pixel. Je décide de prendre le produit des valeurs de br obtenus à chaque itération, par analogie avec des évènements indépendants en proba.

Par contre quand la quantité de bleu est très proche du max, de sorte que la valeur [R,V,B] est exactement [0,0,255], on peut interrompre l'itération.

Ce n'est pas une méthode que j'ai beaucoup utilisée ni perfectionnée, on pourrait faire plus d'essais.

[...]

NONE=0 ; MAX=1 ; BASIN=2 ; DARK=3 ; OVERFLOW=4

def N2(z) : return z.real**2 + z.imag**2

def compute(j,i) :
  z = center + (j-width/2+(height/2-i)*1.0j)*pix_size
  k = 0
  reason = NONE
  r = thick*pix_size
  r_sq = r*r
  br_sq = 1.
  global nb_overflow,nb_max
  
  while True:
    if k>=max_iter : reason = MAX; break
    
    z = z - tau*1j*math.floor(0.5+z.imag/tau)
    
    if z.real>tip and math.log(r_sq)/2 > math.log(tau)+1.5-z.real : 
      d = z.imag / tau
      d = d-math.floor(d)
      d = math.fabs(d-0.5)
      d = max(0.0,0.25-d)
      d = d * tau
      d_sq = d*d
      br_sq *= min(1,d_sq/r_sq)
      if br_sq*255*255<1 : reason = DARK; break
    
    d_sq = N2(z-tip)
    br_sq *= min(1,d_sq/r_sq)
    if br_sq*255*255<1 : reason = DARK; break
    
    if z.real < seuil_bassin : reason = BASIN; break

    if z.real > seuil : break
    
    try : 
      z = cmath.exp(z-1.5)
      r_sq = r_sq * N2(z)
    except OverflowError: reason=OVERFLOW; break
    
    k += 1
    
  if reason==OVERFLOW : nb_overflow +=1 ; return [0,255,0]
  if reason==MAX :      nb_max +=1 ; return [255,0,0]
  if reason==DARK :     return [0,0,255]
  br = math.sqrt(br_sq)
  return [int(255*br),int(255*br),255]

[...]
L'instruction a *= b multiplie la valeur de a par la valeur de b et assigne le résultat à l'étiquette a. Résultat :


1 sample/pix

On n'est qu'en 1 échantillon par pixel ! Comme on le voit, l'adoucissement est très efficace. On voit aussi quelques transitions brusques : il faudrait réfléchir à leur cause et à leur mécanisme pour les supprimer ou les adoucir, comme nous l'avons fait les fois précédentes. Je décide de m'arrêter ici. Toutes ces approximations successive montrent ma démarche quand je travaille à la réalisation d'une image.

Pour conclure :


4 sample/pix

Je ne sais pas si ça a un sens de faire du suréchantillonnage et de l'adoucissement intégré, mais voilà le résultat, il me plaît assez bien (malgré la transition non résolue).


Nous n'avons pas couvert tout le matériel exposé ci-dessus pendant la 1e séance, une partie de la 2e séance fut consacrée à terminer cela. Par contre un exercice fut donné en fin de séance : essayer de représenter l'ensemble de Julia de :

f(z) = sin(z)/2


Séance suivante