我正在尝试从图像制作ASCII Art,但是由于某种原因,输出总是旋转的,我经过了很多遍代码,但我根本找不到错误。我想这与imageWidth和imageHeight有关,但对我来说一切都很好。
代码可以在github
上找到答案 0 :(得分:2)
假设一个字符占据了 21×8
像素的区域。所以首先你要把原图缩小,得到这个区域的平均颜色,然后得到这个颜色的平均亮度,再转换成字符。
原图:
ASCII 图片:
此代码从文件中读取图像,将其缩小到高度的 1/21 和宽度的 1/8,计算缩放区域的平均颜色,然后计算每种颜色的平均亮度并选择一个对应密度的字符,然后将这些字符保存到一个文本文件中。
不缩放scH=1
和scW=1
,字符数等于原图的像素数。
public static void main(String[] args) throws IOException {
// assume that one character occupies an area of 21×8 pixels
char[][] chars = readImage("/tmp/image.jpg", 21, 8);
writeToFile("/tmp/image.txt", chars);
}
static char[][] readImage(String path, int scH, int scW) throws IOException {
BufferedImage image = ImageIO.read(new File(path));
int height = image.getHeight() / scH;
int width = image.getWidth() / scW;
char[][] chars = new char[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// scaling image and accumulating colors
int colorRGB = 0;
for (int k = 0; k < scH; k++)
for (int p = 0; p < scW; p++)
colorRGB += image.getRGB(j * scW + p, i * scH + k);
// get the average color
Color color = new Color(colorRGB / (scH * scW));
// read the R, G, B values of the color and get the average brightness
int brightness = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
// get a character depending on the brightness value
chars[i][j] = getDensity(brightness);
}
}
return chars;
}
static final String DENSITY =
"@QB#NgWM8RDHdOKq9$6khEPXwmeZaoS2yjufF]}{tx1zv7lciL/\\|?*>r^;:_\"~,'.-`";
static char getDensity(int value) {
// Since we don't have 255 characters, we have to use percentages
int charValue = (int) Math.round(DENSITY.length() / 255.0 * value);
charValue = Math.max(charValue, 0);
charValue = Math.min(charValue, DENSITY.length() - 1);
return DENSITY.charAt(charValue);
}
static void writeToFile(String path, char[][] chars) throws IOException {
FileWriter writer = new FileWriter(path);
for (char[] row : chars) {
String str = String.valueOf(row);
writer.append(str).write("\n");
System.out.println(str);
}
writer.flush();
writer.close();
}
输出:
***************************************
***************************************
*************o/xiz|{,/1ctx*************
************77L*```````*_1{j***********
**********?i```````````````FZ**********
**********l`````````````````7**********
**********x`````````````````L**********
**********m?i`````````````iz1**********
************]x```````````\x{***********
********?1w]c>```````````La{]}r********
******jSF~```````````````````^xv>******
*****l1,```````````````````````*Sj*****
****7t```````````````````````````v7****
***uL`````````````````````````````t]***
答案 1 :(得分:0)
在ImageWriting.java中,第34行:
this.writer.append(Density.DENSITY.getDensityFor(this.brightnessValues[j][i]));
答案 2 :(得分:0)
我强烈怀疑您正在遍历某个 for
循环中的一个坐标,而另一个循环嵌套在其中。 (不会在另一个网站上追逐代码。)
尝试交换 for
循环的嵌套或按数组索引访问元素的顺序(根据您拥有的任何代码,将 [i][j]
代码片段替换为 [j][i]
或类似代码另一个我不会去追求的网站)。
答案 3 :(得分:0)
您可以从任何字符范围创建自己的字符密度图,然后,由于密度分布不均匀,将其转换为亮度图,然后进一步调用 ceilingEntry
和 floorEntry
方法。
首先使用 java.awt
包将每个字符绘制为黑白图片并计算像素数 - 您会得到一个密度图。然后,对于该地图中的每个条目,计算比例 0-255
上的亮度百分比 - 您会得到一个亮度图。
图片:
原图 | ASCII:0 - 255 0x0000 - 0x00FF |
符文: 0x16A0 - 0x16FF |
方框图: 0x2500 - 0x257F |
块元素: 0x2580 - 0x259F |
几何形状: 0x25A0 - 0x25FF |
平假名: 0x3040 - 0x309F |
---|---|---|---|---|---|---|
密度标度:
Unicode 块 | 字符范围 | 密度标度 |
---|---|---|
ASCII | 0-255 |
¶@ØÆMåBNÊßÔR#8Q&mÃ0À$GXZA5ñk2S%±3Fz¢yÝCJf1t7ªLc¿+?(r/¤²!*;"^:,'.` |
Runic | 0x16A0-0x16FF |
ᛥᛤᛞᚥᚸᛰᛖᚻᚣᛄᚤᛒᚢᚱᛱᚷᚫᛪᚧᚬᚠᛏᚨᚰᚩᚮᚪᚳᚽᚿᛊᛁᛵᛍ᛬ᚲᛌ᛫ |
Box Drawing | 0x2500-0x257F |
╬╠╫╋║╉╩┣╦╂╳╇╈┠╚┃╃┻╅┳┡┢┹╀╧┱╙┗┞┇┸┋┯┰┖╲╱┎╘━┭┕┍┅╾│┬┉╰╭╸└┆╺┊─╌┄┈╴╶ |
Block Elements | 0x2580-0x259F |
█▉▇▓▊▆▅▌▚▞▀▒▐▍▃▖▂░▁▏ |
Geometric Shapes | 0x25A0-0x25FF |
◙◘■▩●▦▣◚◛◕▨▧◉▤◐◒▮◍◑▼▪◤▬◗◭◖◈◎◮◊◫▰◄◯□▯▷▫▽◹△◁▸▭◅▵◌▱▹▿◠◃◦◟◞◜ |
Hiragana | 0x3040-0x309F |
ぽぼゑぜぬあおゆぎゐはせぢがきぱびほげばゟぁたかぞぷれひずどらさでけぉちごえすゎにづぇとょついこぐうぅぃくっしへゞゝ゚゙ |
代码:
public static void main(String[] args) {
Font font = new Font(Font.MONOSPACED, Font.PLAIN, 22);
// ASCII characters: 0 - 255
// Runic: 0x16A0 - 0x16FF
// Box Drawing: 0x2500 - 0x257F
// Block Elements: 0x2580 - 0x259F
// Geometric Shapes: 0x25A0 - 0x25FF
// Hiragana: 0x3040 - 0x309F
TreeMap<Integer, List<String>> density = getDensityMap(font,0x25A0,0x25FF,0);
// the map of brightness of pixels [0, 255]
TreeMap<Integer, List<String>> brightness = getBrightnessMap(density);
// output, geometric shapes
for (List<String> value : brightness.values()) System.out.print(value.get(0));
// ◙◘■▩●▦▣◚◛◕▨▧◉▤◐◒▮◍◑▼▪◤▬◗◭◖◈◎◮◊◫▰◄◯□▯▷▫▽◹△◁▸▭◅▵◌▱▹▿◠◃◦◟◞◜
}
/**
* @param density character density map
* @return the pixel brightness map [0, 255],
* based on percentages of character density
*/
static TreeMap<Integer, List<String>> getBrightnessMap(
TreeMap<Integer, List<String>> density) {
int max = density.lastKey(); // maximum density
TreeMap<Integer, List<String>> brightness = new TreeMap<>();
for (Map.Entry<Integer, List<String>> entry : density.entrySet()) {
// pixel brightness, based on the percentage of character density
int key = (int) Math.round(255.0 - entry.getKey() * 255.0 / max);
List<String> value = entry.getValue();
List<String> val = brightness.remove(key);
if (val == null) val = new ArrayList<>();
val.addAll(value);
brightness.put(key, val);
}
return brightness;
}
/**
* @param f font to render text
* @param min character codepoint range, lower bound
* @param max character codepoint range, upper bound
* @param pd padding as a precaution, in most cases 0
* @return the character density map:
* key - density, value - list of characters
*/
static TreeMap<Integer, List<String>> getDensityMap(
Font f, int min, int max, int pd) {
// key - density, value - list of characters
TreeMap<Integer, List<String>> density = new TreeMap<>();
for (int i = min; i <= max; i++) {
// printable characters
if (f.canDisplay(i) && Character.isDefined(i)
&& !Character.isISOControl(i)
&& !Character.isIdentifierIgnorable(i)) {
String str = String.valueOf(Character.toChars(i));
int key = getDensity(str, f, pd);
List<String> list = density.remove(key);
if (list == null) list = new ArrayList<>();
list.add(str);
density.put(key, list);
}
}
return density;
}
/**
* @param text source text to draw
* @param f font to render text
* @param pd padding as a precaution, in most cases 0
* @return the density of the characters in this text
*/
static int getDensity(String text, Font f, int pd) {
FontRenderContext ctx = new FontRenderContext(f.getTransform(), false, false);
Rectangle bounds = f.getStringBounds(text, ctx).getBounds();
int width = bounds.width + pd * 2;
int height = bounds.height + pd * 2;
BufferedImage image =
new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
Graphics2D graphics = (Graphics2D) image.getGraphics();
graphics.setFont(f);
graphics.drawString(text, pd + bounds.x, pd - bounds.y);
//ImageIO.write(image, "png", new File("text.png"));
int density = 0;
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (image.getRGB(j, i) == 0xFFFFFFFF)
density++;
return density;
}