用Java生成字符画(2)

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

架构

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)。

数学表达式如下:

其中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评论和提交!

原文链接: korhner 翻译: ImportNew.com - jakiewoo
译文链接: http://www.importnew.com/15962.html
[ 转载请保留原文出处、译者和译文链接。]



相关文章

发表评论

Comment form

(*) 表示必填项

还没有评论。

跳到底部
返回顶部