et utilisés parfois dans des logiciels répandus, comme DoubleCommander (gestionnaire de fichiers écrit en Lazarus) et son "viewer" de fichiers image ?
Bonsoir,
Suite à la lecture intéressante d'un petit bout du "Fundamentals of Computer Graphics" que je vous résume ainsi (traduction Google) :
- Lorsqu'on rétrécit l'image, on dimensionne le filtre en fonction de l'espacement des échantillons de sortie (rayon 3 sur la figure 9.39).
- Lorsqu'on agrandit l'image, la taille du filtre est déterminée par l'espacement des échantillons d'entrée (rayon 1 de la figure 9.39).
et la figure 9.39 c'est elle :
je me suis donc dit que j'allais tester le fonctionnement d'un module écrit en Pascal, qui embarque 7 filtres :
1 2 3 4 5 6 7 8 9 10 11 12 13
| const
ResampleFilters: array[0..6] of record
Name : string; // Filter name
Filter: TFilterProc;// Filter implementation
Width : Single; // Suggested sampling width/radius
end = (
(Name: 'Box'; Filter: BoxFilter; Width: 0.5),
(Name: 'Triangle'; Filter: TriangleFilter; Width: 1.0),
(Name: 'Hermite'; Filter: HermiteFilter; Width: 1.0),
(Name: 'Bell'; Filter: BellFilter; Width: 1.5),
(Name: 'B-Spline'; Filter: SplineFilter; Width: 2.0),
(Name: 'Lanczos3'; Filter: Lanczos3Filter; Width: 3.0),
(Name: 'Mitchell'; Filter: MitchellFilter; Width: 2.0)); |
La seule aide dont on dispose, c'est 4 lignes de commentaires juste avant le prototype de la méthode :
1 2 3 4 5 6
| // Interpolator:
// Src: Source bitmap
// Dst: Destination bitmap
// filter: Weight calculation filter
// fwidth: Relative sample radius
procedure Stretch(Src, Dst: TBitmap; filter: TFilterProc; fwidth: single); |
J'ai regardé comment les autres utilisent cette procédure Stretch, ça a l'air un peu pifométrique : j'ai trouvé
Stretch(src, dst, ResampleFilters[5].Filter, ResampleFilters[5].Width);
et aussi
Stretch(src, dst, ResampleFilters[2].Filter, ResampleFilters[2].Width);
ce qui laisse supposer que le codeur de l'appel a estimé que le mieux était d'utiliser la valeur définie par défaut et basta.
Et comme ce comportement me chagrinait, j'ai essayé de tester avec différentes valeurs pour chaque filtre, et c'est là que les ennuis commencent :
1- pour me simplifier la vie, j'ai d'abord tenté avec une bête boucle genre
1 2 3 4 5
| for i := 0 to 6 do begin // parcours de la liste des filtres
for j := 0 to 4 do begin // 5 valeurs de radius
Stretch(Src, Dst, ResampleFilters[i].Filter, j);
end; // for j
end; // for i |
mais ça partait tout de suite en "Access Violation"...
Je vous la fais courte (car j'y ai passé un certain temps...) : certains filtres ne supportent pas de commencer avec un radius à 0, et c'est même plus vicieux que ça, regardez comment je m'en suis sorti :
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| for i := 0 to 6 do begin
for j := 0 to 4 do begin // 5 valeurs de radius
for k := 1 to 2 do begin
// j=0 radius=0.5 & 1 - j=1 radius=1.5 & 2 - j=2 radius=2.5 & 3 - etc.
radius := (k * 0.5) + j;
// les 3 premiers filtres fonctionnent à partir de 0.5
if i = 3 then radius := radius + 1.0; // démarre à 1.5 et continue
if i = 4 then radius := radius + 1.5; // démarre à 2.0 et continue
if i = 5 then radius := radius + 2.5; // démarre à 3.0 et continue
if i = 6 then radius := radius + 1.5; // démarre à 2.0 et continue
Stretch(Src, Dst, ResampleFilters[i].Filter, radius);
end; // for k
end; // for j
end; // for i |
On dirait que ce qui est noté dans le code comme "Suggested sampling width/radius" est en fait la valeur minimum à employer. Admettons. Mais alors, si on regarde un filtre en détail,
1 2 3 4 5
| function TriangleFilter(Value: Single): Single;
begin
if (Value < 0.0) then Value := -Value; // si la valeur est négative on la transforme en positive
if (Value < 1.0) then Result := 1.0 - Value else Result := 0.0;
end; |
pourquoi ne puis-je pas lui passer 0 (zéro) ?
Mais ce n'est pas le plus important. Ce qui l'est,
2- c'est que une fois ma boucle au point, je l'ai exécutée en générant un fichier pour chaque valeur de chaque filtre, et là, patatras, pour chaque filtre il n'y a aucune différence entre la dizaine de fichiers générés, en contradiction totale avec les "Fondamentals" et la zolie image que je vous ai proposée...
À partir de là, ça dépasse mon entendement et mes compétences, d'où *ce* post.
La seule piste que je vois, c'est une incompréhension de ma part de ce commentaire : Suggested sampling width/radius, le signe "/" n'indiquant pas un mot ou l'autre mais vraiment une division de width (quelle width ? De qui de quoi ?) par radius ? Est-ce que ça colle avec l'autre commentaire : Relative sample radius ?
Un dernier mot : les essais ont été faits en UpSampling et en DownSampling, résultats identiques.
À vos claviers !
Partager