13
\$\begingroup\$

Box blur is a simple operation for blurring images. To apply box blur, simply replace each pixel with the average of its and the surrounding 8 pixels' values. Consider, for example, the following example, in which each "pixel" has a one-digit value:

\begin{array} {|r|r|}\hline 1 & 1 & 1 \\ \hline 1 & 7 & 1 \\ \hline 1 & 1 & 1 \\ \hline \end{array}

To get the blurred value of the center pixel we add its value to the 8 surrounding pixels' values and divide by 9.

$$ \frac{7+1+1+1+1+1+1+1+1}{9}=\frac{5}{3}=1.\overline{6} $$

Repeat this operation for every pixel and you've blurred the image.

The task

Like pixels, strings are just numbers, so we can box blur them too. Your task is to take a string, which may have multiple lines, in some convenient format and return a new string that's been "blurred" by the above process. That is to say, you'll take each character's ASCII value and treat it as that character's value, "blur" the values, and return the new values' corresponding characters.

For example, given the following input:

'''#
''#'
'#''
#'''

Your output would look like this:

''&%
'&&&
&&&'
%&''

Edges and corners

How do you blur a "pixel" that doesn't have eight neighbors because it's on an edge or in a corner of the "canvas"? For our purposes, you'll solve this by "filling in" the missing pixels with the nearest pixel's value. In the example below the missing value northwest of 1 is filled in with 1; likewise the missing value east of 6 is filled in with 6.

\begin{array} {|r|r|}\hline \color{silver}{1} & \color{silver}{1} & \color{silver}{2} & \color{silver}{3} & \color{silver}{3} \\ \hline \color{silver}{1} & 1 & 2 & 3 & \color{silver}{3} \\ \hline \color{silver}{4} & 4 & 5 & 6 & \color{silver}{6} \\ \hline \color{silver}{7} & 7 & 8 & 9 & \color{silver}{9} \\ \hline \color{silver}{7} & \color{silver}{7} & \color{silver}{8} & \color{silver}{9} & \color{silver}{9} \\ \hline \end{array}

Rounding

For our purposes, you'll round fractions to the nearest integer. Halves should be rounded up.

Rules

  • The input will consist of one or more lines of one or more printable ASCII characters, i.e. 0x200x7E inclusive, plus newlines if applicable to your input format. The string will be "rectangular," i.e. every line will have the same length.

  • The input format is flexible, e.g. a single string with lines separated by newlines, an array of strings with one string per line, a multi-dimensional array of characters, etc.

  • The output will be in the same format as the input, and likewise flexible.

  • Standard rules and default I/O rules apply and standard loopholes are forbidden.

  • This is so shortest solution in bytes wins.

More examples

Input      Output

111        222
171        222
111        222


XXXXX      INNNI
,,X,,      ;DDD;
,,X,,      ,;;;,
,,X,,      ;DDD;
XXXXX      INNNI


'888'      /020/
8'''8      00/00
8'8'8      2/)/2
8'''8      00/00
'888'      /020/


103050709  111324256


!~         JU
~!         UJ


Q          Q


+--+       <22<
|  |       <22<
+--+       <22<


^          M
*          ;
*          ;
^          M
\$\endgroup\$
1
  • \$\begingroup\$ Sandbox \$\endgroup\$
    – Jordan
    Oct 20, 2022 at 18:40

7 Answers 7

5
\$\begingroup\$

Vyxal, 20 bytes

4(∩ṘǏǔ)3vl3lƛ∩ṠCvṁṙC

Try it Online!

A mess. Input as a list of rows, output as a char matrix.

4(    )              # Four times...
  ∩Ṙ                 # Rotate 90°
    Ǐǔ               # Prepend the first item
       3vl           # Cut each into chunks of length 3
          3l         # Cut into chunks of length 3
            ƛ        # Over each list of lists of chunks...
             ∩       # Transpose into a list of 3x3 chunks
              Ṡ      # Stringify each chunk
               C     # Take the charcodes
                vṁṙ  # Take the mean of each and round back to integers
                   C # Convert back to characters
\$\endgroup\$
4
\$\begingroup\$

Octave with Image Package, 50 bytes

@(X)char(round(imfilter(+X,~~e(3)/9,'replicate')))

Try it online!

\$\endgroup\$
4
\$\begingroup\$

J, 47 45 bytes

