15
\$\begingroup\$

The task

Given an image as input, your task is to do the following:

  1. Resize the image so it is At least 2 times smaller, but still has the same width/height ratio by taking every second (if resized to 2x) pixel in both horizontal and vertical directions and using those in the pixel art image. Example:
a 4x4 image 

[abcd
,efgh
,ijkl
,mnop]

When resized to 2x will become one of the following:

[ac  [bd  [eg  [fh
,ik] ,jl] ,mo] ,np]
  1. Each RGB pixel in the newly resized image must be converted to a 3-bit color, so there are 8 different possible colors:
Red        (255,0,0)
Green      (0,255,0)
Blue       (0,0,255)
Light Blue (0,255,255)
Magenta    (255,0,255)
Yellow     (255,255,0)
White      (255,255,255)
Black      (0,0,0)

An image of the colors:

3bit colors

  1. And output the resulting image.

Input

Your input may be:

  1. An image
  2. A path to the inputting image

Output

Can be:

  1. An image
  2. A path to the outputting image

Rules

  • The inputting image will not be larger than 2048x2048 and will always be at least 256x256
  • The outputting image must be at least 64x64
  • When changing pixels, the original pixel must be converted to the closest (euclidean) pixel in the 3-bit scheme, no randomization
  • You may hardcode how much you resize the image if you want to
  • When submitting your answer, please include the following:
    1. Your byte-count in the title
    2. Your code
    3. An pair of images, one original of your choice and the other being the "pixel-art" from that image
  • This is code-golf, so lowest byte count for each language wins.

Test cases

flower flower (2x resize)

tracer tracer (2x resize)

