如何制作指定词数的原图词云及图片转ASCII词云图?
我来帮你解决这两个技术需求,下面分别给出详细的实现方案:
两项技术需求的实现指南
1. 基于原始图片制作指定词数量的词云
要实现这个需求,核心是先匹配图片内容或自定义指定数量的词库,再结合词云生成逻辑完成制作,步骤如下:
步骤1:确定词库与词频
- 如果要贴合图片内容:可以用Android自带的ML Kit图像标签识别API,提取图片中的核心元素,生成指定数量的关键词;也可以手动整理出你想要的N个词汇,并给每个词设置权重(权重越高,词在词云中显示越大)。
- 如果是自定义词库:直接列出你需要的指定数量词汇,比如10个、20个,搭配对应的权重值。
步骤2:Android平台生成词云
可以基于自定义绘制或现成的轻量库实现,这里给你一个核心逻辑示例:// 准备指定数量的词频数据(示例:5个词) Map<String, Integer> wordFrequency = new HashMap<>(); wordFrequency.put("自然", 8); wordFrequency.put("风景", 6); wordFrequency.put("山脉", 5); wordFrequency.put("河流", 4); wordFrequency.put("森林", 3); // 初始化词云生成器,绑定原始图片背景 WordCloud wordCloud = new WordCloud.Builder() .setWidth(800) .setHeight(600) .setBackgroundBitmap(yourOriginalBitmap) // 传入你要基于的原始图片 .setWordFrequency(wordFrequency) .setMaxWords(5) // 限制词数量为指定值 .setFontSizeRange(20, 60) .build(); // 生成词云Bitmap并显示 Bitmap wordCloudBitmap = wordCloud.generate(); yourImageView.setImageBitmap(wordCloudBitmap);注:如果需要更精细的样式控制(比如词的颜色、字体),可以扩展绘制逻辑,或调整库的配置参数。
2. 将图片转换为词云风格的ASCII图像
你目前使用的Android-Img2Ascii库默认用固定符号生成ASCII图,要改成词云风格(用指定词汇替代符号),需要修改库的核心字符匹配逻辑,以下是优化后的完整方案:
优化后的Img2Ascii类核心代码
package com.bachors.img2ascii; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Color; import android.os.AsyncTask; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.style.ForegroundColorSpan; import java.util.Random; import static java.lang.Math.round; public class Img2Ascii { // 替换成你需要的词云词汇(指定数量的词) private String[] wordCloudWords = {"自然", "风景", "山脉", "河流", "森林"}; // 对应词汇的权重:权重越高,出现概率越大 private int[] wordWeights = {8, 6, 5, 4, 3}; private Bitmap rgbImage; private Boolean color = false; private int quality = 3; private int qualityColor = 6; private Spannable response; private Listener listener; public Img2Ascii(){} public Img2Ascii bitmap(Bitmap rgbImage){ this.rgbImage = rgbImage; return this; } public Img2Ascii quality(int quality){ this.quality = quality; return this; } public Img2Ascii color(Boolean color){ this.color = color; return this; } public void convert(Listener listener) { this.listener = listener; new InstaApi().execute(); } @SuppressLint("StaticFieldLeak") private class InstaApi extends AsyncTask<String, Integer, Void> { @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Void doInBackground(String... arg0) { // 质量参数校验 if(color) { quality = quality + qualityColor; if (quality > 5 + qualityColor || quality < 1 + qualityColor) quality = 3 + qualityColor; }else{ if (quality > 5 || quality < 1) quality = 3; } String tx; SpannableStringBuilder span = new SpannableStringBuilder(); int width = rgbImage.getWidth(); int height = rgbImage.getHeight(); int charIndex = 0; Random randomizer = new Random(); for (int y = 0; y < height; y = y + quality) { for (int x = 0; x < width; x = x + quality) { int pixel = rgbImage.getPixel(x, y); int red = Color.red(pixel); int green = Color.green(pixel); int blue = Color.blue(pixel); if(color) { // 彩色模式:根据亮度匹配权重词汇 int brightness = red + green + blue; brightness = round(brightness / (765 / (wordCloudWords.length - 1))); tx = getWeightedRandomWord(randomizer); span.append(tx); // 给整个词汇设置对应像素的颜色 span.setSpan(new ForegroundColorSpan(Color.rgb(red, green, blue)), charIndex, charIndex + tx.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); charIndex += tx.length(); }else { // 黑白模式:根据亮度匹配对应词汇 int brightness = red + green + blue; brightness = round(brightness / (765 / (wordCloudWords.length - 1))); tx = wordCloudWords[brightness]; span.append(tx); charIndex += tx.length(); } } tx = "\n"; span.append(tx); publishProgress(y, height); charIndex++; if(isCancelled()) break; } response = span; return null; } // 根据权重随机获取词汇的工具方法 private String getWeightedRandomWord(Random random) { int totalWeight = 0; for (int weight : wordWeights) { totalWeight += weight; } int randomValue = random.nextInt(totalWeight); int currentWeight = 0; for (int j = 0; j < wordCloudWords.length; j++) { currentWeight += wordWeights[j]; if (randomValue < currentWeight) { return wordCloudWords[j]; } } return wordCloudWords[0]; // 默认返回第一个词 } protected void onProgressUpdate(Integer... progress) { int current = progress[0]; int total = progress[1]; int percentage = 100 * current / total; listener.onProgress(percentage); } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); listener.onResponse(response); } } public interface Listener { void onProgress(int percentage); void onResponse(Spannable text); } }
调用优化后的代码
TextView textAsc = findViewById(R.id.textAsc); Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.step0001); new Img2Ascii() .bitmap(image) .quality(4) // 1-5,值越小ASCII图越精细 .color(true) // 开启彩色词云风格ASCII .convert(new Img2Ascii.Listener() { @Override public void onProgress(int percentage) { textAsc.setText(String.valueOf(percentage) + " %"); } @Override public void onResponse(Spannable text) { textAsc.setText(text); } });
关键优化点
- 替换了原有的符号集为你指定的词云词汇,实现“词云风格”的ASCII效果
- 新增权重随机逻辑,让重要词汇更频繁地出现在图片对应区域
- 适配了多字符词汇的颜色设置,确保整个词汇都能显示对应像素的颜色
内容的提问来源于stack exchange,提问作者Arjun saini
相关产品推荐
相关产品推荐

