11#!/usr/bin/env python3
22
33"""
4- Averaging image pixels in a row until reaching `abs(average - current) > threshold`, then repeating in a column.
4+ Averaging image pixels in a row until reaching `abs(average - current) > threshold`,
5+ then repeating in a column.
56
67Created by: `Ilya Razmanov <https://dnyarri.github.io/>`_
78
8- History:
9- ---------
10-
11- 0.10.12.3 Initial version - 12 Oct 2024. RGB only.
12-
13- 0.10.13.2 Forces RGB, skips alpha. Changed threshold condition to r, g, b separately.
14- Seem to be just what I need.
15-
16- 0.10.25.1 Bugfix for tiny details.
17-
18- 1.16.5.10 Modularization, some optimization. Force keep alpha.
19-
20- 1.17.10.1 Edge condition bugfix.
21-
22- 2.19.14.16 Wrap around processing introduced.
23-
24- 3.20.1.1 Substantial rewriting with `map` to correctly support L.
25- No force RGB anymore.
26-
27- 3.20.7.14 Alpha filtering. Full support for L, LA, RGB, RGBA filtering with one `map`.
28-
29- 3.20.20.3 Code harmonization. Lambdas completely replaced with operators
30- and defined functions to improve speed.
31-
32- 3.22.13.11 Unnecessary map to list conversion removed, necessary replaced with [*map] unpacking.
33-
349"""
3510
11+ # History:
12+ # ---------
13+ #
14+ # 0.10.12.3 Initial version - 12 Oct 2024. RGB only.
15+ #
16+ # 0.10.13.2 Forces RGB, skips alpha. Changed threshold condition to r, g, b separately.
17+ # Seem to be just what I need.
18+ #
19+ # 0.10.25.1 Bugfix for tiny details.
20+ #
21+ # 1.16.5.10 Modularization, some optimization. Force keep alpha.
22+ #
23+ # 1.17.10.1 Edge condition bugfix.
24+ #
25+ # 2.19.14.16 Wrap around processing introduced.
26+ #
27+ # 3.20.1.1 Substantial rewriting with `map` to correctly support L.
28+ # No force RGB anymore.
29+ #
30+ # 3.20.7.14 Alpha filtering. Full support for L, LA, RGB, RGBA filtering with one `map`.
31+ #
32+ # 3.20.20.3 Code harmonization. Lambdas completely replaced with operators
33+ # and defined functions to improve speed.
34+ #
35+ # 3.22.13.11 Unnecessary map to list conversions removed,
36+ # necessary ones replaced with [*map] unpacking.
37+ #
38+ # 3.22.18.8 Evasive bug discovered and presumably exterminated.
39+ #
40+
3641__author__ = 'Ilya Razmanov'
3742__copyright__ = '(c) 2024-2025 Ilya Razmanov'
3843__credits__ = 'Ilya Razmanov'
3944__license__ = 'unlicense'
40- __version__ = '3.22.13.11 '
45+ __version__ = '3.22.18.8 '
4146__maintainer__ = 'Ilya Razmanov'
4247__email__ = 'ilyarazmanov@gmail.com'
4348__status__ = 'Production'
@@ -52,7 +57,7 @@ def create_image(X: int, Y: int, Z: int) -> list[list[list[int]]]:
5257 return new_image
5358
5459
55- def filter (source_image : list [list [list [int ]]], threshold_x : int , threshold_y : int , wrap_around : bool = False , keep_alpha : bool = False ) -> list [list [list [int ]]]:
60+ def filter (source_image : list [list [list [int ]]], threshold_x : int | float , threshold_y : int | float , wrap_around : bool = False , keep_alpha : bool = False ) -> list [list [list [int ]]]:
5661 """Average image pixels in a row until `abs(average - current) > threshold` criterion met, then repeat in a column."""
5762
5863 # ↓ Determining image sizes.
@@ -110,15 +115,19 @@ def _criterion_x(channel: int, channel_sum: int) -> bool:
110115 # Uses outer scope `number` and `threshold_x`.
111116
112117 for y in range (0 , Y , 1 ):
113- x_start = 0 # Defining start of inner loop of averaging until threshold.
118+ x_start = 0 # Defining start of inner loop of averaging until threshold hit .
114119 number = 1 # Number of pixels being read during averaging loop.
115- pixel = source_image [cy (y )][0 ] # Current pixel.
120+ pixel = source_image [cy (y )][0 ] # Starting pixel.
116121 pixels_sum = pixel # Sum of pixels being read during averaging loop.
117122 for x in range (0 , X + x_overhead , 1 ):
118123 number += 1
124+ # ↓ Core part of averaging - adding up.
125+ # It is important to sum pixels read BEFORE current pixel
126+ # so when checking threshold and writing an averaged line
127+ # edge pixel is not included into average.
128+ pixels_sum = [* map (add , pixel , pixels_sum )]
119129 pixel = source_image [cy (y )][cx (x )]
120- pixels_sum = [* map (add , pixel , pixels_sum )] # Core part of averaging - adding up.
121- if any (map (_criterion_x , pixel [:Z_COLOR ], pixels_sum [:Z_COLOR ])) or (x == (X - 1 + x_overhead )):
130+ if any (map (_criterion_x , pixel [:Z_COLOR ], pixels_sum [:Z_COLOR ])):
122131 average_pixel = [* map (floordiv , pixels_sum , (number ,) * Z )] # Inner loop result.
123132 for i in range (x_start , x - 1 , 1 ):
124133 intermediate_image [y ][cx (i )] = average_pixel
@@ -143,9 +152,9 @@ def _criterion_y(channel: int, channel_sum: int) -> bool:
143152 pixels_sum = pixel
144153 for y in range (0 , Y + y_overhead , 1 ):
145154 number += 1
146- pixel = intermediate_image [cy (y )][cx (x )]
147155 pixels_sum = [* map (add , pixel , pixels_sum )]
148- if any (map (_criterion_y , pixel [:Z_COLOR ], pixels_sum [:Z_COLOR ])) or (y == (Y - 1 + y_overhead )):
156+ pixel = intermediate_image [cy (y )][cx (x )]
157+ if any (map (_criterion_y , pixel [:Z_COLOR ], pixels_sum [:Z_COLOR ])):
149158 average_pixel = [* map (floordiv , pixels_sum , (number ,) * Z )]
150159 for i in range (y_start , y - 1 , 1 ):
151160 result_image [cy (i )][x ] = average_pixel
@@ -166,6 +175,8 @@ def _criterion_y(channel: int, channel_sum: int) -> bool:
166175 return resultimage_plus_alpha
167176 else :
168177 return result_image
178+
179+
169180# ↑ filter finished
170181
171182# ↓ Dummy stub for standalone execution attempt
@@ -174,4 +185,5 @@ def _criterion_y(channel: int, channel_sum: int) -> bool:
174185 need_help = input ('Would you like to read some help (y/n)?' )
175186 if need_help .startswith (('y' , 'Y' )):
176187 import avgrow
188+
177189 help (avgrow )
0 commit comments