(0.5<.@+9%~3+/\"#.3+/\(|.@|:@,{:)^:4)&.(3&u:)

Try it online!

-2 thanks to ovs

  • &.(3&u:) Do everything that follows "under" converting to ascii code. This means it gets converted back automatically at the end.
  • ({.|.@|:@,])^:4) Standard reverse/transpose trick to fill out the sides and top.
  • 3+/\"#.3+/\ Even though J has a built-in for applying a verb to "tiles" -- in this case it's 1 byte shorter to scan sum rows in groups of 3, then scan sum colums in groups of 3 to get the 3x3 tile averages.
  • 9%~ Divide each by 9 for the average.
  • 0.5<.@+ And round.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I think (|.@|:@,{:) saves a byte ... And another one by using 3+/\ instead of 3 3;._3: TIO \$\endgroup\$
    – ovs
    Oct 21, 2022 at 8:34
  • \$\begingroup\$ Those are very nice, thanks. \$\endgroup\$
    – Jonah
    Oct 21, 2022 at 12:57
2
\$\begingroup\$

Jelly, 20 bytes

1ịṭṚZµ4¡O+3\Z$⁺+4:9Ọ

A monadic Link that accepts a list of lines and yields a list of lines.

Try it online! Or see the test-suite.

How?

1ịṭṚZµ4¡O+3\Z$⁺+4:9Ọ - Link: list of lines, T
     µ4¡             - repeat four times (starting with T):
1                    -   one
 ị                   -   index into -> top row
   Ṛ                 -   reverse (the current lines)
  ṭ                  -   tack -> reversed current lines + top row
    Z                -   transpose
        O            - convert to ordinals
              ⁺      - do this twice:
             $       -   last two links as a monad:
          3\         -     three-part reduce  with:
         +           -       addition
            Z        -     transpose
               +4    - add four
                 :9  - integer divide by nine
                   Ọ - convert to characters
\$\endgroup\$
2
\$\begingroup\$

Pyth, 44 bytes

L++hbbebDONRmsM.:d3CN;jmsmC+.5ck9dOOCMMyyM.z

Try it online!

Takes each line of the string as a separate input.

Explanation

L++hbbeb                                        define y(b) as the "filling in" for the edges
        DONRmsM.:d3CN;                          define O(N) to transpose then blur the rows of a list by splitting into sublists of length 3 and mapping to their sum
                                          .z    put all available inputs into a list
                                       yyM      apply y to the rows and columns
                                    CMM         convert strings to lists of codepoints
                                  OO            apply the blurring, the two transpositions mean it ends as it started
                       m         d              map to
                        sm                      the joined strings of the map of
                          C                     the ascii value of the floor of
                           +.5ck9               0.5 + each element divided by 9
                      j                         join on newlines
\$\endgroup\$
1
\$\begingroup\$

Charcoal, 61 bytes

WS⊞υι≔E⊞O⁺⟦§υ⁰⟧υ§υ±¹E⁺⁺§ι⁰ι§ι±¹℅λθEυ⭆ι℅÷⁺⁴ΣE✂θκ⁺³κ¹Σ✂νμ⁺³μ¹¦⁹

Try it online! Link is to verbose version of code. Takes input as a list of newline-terminated strings. Explanation:

WS⊞υι

Input the string to be blurred.

≔E⊞O⁺⟦§υ⁰⟧υ§υ±¹E⁺⁺§ι⁰ι§ι±¹℅λθ

Prepend and append a copy of the first and last rows, then for each row, prepend and append a copy of the first and last characters, and convert all of the characters to their code points to create an expanded array.

Eυ⭆ι℅÷⁺⁴ΣE✂θκ⁺³κ¹Σ✂νμ⁺³μ¹¦⁹

Map over the original list of strings, replacing each character with the average of the 3×3 tile taken from the expanded array.

\$\endgroup\$
1
  • \$\begingroup\$ Best I could do with canvas functions was 64 bytes: Try it online! \$\endgroup\$
    – Neil
    Oct 21, 2022 at 9:37
0
\$\begingroup\$

05AB1E, 19 bytes

4Fíø¬š}€ü3ü3εøÇÅAòç

I/O as character-matrices.

Try it online or verify all test cases.

Explanation:

Step 1: Add the edges and corners as explained in the challenge description:

4F            # Loop 4 times:
  íø          #  Rotate once counterclockwise:
  í           #   Reverse each inner row
   ø          #   Zip/transpose; swapping rows/columns
    ¬         #  Push the first row (without popping the matrix)
     š        #  Prepend it
 }            # Close the map

Try just this first step online.

Step 2: Create overlapping 3x3 blocks:

€             # After the loop: map over each inner row:
 ü3           #  Convert it to a list of overlapping triplets
   ü3         # And then convert these lists to overlapping triplets as well
     ε        # Map over each list of matrices:
      ø       #  Zip/transpose; swapping rows/columns, to create 3x3 blocks

Try just the first two steps online.

Step 3: Convert the characters to codepoint integers; get the rounded average of each 3x3 block; and convert these new codepoint integers back to characters (and output as result):

       Ç      #  Convert each inner 3x3 block to a flattened list of codepoint integers
        ÅA    #  Get the average of each list
          ò   #  Round each decimal to an integer
           ç  #  Convert this rounded integer back to a character
              # (after which the resulting matrix is output implicitly)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.