zoukankan      html  css  js  c++  java
  • 基于现有图像数据创建自定义像素格式的 BufferedImage

    在最近的一个项目中,需要实现 Mac OS X 环境下的摄像头图像实时捕获并转换为 Java 中的 BufferedImage 对象。首先通过开发一个本地库实现 Mac OS X 的摄像头图像捕获,采用的是 Apple 推荐的新的 AVFoundation 框架,摄像头图像格式设置为 kCVPixelFormatType_32ARGB(设置成其他的测试了无法得到图像,系统不支持),通过 delegate 方式得到 CMSampleBufferRef 类型的 sample buffer 后,需要通过 CMSampleBufferGetImageBuffer 函数将其转换为 CVImageBufferRef 类型的图像缓冲(因为这里捕获的是图像数据,并不是采样数据,所以不能用 CMSampleBufferGetDataBuffer)。然后通过 CVPixelBufferGetBaseAddress 函数得到图像缓冲的首地址,用 CVPixelBufferGetDataSize 函数得到图像缓冲区数据大小,但这里千万要注意,不要以为这时获取的图像缓冲区数据就可以通过Java 的 Raster 和 DataBuffer 等方式来直接填充 Java 中的 BufferedImage(这里假定 BufferedImage 采用 TYPE_INT_ARGB,因为想着对应 kCVPixelFormatType_32ARGB)。因为这么做了会发现图像颜色完全是错乱的,事实上,我们通过计算就可以知道,对应高、宽下的 TYPE_INT_ARGB 格式的 BufferedImage 图像数据大小为 width × height × 4 字节(因为这时一个像素为 int 类型,4 字节大小),但 CVPixelBufferGetDataSize 得到的图像数据大小总比前者要多 4 个字节,可能是保存了其他的一些信息。所以这里直接创建 TYPE_INT_ARGB 格式的 BufferedImage 然后用 Raster 以及 DataBuffer 等方式进行填充是行不通的。

    这里就需要采取另外的方式,用 DataBufferByte、ComponentSampleModel、WritableRaster、ColorSpace、ColorModel 来构建 BufferedImage,其实也是使用了 BufferedImage 的另一种不常用的、但效率非常高的构造函数模式。当然,前提是还需要通过 CVPixelBufferGetBytesPerRow 函数得到图像中每个扫描行的字节数,通过 CVPixelBufferGetHeight 函数得到图像的高度,通过 CVPixelBufferGetWidth 函数得到图像的宽度,后面会用得上。具体如以下代码:

    1 DataBufferByte dataBufferByte = new DataBufferByte(new byte[][] {dataBytes}, dataSize); // 这里假定 dataBytes 保存了本地获取的图像数据,dataSize 为图像数据大小(总是比“w * h * 每像素字节数”计算出来要大一点)
    2 ComponentSampleModel componentSampleModel = new ComponentSampleModel(DataBuffer.TYPE_BYTE, width, height, 4, bytesPerRow, new int[] {1, 2, 3, 0}); // 自定义 BufferedImage 中的图像格式,还是以字节来存储每个像素,具体构造函数的说明见 javadoc api
    3 WritableRaster writableRaster = Raster.createWritableRaster(componentSampleModel, dataBufferByte, new Point(0, 0)); // 创建包含具体图像数据的栅格阵列
    4 ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); // 创建 RGB 颜色空间
    5 int[] nBits = {8, 8, 8, 8}; // 对应源图像数据的 ARGB,因为源图像数据采用 32ARGB,等效于 4 个字节,每个字节按顺序分别表示 alpha、red、green、blue
    6 ColorModel colorModel = new ComponentColorModel(colorSpace, nBits, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); // 创建颜色模式
    7 BufferedImage bufferedImage = new BufferedImage(colorModel, writableRaster, false, null); // 构建自定义像素格式的 BufferedImage

    这种方式就不会出现问题了,本地库捕获的实时摄像头图像能够正确填充到 Java 的 BufferedImage 中,而且效率非常高。

  • 相关阅读:
    yocto/bitbake 学习资源
    QEMU/KVM学习资源
    ubuntu 中创建和删除用户
    git 重命名本地和远程分支
    Ubuntu 上搭建 FTP 服务器
    gdb 常见用法
    git log 显示与特定文件相关的 commit 信息
    基于 qemu system mode 运行 arm 程序
    基于 qemu user mode 运行 aarch64 程序
    checking in(airport)
  • 原文地址:https://www.cnblogs.com/cyberniuniu/p/5026156.html
Copyright © 2011-2022 走看看