上一篇博客里我用Java创建了一个简单的Ascii 字符画生成器(可以从GitHub上获取), 文章发布之后我收到了很多反馈。所以今天我打算继续在这个项目上添加一些新特性,期待能受到更多欢迎。我重新设计了核心部分,目的是增加扩展性以便测试不同的算法以及产生多样化的结果。 在本文中,我会展示本项目的全新架构,方便您整合进自己的项目中以及根据需要进行扩展。

架构

用Java生成字符画(2)

AsciiImgCache

在任何ascii字符渲染发生前,我们需要创建一个此类的实例。 它需要一个字体和字符列表作为参数,然后它将为每个字符生成一个图片的Map。如果你嫌麻烦,也有默认的字符列表提你选择。

提供给对此感兴趣的读者:

private static final char[] defaultCharacters = 
    "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft///|()1{}[]?-_+~<>i!lI;:,/"^`'. "

示例

// use only '/' '/' and ' '
AsciiImgCache mediumBlackAndWhiteCache = AsciiImgCache.
    create(new Font("Courier", Font.BOLD, 10), new char[] {'//', ' ', '/'});
// use default list
AsciiImgCache largeFontCache = AsciiImgCache.
    create(new Font("Courier",Font.PLAIN, 16));

BestCharacterFitStrategy

这是一个算法的抽象,用来判断源图像与每个字符的相似度。该抽象只有一个方法:

float calculateError(final GrayscaleMatrix character, final GrayscaleMatrix tile);

对于具体的实现来说,它应该比较两个图片并返回浮点格式的偏差值。每个字符都会被用来进行比较,最终采用返回最小偏差值的字符。目前有两种实现:

ColorSquareErrorFitStrategy

这个实现非常容易理解。 它比较每个像素然后计算灰度差异的均方误差(Mean squared error)。

数学表达式如下:

用Java生成字符画(2)

其中n代表像素的数量, C和T分别代表字符和tile图像的像素。

StructuralSimilarityFitStrategy

结构相似性(SSIM)索引算法声称能还原人类视角,其目标是提升传统的诸如MSE的算法。此处我不打算详细解释其原理,如果你感兴趣可以在Wikipedia上阅读相关资料。我自己也进行了一些尝试并实现了一个版本,似乎能在我们的用例中获得不错的结果。

AsciiConverter

这是整个流程的核心,它包含源图像取样(tiling)的逻辑,调用具体实现计算出最匹配的字符。然而,它并不知道如何创建ascii 字符 – 这需要子类来实现。 目前有两个实现:AsciiToImageConverter and AsciiToStringConverter – 顾名思义,它们分别输出图像和字符串。

示例用法:

正所谓埋头苦干胜于纸上谈兵,下面就整合各个部分,给大家展示整个流程:

// initialize cache
AsciiImgCache cache = AsciiImgCache.create(new Font("Courier",Font.BOLD, 6));
// load image
BufferedImage portraitImage = ImageIO.read(new File("image.png"));
// initialize converters
AsciiToImageConverter imageConverter = 
    new AsciiToImageConverter(cache, new ColorSquareErrorFitStrategy());
AsciiToStringConverter stringConverter = 
    new AsciiToStringConverter(cache, new StructuralSimilarityFitStrategy());
// image output
ImageIO.write(imageConverter.convertImage(portraitImage), "png", 
    new File("ascii_art.png"));
// string converter, output to console
System.out.println(stringConverter.convertImage(portraitImage));

下面还有一些通过设置不同参数产生的图片:

原始图片

16 pts字体,MSE 16 pts字体, SSIM 10 pts字体3字符,MSE 10 pts字体3字符,SSIM 6 pts字体,MSE 6 pts字体,SSIM

下一步工作

下面是对未来工作的一些想法:

  • 研究并实现更多的图像比较算法。
  • 对图片重新处理达到更佳效果(改进对比度,使用边缘监测等)。
  • 通过并行处理改进图像处理效果,根据结果评估是否值得改进。
  • 增加一些转换格式(比如html输出)。
  • 支持输出带颜色的字符。
  • 为项目添加测试。

对代码有建议或者发现任何问题,欢迎通过GitHub评论和提交!

你可能感兴趣的内容
Java序列化与static 收藏,3266 浏览
0条评论

dexcoder

这家伙太懒了 <( ̄ ﹌  ̄)>
Owner