引言

最近啊,AI 图像生成技术发展迅速。本项目将带大家使用 Java 桌面端技术(Swing)结合火山引擎(豆包大模型),开发一款属于自己的“智能美颜相机”与“AI P图智能体” 。

致力于做到让咱用户可以通过调用本地摄像头实时拍照,或上传本地图片,结合自定义的“提示词”(Prompt),让 AI 大模型为你进行画面重绘、风格转换(如:赛博朋克风、二次元动漫风等)。


项目结构

AIimgpro/                        // 项目根目录 (Package: AIimgpro)
│
├── src/                         // 源代码目录
│   └── AIimgpro/                // 主包名
│       │
│       ├── ImageAgentUI.java    // 【视图层 & 入口】
│       │                        // 程序的启动入口(包含 main 方法)。负责 JFrame 窗体以及所有 UI 组件(按钮、文本框、画板)的初始化、尺寸设定与流式布局 (FlowLayout),并将按钮绑定到监听器。
│       │
│       ├── AgentListener.java   // 【控制层核心】
│       │                        // 事件监听与调度中心(实现 ActionListener)。负责处理各种用户交互(点击拍照、打开图片、生成图片等),调度 WebcamThread 控制相机,调用 AIService 请求大模型,并将结果渲染回 UI 面板。同时负责将拍摄的照片写入本地磁盘。
│       │
│       ├── WebcamThread.java    // 【并发处理层】
│       │                        // 独立的相机渲染线程(继承自 Thread)。通过 while(true) 循环不断从 webcam 抓取图像帧(BufferedImage),并重绘到 Graphics 画板上。通过独立线程避免了 UI 主线程被死循环卡死。
│       │
│       └── AIService.java       // 【服务层/网络层】
│                                // AI 接口通信服务类。封装了与“火山引擎豆包大模型”的所有网络交互细节。包括:将本地文件转为 Base64 Data URI、手动构建 JSON 请求体、发起带有超时控制的 HTTP POST 请求、解析返回的 JSON 获取 URL 并最终下载为图片对象。
│
├── lib/                         // 第三方依赖库目录
│   └── sarxos-webcam            // 调取本机底层摄像头的核心依赖包 (com.github.sarxos.webcam.Webcam)。
│
└── 存储目录/                     // 本地文件系统 (代码中硬编码为 D:\代码库\AIimgpro\相册)
    └── [时间戳].png              // 由 AgentListener 生成,用于缓存摄像头拍摄的原始画面,以便作为源文件发送给 AI 进行图生图处理。

项目准备

  • UI 界面: Java Swing 。

  • 硬件调用: 引入webcam库,用于驱动本地电脑摄像头并抓取实时画面 

  • 大模型 API: 注册并登录字节跳动“火山引擎”,开通图像创作模型(本项目使用 doubao-seedream-5-0-260128 模型),获取 API Key 。


具体项目解析

为了让大家快速抓住重点,我将对 UI 搭建等样板代码一笔带过,将核心篇幅留给 摄像头多线程渲染AI 接口对接

1. 界面搭建 (UI层) —— 简单带过

利用 JFrameFlowLayout 流式布局,我们可以快速把“打开相机”、“拍照”、“输入提示词”、“生成图片”等核心组件堆叠出来 。UI 层的主要任务就是将用户操作绑定到监听器(AgentListener)上。

import javax.swing.*;
import java.awt.*;

public class ImageAgentUI extends JFrame {
    public ImageAgentUI() {
        setTitle("Image Agent");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1100, 600);
        setLocationRelativeTo(null);
        setLayout(new FlowLayout());

        JButton openCameraButton = new JButton("打开相机");
        JButton takePhotoButton = new JButton("拍照");
        JButton closeCameraButton = new JButton("关闭相机");
        JButton openImageButton = new JButton("打开图片");
        JLabel promptLabel = new JLabel("提示词:");
        JTextField promptField = new JTextField(20);
        JButton generateButton = new JButton("生成图片");

        add(openCameraButton);
        add(closeCameraButton);
        add(takePhotoButton);
        add(openImageButton);
        add(promptLabel);
        add(promptField);
        add(generateButton);

        setVisible(true);

        Graphics g = getGraphics();

        //监听按钮点击事件
        AgentListener listener = new AgentListener();
        openCameraButton.addActionListener(listener);
        takePhotoButton.addActionListener(listener);
        openImageButton.addActionListener(listener);
        generateButton.addActionListener(listener);
        closeCameraButton.addActionListener(listener);
        listener.g = g;
        listener.promptField = promptField;
    }

    public static void main(String[] args) {
        new ImageAgentUI();
    }
}

2. 本地摄像头实时预览 ——解决主线程阻塞

