基于现有图像数据创建自定义像素格式的 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 函数得到图像的宽度,后面会用得上。具体如以下代码:
DataBufferByte dataBufferByte = new DataBufferByte(new byte[][] {dataBytes}, dataSize); // 这里假定 dataBytes 保存了本地获取的图像数据,dataSize 为图像数据大小(总是比“w * h * 每像素字节数”计算出来要大一点)
ComponentSampleModel componentSampleModel = new ComponentSampleModel(DataBuffer.TYPE_BYTE, width, height, 4, bytesPerRow, new int[] {1, 2, 3, 0}); // 自定义 BufferedImage 中的图像格式,还是以字节来存储每个像素,具体构造函数的说明见 javadoc api
WritableRaster writableRaster = Raster.createWritableRaster(componentSampleModel, dataBufferByte, new Point(0, 0)); // 创建包含具体图像数据的栅格阵列
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); // 创建 RGB 颜色空间
int[] nBits = {8, 8, 8, 8}; // 对应源图像数据的 ARGB,因为源图像数据采用 32ARGB,等效于 4 个字节,每个字节按顺序分别表示 alpha、red、green、blue
ColorModel colorModel = new ComponentColorModel(colorSpace, nBits, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); // 创建颜色模式
BufferedImage bufferedImage = new BufferedImage(colorModel, writableRaster, false, null); // 构建自定义像素格式的 BufferedImage
这种方式就不会出现问题了,本地库捕获的实时摄像头图像能够正确填充到 Java 的 BufferedImage 中,而且效率非常高。
基于现有图像数据创建自定义像素格式的 BufferedImage的更多相关文章
- NumPy 基于已有数据创建数组
原文:Python Numpy 教程 章节 Numpy 介绍 Numpy 安装 NumPy ndarray NumPy 数据类型 NumPy 数组创建 NumPy 基于已有数据创建数组 NumPy 基 ...
- .Net Core WebApi返回的json数据,自定义日期格式
基本上所有的人都在DateTime类型的字段,被序列化成json的时候,遇到过可恨的Date(1294499956278+0800):但是又苦于不能全局格式化设置,比较难受.以往的方式,要么使用全局的 ...
- ASP.Net Core 返回的json数据,自定义日期格式
//代码位置:Startup.cs public void ConfigureServices(IServiceCollection services) { services.AddMvc() .Ad ...
- CAFFE学习笔记(四)将自己的jpg数据转成lmdb格式
1 引言 1-1 以example_mnist为例,如何加载属于自己的测试集? 首先抛出一个问题:在example_mnist这个例子中,测试集是人家给好了的.那么如果我们想自己试着手写几个数字然后验 ...
- Excel 2007中自定义数字格式前要了解的准则
要在Excel 2007中创建自定义数字格式,首先应了解自定义数字格式的准则,并从选择某一内置数字格式开始.然后,可以更改该格式的任意代码部分,从而创建自己的自定义数字格式. 数字格式最多可包含四个代 ...
- .net下灰度模式图像在创建Graphics时出现:无法从带有索引像素格式的图像创建graphics对象 问题的解决方案。
在.net下,如果你加载了一副8位的灰度图像,然后想向其中绘制一些线条.或者填充一些矩形.椭圆等,都需要通过Grahpics.FromImage创建Grahphics对象,而此时会出现:无法从带有索引 ...
- 无法从带有索引像素格式的图像创建graphics对象(转)
大家在用 .NET 做图片水印功能的时候, 很可能会遇到 “无法从带有索引像素格式的图像创建graphics对象”这个错误,对应的英文错误提示是“A Graphics object cannot be ...
- 无法从带有索引像素格式的图像创建graphics对象
大家在用 .NET 做图片水印功能的时候, 很可能会遇到 “无法从带有索引像素格式的图像创建graphics对象”这个错误,对应的英文错误提示是“A Graphics object cannot be ...
- .Net给图片加水印,并解决“无法从带有索引像素格式的图像创建Graphics对象”问题
using (Image img = Image.FromFile(savePath)) { //如果原图片是索引像素格式之列的,则需要转换 if (img.PixelFormat!=null) { ...
随机推荐
- NOIP模拟赛 czy的后宫4
czy的后宫4 [问题描述] czy有很多妹子,妹子虽然数量很多,但是质量不容乐观,她们的美丽值全部为负数(喜闻乐见). czy每天都要带N个妹子到机房,她们都有一个独一无二的美丽值,美丽值为-1到- ...
- hive sql 学习笔记
1.coalesce 语法: COALESCE ( expression [ ,...n ] ) 参数: expression 任何类型的表达式. 返回类型: 返回数据类型优先级最高的 express ...
- laravel中redis各方法的使用
在laravel中使用redis自带方法的时候会发现许多原生的方法都不存在了,laravel对其进行了重新的封装但是在文档中并没有找到相关的资料最后在 \vendor\predis\predis\sr ...
- IOC容器和Bean的配置实例
实验1: <!--实验1:通过IOC容器创建对象,并为属性赋值 --> <!-- 需要由IOC容器创建对象的全类名 --> <!-- 为了便于从IOC容器中获取book对 ...
- POJ:2632-Crashing Robots
Crashing Robots Time Limit: 1000MS Memory Limit: 65536K Description In a modernized warehouse, robot ...
- re--读书笔记【转】
原文链接 * 正则表达式入门 1.正则表达式的两种基本用途:搜索和替换. 2.正则表达式是一些用来匹配和处理文本的字符串. 小结:正则表达式是文本处理方面功能最强大的工具之一,正则表达式语言用来构造正 ...
- hdu4861 我只能说这是找规律=.=
先说明一下题意,因为开始我就没太读懂,感觉作者不是没交代清楚就是让做题的人自己去领悟,开始我不知道球是可以随便选的,然后那个关系式到底是最后一个数模p,还是整体模P........最后确定是整体模P ...
- Python虚拟机函数机制之闭包和装饰器(七)
函数中局部变量的访问 在完成了对函数参数的剖析后,我们再来看看,在Python中,函数的局部变量时如何实现的.前面提到过,函数参数也是一种局部变量.所以,其实局部变量的实现机制与函数参数的实现机制是完 ...
- django 缓存 实现
由于Django构建得是动态网站,每次客户端请求都要严重依赖数据库,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中, ...
- js---post与get请求的区别
request获取请求参数 最为常见的客户端传递参数方式有两种: 浏览器地址栏直接输入:一定是GET请求: 超链接:一定是GET请求: 表单:可以是GET,也可以是POST,这取决与<form& ...