\$\endgroup\$
11
  • \$\begingroup\$ @Noodle9 will edit and clarify, the resizing works by taking every second (if resized to 2x) pixel from the original image. \$\endgroup\$
    – Dion
    Commented Apr 21, 2020 at 10:24
  • 1
    \$\begingroup\$ What is the metric used for "closest" for colors? What stops us from outputting an 1x1 image? \$\endgroup\$ Commented Apr 21, 2020 at 10:27
  • \$\begingroup\$ @mypronounismonicareinstate When i made an ungolfed version of this, I used (r//128*255,g//128*255,b//128*255) for (r,g,b) in every pixel (python). As for the size, will add in rules to output at least 64x64 image \$\endgroup\$
    – Dion
    Commented Apr 21, 2020 at 10:29
  • \$\begingroup\$ @Noodle9 added an explanation in the post \$\endgroup\$
    – Dion
    Commented Apr 21, 2020 at 10:36
  • 3
    \$\begingroup\$ I will repeat @mypronounismonicareinstate : What stops us from outputting a 1x1 image since the ratio is ours to decide? \$\endgroup\$ Commented Apr 21, 2020 at 10:51

11 Answers 11

10
\$\begingroup\$

Sledgehammer, 22 17 bytes

I noticed I'm no longer winning for some reason and made a minor IO golf

⢟⢡⡂⠴⠒⢂⢜⠧⣘⡨⡏⣻⢈⠯⣧⠼⡫

Corresponding Mathematica code: Export[".bmp",ImageAdjust[Import[#]~Downsample~2, 9!]]& . Takes input from the file with name specified in the program's arguments (for some reason these are put in a file, too), outputs to the file .bmp. There are literally built-ins for everything!

  • built-in for reading arbitrary image format
  • built-in for downsampling
  • built-in for adjusting the contrast by \$9!\$
  • built-in for writing all that into a file

At least it's not PixelArtify[Input[]].

Mathematica, 61 31 bytes

ImageAdjust[#~Downsample~2,9!]&

Adjusts the contrast of the downsampled image by the factorial of nine.

\$\endgroup\$
2
  • \$\begingroup\$ I guess my answer helped you to remove Import/Export \$\endgroup\$
    – ZaMoC
    Commented Apr 21, 2020 at 12:46
  • \$\begingroup\$ I included them in the Sledgehammer code because while I could input and output a bunch of pixel values, that's not very kind, and that answer is probably winning anyway, so I could sacrifice a few bytes for that purpose. \$\endgroup\$ Commented Apr 21, 2020 at 12:50
9
\$\begingroup\$

MATL, 18 bytes

Yi2Lt3:K$)127>o2YG

The input is a string with the file name. The output is an image displayed in a window.

Input image:

enter image description here

Output image:

enter image description here

Explanation

Yi    % Implicit input: filename. Read image. Gives an N×M×3 uint8 array
2L    % Push [2 2 j] (predefined literal). When interpreted as an index,
      % this means 2:2:end
t     % Duplicate
3:    % Push [1 2 3]
K$)   % 4-input indexing. Downsamples the image by a factor of 2 in each
      % dimension of the first two dimensions (vertical and horizontal),
      % while keeping the three colour components
127>  % Greater than 127? Gives true (1) or false (0)
o     % Convert to double
2YG   % Display image. For double data type this assumes range from 0 to 1
\$\endgroup\$
7
\$\begingroup\$

Python 3 + imageio, 68 67 bytes

Takes the filename as input, overwrites the original file.

from imageio import*
lambda f:imwrite(f,(~imread(f)[::2,::2]>>7)-1)

imageio.imread returns a numpy 3d array of unsigned 8-bit integers corresponding to the RGB value of each pixel. array[::2, ::2] takes every other row and every other column of the array.

Because of the 8-bit data type (~array>>7)-1 is equivalent to ((255-array)//128-1)%256.

image source

enter image description here

enter image description here

\$\endgroup\$
3
  • \$\begingroup\$ Is it me or this output is not downsampled? \$\endgroup\$ Commented Apr 21, 2020 at 14:03
  • \$\begingroup\$ @mypronounismonicareinstate I displayed a downscaled version of the original because it took up so much space, the true original would open if you click on it. I have changed this now because this will probably confuse more people. \$\endgroup\$
    – ovs
    Commented Apr 21, 2020 at 14:11
  • \$\begingroup\$ Damn, i also used python 3 but used PIL as it's the only image library I know. Well done! \$\endgroup\$
    – Dion
    Commented Apr 21, 2020 at 18:02
4
\$\begingroup\$

Wolfram Language (Mathematica), 69 bytes

Image[#&@@Nearest[{0,1}~Tuples~3,#]&/@#&/@ImageData@Downsample[#,2]]&      

enter image description here

enter image description here

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I out-builtinned you! \$\endgroup\$ Commented Apr 21, 2020 at 12:35
  • \$\begingroup\$ @mypronounismonicareinstate yes, I forgot about downsample... \$\endgroup\$
    – ZaMoC
    Commented Apr 21, 2020 at 12:42
4
\$\begingroup\$

Java 10, 255 254 252 251 248 bytes

import java.awt.image.*;I->{int w=I.getWidth()/2,h=I.getHeight()/2,c[]={0,255,65535,65280,255<<16,16711935,16776960,-1>>>8};var r=new BufferedImage(w,h,13,new IndexColorModel(3,8,c,0,0>1,1,0));r.createGraphics().drawImage(I,0,0,w,h,null);return r;}

-2 bytes thanks to @mypronounismonicareinstate
-4 bytes thanks to @OlivierGrégoire.

Some example I/O:

enter image description here enter image description here enter image description here enter image description here

I/O as a java.awt.image.BufferedImage.

Explanation:

import java.awt.image.*;      // Import for BufferedImage and IndexColorModel
I->{                          // Method with BufferedImage as both parameter & return
  int w=I.getWidth()/2,       //  Get the width/2 of the input-image
      h=I.getHeight()/2,      //  Get the height/2 of the input-image
      c[]={                   //  Integer-arry for the colors:
       0,                     //   0x000000 (black)
       255,                   //   0x0000ff (blue)
       65535,                 //   0x00ff00 (green)
       65280,                 //   0x00ffff (aqua)
       255<<16,               //   0xff0000 (red)
       16711935,              //   0xff00ff (magenta)
       16776960,              //   0xffff00 (yellow)
       -1>>>8};               //   0xffffff (white)
  var r=new BufferedImage(w,h,//  Create the return-BufferdImage with this size, and:
         13,                  //   An indexed byte image (BufferedImage.TYPE_BYTE_INDEXED)
         new IndexColorModel( //   Using the following ColorModel:
          3,                  //    3-bits
          8,c,                //    with the 8 colors of the earlier created array
          0,                  //    without an offset index
          0>1,                //    without alpha layers (false)
          1,                  //    without transparent colors (Transparency.OPAQUE)
          0));                //    using unsigned bytes as data (DataBuffer.TYPE_BYTE)
  r.createGraphics()          //  Convert this image to a Graphics2D object
   .drawImage(I,              //  So we can use the input-image for it
              0,0,            //   with 0,0 as starting x,y coordinates
              w,h,            //   the same halved width & height
              null);          //   and no ImageObserver
  return r;}                  //  Return this created BufferedImage as result
\$\endgroup\$
7
  • \$\begingroup\$ Are the last 3 parameters of IndexColorModel necessary? \$\endgroup\$ Commented Apr 22, 2020 at 12:39
  • 1
    \$\begingroup\$ Does something like -1u>>8 work for 16777215? \$\endgroup\$ Commented Apr 22, 2020 at 12:40
  • \$\begingroup\$ @OlivierGrégoire I'm afraid so. The constructors of the IndexColorModel are limited when using an int[] for the colors. It's either (int,int,int[],int,boolean,int,int) or int,int,int[],int,int,BigInteger). It also has a constructor with byte[], but those can't fit some of the colors, and the three separated parameters for red,green,blue, but I doubt those would save bytes considering the three loose arrays. \$\endgroup\$ Commented Apr 22, 2020 at 12:43
  • \$\begingroup\$ @mypronounismonicareinstate Thanks, that indeed works (although it's >>> instead of u>> in Java). I tried to find something shorter for some of those numbers, but didn't really worked out. Thanks! \$\endgroup\$ Commented Apr 22, 2020 at 12:44
  • 1
    \$\begingroup\$ Ok for the constructors, I hadn't noticed the change from byte[] to int[]. Also, same idea as @mypronounismonicareinstate: 255<<16 == 16711680. \$\endgroup\$ Commented Apr 22, 2020 at 12:49
3
\$\begingroup\$

Red, 150 148 bytes

func[s][r: func[a][round/to a 255]i: load s forall i[i/1: as-rgba r i/1/1
r i/1/2 r i/1/3 0]view compose[base(i/size / 2)draw[scale .5 .5 image i]]]

The output is an image displayed in a window.

Figure Original

Figure x.5 Scale 0.5

Samoyed Original

Samoyed x 0.5 Scale x 0.5

\$\endgroup\$
2
  • \$\begingroup\$ That downsampled dog is pretty scary looking :p \$\endgroup\$
    – rydwolf
    Commented Sep 24, 2020 at 3:55
  • \$\begingroup\$ @RedwolfPrograms It's the first time I hear someone to call a samoyed dog "scary looking" :) It's good that you were talking about the downsampled one. I have a samoyed dog myself, not as fluffy as the one above though and still she's adorable! \$\endgroup\$ Commented Sep 24, 2020 at 6:46
3
\$\begingroup\$

bash + ImageMagick, 123 50 bytes

convert "$1" -sample 50% +dither -posterize 2 "$2"

Untested, as I haven't actually installed it; I've just cribbed stuff from Stack Overflow. Edit: Saved 73 bytes thanks to @someone.

\$\endgroup\$
3
  • \$\begingroup\$ There's the -posterize flag that probably does the equivalent of the red,lime,blue,... thingy (I don't understand that line properly though). \$\endgroup\$ Commented Apr 21, 2020 at 13:35
  • \$\begingroup\$ @someone What that line did was to generate an image with that palette so that the input image could be converted to the same palette. \$\endgroup\$
    – Neil
    Commented Apr 21, 2020 at 14:05
  • \$\begingroup\$ I think the double quotes are unnecessary (on this website). Mogrify instead of convert can probably save a few bytes too. \$\endgroup\$ Commented Apr 22, 2020 at 1:20
3
\$\begingroup\$

bash + netpbm, 30 bytes

pnmdepth 1|pnmscale -nomix 0.5

Takes input on stdin as a PNM file, and outputs on stdout as a PNM file.

pnmdepth 1 reduces the depth of the image on its stdin to 1, and pnmscale 0.5 reduces the size by a half in each direction. The -nomix option is required for pnmscale to choose a pixel from the starting image for each output pixel, instead of mixing adjacent input pixels into one output pixel.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Does it parse .5 as 0.5? (I haven't tried) \$\endgroup\$ Commented Apr 22, 2020 at 6:16
3
\$\begingroup\$

Python 3 + PIL, 211 208 bytes

from PIL import Image as I
i=I.open(input(),'r')
p=i.load()
q,g=i.size;a=q//4;c=g//4
u=I.new('RGB',(a,c))
o=u.load()
for w in range(a):
 for h in range(c):o[w,h]=tuple(e//128*255 for e in p[w*4,h*4])
u.show()

Golfed the testing script I used to create the test cases for this challenge

\$\endgroup\$
2
  • 1
    \$\begingroup\$ When you post a challenge, it's good to let a few days before you post your try, so that people can try in all the languages they want. \$\endgroup\$ Commented Apr 21, 2020 at 15:21
  • 4
    \$\begingroup\$ @OlivierGrégoire I don't see how this answer prevents people from answering... \$\endgroup\$ Commented Apr 23, 2020 at 2:49
1
\$\begingroup\$

MATLAB, 32 bytes

@(x)(x(1:2:end,1:2:end,:)>127)*1

Both input and output are images. Output is an array storing image data, it's not specified in challenge that output image must be displayed. (to display result add 8 bytes for imshow(...) command)
The actual result and original:
input image output image

Art credit to Janna Sophia.

\$\endgroup\$
0
\$\begingroup\$

Processing, 463 bytes

size(500,500);String u="";PImage p=loadImage(u);p.resize(p.width/2,p.height/2);noStroke();color[]c={#ff0000,#00ff00,#0000ff,#00ffff,#ff00ff,#ffff00,#ffffff,0};p.loadPixels();for(int i=0;i<p.width;i++){for(int j=0;j<p.height;j++){float[]d=new float[8];color x=p.get(i,j);for(int k=0;k<8;k++)d[k]=sqrt(sq(red(x)-red(c[k]))+sq(blue(x)-blue(c[k]))+sq(green(x)-green(c[k])));int b=0;for(int l=0;l<8;l++){if(d[l]<=d[b]){b=l;}}fill(c[b]);rect(i,j,1,1);}}save(u+"1.png");

Takes image location, saves pixel art as image1.png. enter image description hereenter image description here Image from beeple.

\$\endgroup\$

Your Answer

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

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