当我一开始在做相机应用时,直接在主线程写一个 while(true) 循环读取画面,导致整个 UI 卡死无法点击。那么有了前车之鉴,我们使用正确的做法:单开一个子线程 WebcamThread

public class WebcamThread extends Thread {
    Graphics g;
    Webcam webcam;

    public void run() {
        while (true) {
            try {
                Thread.sleep(100); // 控制帧率,防止CPU占用过高
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            BufferedImage image = webcam.getImage();
            // 将实时画面直接绘制在画板上
            g.drawImage(image, 60, 100, 400, 400, null);
        }
    }
}

(核心点: 将获取到的 BufferedImage 通过 Graphics 对象持续重绘到面板的指定区域,形成视频流的视觉效果。)

3. 大模型 API 核心对接 (AIService) —— 【重中之重】

这是整个智能体的灵魂所在,负责与云端 AI 交互。其核心流程分为三步:

图片编码 -> 发送请求 -> 下载结果 

Step 3.1:将本地图片转为 Base64 (Data URI)

大模型的图生图接口通常不直接接收文件对象,我们需要将其转化为 Base64 字符串,并拼接成标准的 Data URI 格式 。

// 读取图片字节流
byte[] imageBytes = Files.readAllBytes(imageFile.toPath());
// 转换为 Base64 编码
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
// 获取图片MIME类型(如 image/png)并拼装 Data URI
String mimeType = detectMimeType(imageFile.getName());
String dataUri = "data:" + mimeType + ";base64," + base64Image;

Step 3.2:发送 HTTP POST 请求

我们使用 Java 11 提供的原生 HttpClient 发起请求 。需要特别注意超时时间,因为大模型生成图片属于高延迟操作,建议将超时时间设置在 60 秒到 120 秒之间,否则极易出现 TimeoutException

String jsonBody = buildRequestJson(prompt, dataUri); // 将提示词和图片组装成JSON

HttpClient client = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(30))
        .build();

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(API_URL))
        .header("Content-Type", "application/json")
        .header("Authorization", "Bearer " + apiKey) // 鉴权
        .POST(HttpRequest.BodyPublishers.ofString(jsonBody))
        .timeout(Duration.ofSeconds(120)) // ⚠️ 生成图片耗时较长,务必调大超时时间
        .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

Step 3.3:解析 JSON 并下载成图

如果 HTTP 状态码为 200,API 会返回一段 JSON,里面包含了生成好的图片 URL。为了保持项目轻量,我们没有引入外部 JSON 库,而是通过字符串截取 extractImageUrl 提取了 URL 。 拿到 URL 后,我们需要二次发起 GET 请求将其下载并转换为可以直接在 UI 上渲染的 BufferedImage 

// 提取在线图片URL
String imageUrl = extractImageUrl(body); 

// 二次请求,下载结果图片
HttpRequest imgRequest = HttpRequest.newBuilder()
        .uri(URI.create(imageUrl))
        .GET()
        .build();
HttpResponse<InputStream> imgResponse = client.send(imgRequest, HttpResponse.BodyHandlers.ofInputStream());

// 将输入流解码为 BufferedImage 对象返回给 UI 层
BufferedImage resultImage = ImageIO.read(imgResponse.body());
return resultImage;

4. 事件调度与文件保存

AgentListener 中,我们将 UI 动作与后台逻辑连接起来。比如点击“拍照”时,不仅要捕获当前帧,还要生成唯一文件名存盘,以备后续传给 AI 。这里使用当前时间戳来确保文件名不冲突 。

long timestamp = System.currentTimeMillis();
Date date = new Date(timestamp);
// 拼装时间字符串作为文件名: year-month-day-hour-minute-second
String time = (date.getYear() + 1900) + "-" + (date.getMonth() + 1) + ... ;
File imageFile = new File(path + "\\" + time + ".png");
ImageIO.write(image, "png", imageFile); // 保存到本地相册
selectedImage = imageFile; // 缓存选中的图片用于后续AI处理

这样就可以将拍照和上传的文件存在一个相册里,方便使用和查找


效果展示

(太可爱了!!!!!!!!!!!!!!!!!!!!!!!!!粉色也是!!!!)


进阶与优化

  • 阻塞UI问题: 目前代码中 generateImage() 被直接放在了事件监听器线程 (Event Dispatch Thread) 中执行。AI 生成需要几秒到十几秒,这段时间内 UI 会处于“假死”状态。

后续优化:可以将 AI 接口的调用放入 SwingWorker 或新的 Thread 中,并在调用前后加上“正在生成中...”的 Loading 提示。)

  • 内存泄漏: 摄像头不使用时,可以调用 webcam.close() 释放硬件资源,防止后台持续占用 。

项目总结

本项目以AI 图像生成为核心,打造了一款集摄像头实时预览、拍照保存、本地图片导入、AI 智能重绘于一体的桌面端图像创作工具。大家一起来试试吧!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