16
\$\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\$
  • \$\begingroup\$ @Noodle9 will edit and clarify, the resizing works by taking every second (if resized to 2x) pixel from the original image. \$\endgroup\$ – Dion Apr 21 at 10:24
  • 1
    \$\begingroup\$ What is the metric used for "closest" for colors? What stops us from outputting an 1x1 image? \$\endgroup\$ – the default. Apr 21 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 Apr 21 at 10:29
  • \$\begingroup\$ @Noodle9 added an explanation in the post \$\endgroup\$ – Dion Apr 21 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\$ – Olivier Grégoire Apr 21 at 10:51

10 Answers 10

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.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I guess my answer helped you to remove Import/Export \$\endgroup\$ – J42161217 Apr 21 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\$ – the default. Apr 21 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
| improve this answer | |
\$\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

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Is it me or this output is not downsampled? \$\endgroup\$ – the default. Apr 21 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 Apr 21 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 Apr 21 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

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ I out-builtinned you! \$\endgroup\$ – the default. Apr 21 at 12:35
  • \$\begingroup\$ @mypronounismonicareinstate yes, I forgot about downsample... \$\endgroup\$ – J42161217 Apr 21 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
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Are the last 3 parameters of IndexColorModel necessary? \$\endgroup\$ – Olivier Grégoire Apr 22 at 12:39
  • 1
    \$\begingroup\$ Does something like -1u>>8 work for 16777215? \$\endgroup\$ – the default. Apr 22 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\$ – Kevin Cruijssen Apr 22 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\$ – Kevin Cruijssen Apr 22 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\$ – Olivier Grégoire Apr 22 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

| improve this answer | |
\$\endgroup\$
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.

| improve this answer | |
\$\endgroup\$
  • \$\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\$ – the default. Apr 21 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 Apr 21 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\$ – the default. Apr 22 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.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Does it parse .5 as 0.5? (I haven't tried) \$\endgroup\$ – the default. Apr 22 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

| improve this answer | |
\$\endgroup\$
  • 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\$ – Olivier Grégoire Apr 21 at 15:21
  • 2
    \$\begingroup\$ @OlivierGrégoire I don't see how this answer prevents people from answering... \$\endgroup\$ – the default. Apr 23 at 2:49
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.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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