如何将点钞机串口输出的二进制字符串转换为灰度图像?
点钞机串口数据转黑白图像实现方案
问题背景
我正在从点钞机的串口读取数据,目标是提取钞票序列号。目前已通过代码将读取到的字节数组转换为二进制字符串,输出结果中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
相关产品推荐
相关产品推荐

