You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何制作指定词数的原图词云及图片转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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:23:34