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

如何将点钞机串口输出的二进制字符串转换为灰度图像?

点钞机串口数据转黑白图像实现方案

问题背景

我正在从点钞机的串口读取数据,目标是提取钞票序列号。目前已通过代码将读取到的字节数组转换为二进制字符串,输出结果中1对应黑色像素(代表钞票序列号),0对应白色像素(代表背景)。现需将这些二进制字符串转换为黑白图像文件,寻求技术实现帮助。

现有代码

二进制字符串输出代码

public void serialEvent(SerialPortEvent serialPortEvent) {
    ArrayList<String> list = new ArrayList<>();
    String s1 = new String();

    if (serialPortEvent.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {
        return;
    }
    byte[] readBuffer = new byte[comPort.bytesAvailable()];
    int numRead = comPort.readBytes(readBuffer, readBuffer.length);

    for (Byte b : readBuffer) {
        // 判断是否为图像数据(图像数据超过500字节,其他数据小于500字节)
        if (numRead <= 500) {
            break;
        }

        s1 = String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0');

        // 换行标识字节,遇到则换行
        if (s1.equals("01000101")) {
            System.out.println();
            continue;
        }

        System.out.print(s1);
    }
}

ASCII输出尝试代码

public void serialEvent(SerialPortEvent serialPortEvent) {
    InputStream in = comPort.getInputStream();
    Reader in2 = new InputStreamReader(in, StandardCharsets.US_ASCII);
    try {
        for (int j = 0; j < 10000; ++j) {
            System.out.print((char)in2.read());
            in.close();
        }
    } catch (Exception e) { 
        e.printStackTrace(); 
    }
    comPort.closePort();
}

实现方案

步骤1:完整收集图像二进制数据

修正数据收集逻辑,确保完整获取所有图像相关的二进制位:

  • 将if (numRead <=500) break移到循环前,避免中途中断图像数据读取
  • 使用StringBuilder收集所有二进制位,遇到换行标识时记录行分隔位置

步骤2:构建二维像素数组

根据收集到的二进制数据和换行位置确定图像宽高,将每个二进制位转换为对应像素值:

  • 0对应白色像素(RGB值0xFFFFFF)
  • 1对应黑色像素(RGB值0x000000)

步骤3:生成并保存图像

借助Java的BufferedImage和ImageIO类完成像素数据到图像文件的转换。

完整实现代码

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public void serialEvent(SerialPortEvent serialPortEvent) {
    if (serialPortEvent.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {
        return;
    }

    byte[] readBuffer = new byte[comPort.bytesAvailable()];
    int numRead = comPort.readBytes(readBuffer, readBuffer.length);

    // 仅处理图像数据(超过500字节)
    if (numRead <= 500) {
        return;
    }

    StringBuilder imageBinary = new StringBuilder();
    List<Integer> lineBreaks = new ArrayList<>(); // 记录每行结束的索引位置

    for (Byte b : readBuffer) {
        String s1 = String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0');
        
        // 遇到换行标识,记录当前位置并跳过
        if (s1.equals("01000101")) {
            lineBreaks.add(imageBinary.length());
            continue;
        }
        
        imageBinary.append(s1);
    }

    // 计算图像宽高:取第一个换行前的长度作为宽度,换行次数作为高度
    if (lineBreaks.isEmpty()) {
        System.err.println("未检测到换行标识,无法确定图像尺寸");
        return;
    }
    int width = lineBreaks.get(0);
    int height = lineBreaks.size();

    // 创建RGB格式的BufferedImage
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

    // 填充像素数据
    int currentIndex = 0;
    for (int y = 0; y < height; y++) {
        int lineEnd = lineBreaks.get(y);
        for (int x = 0; x < width; x++) {
            char bit = imageBinary.charAt(currentIndex++);
            int rgb = bit == '0' ? 0xFFFFFF : 0x000000;
            image.setRGB(x, y, rgb);
        }
    }

    // 保存图像到文件
    try {
        ImageIO.write(image, "PNG", new File("钞票序列号.png"));
        System.out.println("图像已成功保存");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

注意事项

  • 需确保串口数据读取的完整性,避免因缓存不足导致数据丢失
  • 若实际换行标识的二进制字符串不是01000101,需根据输出调整判断条件
  • 若每行二进制位长度不一致,需额外添加尺寸适配逻辑

内容的提问来源于stack exchange,提问作者Danilo Djurovic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 05:50:27