raymondT raymondT - 17 days ago 6
Java Question

Transforming image to Ascii code using conversion of grayVal to Ascii Character

So basically this is the part of the program where it is supposed to convert gray value of the image to ascii codes respectively down below, but there is error saying "method must return a type of char[][]" I have succeeded for the first one ("return null") which prints blank space.

public static char[][] imageToASCII(Image img)
{
BufferedImage bufImg = convert(img);
for(int j=0; j<bufImg.getHeight(); j++)
{
for(int i=0; i<bufImg.getWidth(); i++)
{

int values=bufImg.getRGB(i,j);
Color oldColor = new Color(values);
int red = oldColor.getRed(); // get red value
int green = oldColor.getGreen(); // get green value
int blue = oldColor.getBlue();
double grayVal = 0.299*red + 0.587*green + 0.114*blue;
Color newColor = new Color((int)grayVal, (int)grayVal, (int)grayVal);


if(grayVal >= 230)
{
return null;
}
else if(grayVal >= 200 && grayVal < 230)
{
return .;
}
else if(grayVal >= 180 && grayVal < 200)
{
return *;
}
else if(grayVal >= 160 && grayVal < 180)
{
return :;
}
else if(grayVal >= 130 && grayVal < 160)
{
return o;
}
else if(grayVal >= 100 && grayVal < 130)
{
return &;
}
else if(grayVal >= 70 && grayVal < 100)
{
return 8;
}
else if(grayVal >=50 && grayVal < 70)
{
return #;
}
else
return @

}
}



}}

Answer

First of all, to return a char you should enclose it in single-quotes. Second, you don't actually want to return a character, but rather set it in a matrix of characters. The following is a modification of your code which does it:

import java.awt.image.BufferedImage;
import java.awt.Color;

public class Test {
  public static char[][] imageToASCII(BufferedImage img) {
    int w = img.getWidth();
    int h = img.getHeight();
    char[][] res = new char[h][w];

    for(int j=0; j<h; j++) {
      for(int i=0; i<w; i++) {
        int values = img.getRGB(i,j);
        Color oldColor = new Color(values);
        int red = oldColor.getRed();        // get red value
        int green = oldColor.getGreen();    // get green value
        int blue = oldColor.getBlue();
        double grayVal = 0.299*red + 0.587*green + 0.114*blue;

        if(grayVal >= 230) {
          res[j][i] = ' ';
        } else if(grayVal >= 200 && grayVal < 230) {
          res[j][i] = '.';
        } else if(grayVal >= 180 && grayVal < 200) {
          res[j][i] = '*';
        } else if(grayVal >= 160 && grayVal < 180) {
          res[j][i] = ':';
        } else if(grayVal >= 130 && grayVal < 160) {
          res[j][i] = 'o';
        } else if(grayVal >= 100 && grayVal < 130) {
          res[j][i] = '&';
        } else if(grayVal >= 70 && grayVal < 100) {
          res[j][i] = '8';
        } else if(grayVal >=50 && grayVal < 70) {
          res[j][i] = '#';
        } else {
          res[j][i] = '@';
        }
      }
    }
    return res;
  }
}

Also, this code can be quite inefficient in terms of performance. For images where W x H > 255, it's better to avoid the sequential ifs. this can be done by creating at initialization time an array which maps each possible gray value to the corresponding char, and then just dereference such array when looping through the image:

import java.awt.image.BufferedImage;
import java.awt.Color;

public class Test {
  private static char[] map;

  private static void initMap() {
    map = new char[256];
    int[][] ranges = new int[][] {
      {0, 50}, {50, 70}, {70, 100}, {100, 130},
      {130, 160}, {160, 180}, {180, 200},
      {200, 230}, {230, 256}
    };
    char[] v = {' ', '#', '8', '&', 'o', ':', '*', '.', ' '};
    for(int i=0; i<v.length; i++) {
      for(int j=ranges[i][0]; j < ranges[i][1]; j++) {
        map[j] = v[i];
      }
    }
  }

  public static char[][] imageToASCII(BufferedImage img) {
    if (map == null) {
      initMap();
    }
    int w = img.getWidth();
    int h = img.getHeight();
    char[][] res = new char[h][w];

    for(int j=0; j<h; j++) {
      for(int i=0; i<w; i++) {
        int values = img.getRGB(i,j);
        Color oldColor = new Color(values);
        int red = oldColor.getRed();        // get red value
        int green = oldColor.getGreen();    // get green value
        int blue = oldColor.getBlue();
        int grayVal = (int)(0.299*red + 0.587*green + 0.114*blue);
        if (grayVal > 255) {
          grayVal = 255;
         }
        res[j][i] = map[grayVal];
      }
    }
    return res;
  }
}