Android将字节数组从Camera API转换为颜色Mat对象openCV
Posted
技术标签:
【中文标题】Android将字节数组从Camera API转换为颜色Mat对象openCV【英文标题】:Android convert byte array from Camera API to color Mat object openCV 【发布时间】:2014-04-21 17:12:48 【问题描述】:我正在尝试从相机 API 中获取数据并进行颜色后处理。我的问题是,虽然我可以将 byte[] 对象转换为 Mat 对象,但我无法在没有收到错误的情况下获取颜色通道。我从以下帖子开始:How to get the Mat object from the Byte[] in openCV android? 但该实现不起作用。
以下是相关代码:
@Override
public void onPictureTaken(byte[] data, Camera camera)
// The camera preview was automatically stopped. Start it again.
mCamera.startPreview();
mCamera.setPreviewCallback(this);
// Write the image in a file (in jpeg format)
File pictureFile_interp = getOutputMediaFile(MEDIA_TYPE_IMAGE);
try
//Now try to convert and save.
Parameters params = camera.getParameters();
Size sz = params.getPictureSize();
//ERROR IN THE LINE BELOW!!!!
Mat raw = new Mat(sz.height,sz.width,CvType.CV_8UC4);
raw.put(0, 0, data);
Mat targ = Highgui.imdecode(raw, 0);
orig = new Mat();
Imgproc.cvtColor(targ, orig, Imgproc.COLOR_GRAY2RGB);
//Imgproc.cvtColor(targ, fixed, Imgproc.COLOR_BGR2RGB);
//now we have the target we want...let's interpolate.
interp = interpExperiment(orig,interpBy);
Highgui.imwrite(pictureFile_interp.toString(), interp);
finally
当我尝试该代码时,我得到一个异常:
Provided data element number should be multiple of the Mat channels count (3)
我将有问题的行替换为
Mat raw = new Mat(sz.height,sz.width,CvType.CV_8U);
raw.put(0, 0, data);
Mat targ = Highgui.imdecode(raw, 0);
我可以获得灰度图像。我做错了什么
Mat raw = new Mat(sz.height,sz.width,CvType.CV_8UC3);
?我已经查看了很多解决此问题的 *** 帖子,但没有一个适用于颜色矩阵。非常感谢任何帮助。
【问题讨论】:
异常发生在 raw.put(0,0,data);行 【参考方案1】:我找到了一个解决方法:使用 Bitmapfactory,您可以将 byte[] 数组转换为位图,然后您可以正确地将其转换为 Mat。
Bitmap bmp = BitmapFactory.decodeByteArray(data , 0, data.length);
Mat orig = new Mat(bmp.getHeight(),bmp.getWidth(),CvType.CV_8UC3);
Bitmap myBitmap32 = bmp.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(myBitmap32, orig);
Imgproc.cvtColor(orig, orig, Imgproc.COLOR_BGR2RGB,4);
似乎应该有更好的方法,但这是可行的。
【讨论】:
你找到更直接的方法了吗?【参考方案2】:public Mat Byte_to_Mat(byte[] data)
Mat jpegData = new Mat(1, data.length, CvType.CV_8UC1);
jpegData.put(0, 0, data);
Mat bgrMat = new Mat();
bgrMat = Highgui.imdecode(jpegData, Highgui.IMREAD_COLOR);
【讨论】:
此代码有效。我不知道如何使用Highgui.imdecode
但现在我知道了:) 谢谢@Idol
我不知道这怎么没有得到更多的选票。这对我有用,但遗憾的是它比解码为位图要慢:(【参考方案3】:
使用时:
raw.put(0, 0, data);
您通常会在点 (0,0) 处设置像素的所有通道值;因此,如果您有一个 3 通道图像,那么您将提供一个包含三个值的字节数组,例如:
byte data[] = 1,2,3
您可以一次设置多个像素,但关键是您的数据数组需要是多个通道,否则 opencv 将不知道查看所有像素值的内容。因此,例如,对于 3 通道 Mat,您可以:
byte data[] = 1,2,3,4,5,6;
这会将像素值 (0,0) 设置为 (1,2,3) 并将 (0,1) 设置为 (4,5,6)
但不是:
byte data[] = 1,2,3,4,5,6,7;
因为这是 7 个元素,不是 3 的倍数。
您看到的错误是因为您的数据数组长度不是通道数的倍数。
您应该检查数据数组的实际格式。根据我在设备上的经验,它往往是 YUV,它与 RGB 具有不同的尺寸,因此需要进行一些转换。
【讨论】:
啊,这是有道理的——我只是不确定 Mat 的正确结构是什么。不过,将数据格式设为 YUV 是有意义的。【参考方案4】:您将获得的数据很可能是YUV
格式。一般为1通道矩阵,如果是RGB或灰度,宽度相同,高度为图像高度的1.5倍。
Mat raw = new Mat(sz.height*1.5,sz.width,CvType.CV_8UC1); // YUV data
raw.put(0, 0, data);
orig = new Mat(sz.height, sz.height, CvType.CV_8UC4); // RGBA image
Imgproc.cvtColor(raw, orig, Imgproc.COLOR_YUV2RGBA_NV21); // This might vary depending on the camera image type
【讨论】:
谢谢! Mat 类似乎没有采用 (double,int,int) 的构造函数,因此我将 1.5*sz.height 转换为整数并进行了尝试。结果是一个完全绿色的图像。 转换为 RGBA 后?还是您保存了原始 Mat? 我尝试了发布的确切代码,结果是绿色图像。我认为类型转换中有些东西搞砸了(即您发布的第 4 行)。我正在使用 Nexus 5。我想我在某处看到这款手机保存为 YUV...我转换为位图,根据我最近的帖子它运行良好。【参考方案5】:@user3502402 所做的更改是绝对正确的。您只需将 Highgui.imdecode(raw, 1)
中的标志从 0 更改为 1,代码即可提供完美的彩色照片
【讨论】:
【参考方案6】:正确答案是===>
int width = camera.getParameters().getPreviewSize().width; // 获取相机预览尺寸的宽度
int height = camera.getParameters().getPreviewSize().height; // 获取相机预览尺寸的高度
Mat mat = new Mat(height + height/2,width, CvType.CV_8UC1); //为NV21 byte[]创建mat对象
mat.put(0, 0, 字节); //将byte[]放入mat生成raw mat
Mat mRgba = new Mat(); //创建新的mat对象,将NV21 mat转换为RGBA
Imgproc.cvtColor(mat, mRgba, Imgproc.COLOR_YUV2RGB_NV21,4); //将mat转换成新的rgba mat
Bitmap bitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888); //创建与相机预览大小相同的位图。哦。它会抛出错误。
Utils.matToBitmap(mRgba,bitmap); // 最后将 mat 对象转换为位图。
你好啊……
在个人项目上进行测试,它正在 100% 工作
【讨论】:
让我知道您在上面的代码中遇到了什么问题。然后投票;)以上是关于Android将字节数组从Camera API转换为颜色Mat对象openCV的主要内容,如果未能解决你的问题,请参考以下文章
将 Android camera2 api YUV_420_888 转换为 RGB
Android JNI:将cv :: Mat转换为jbyteArray
在Android camera2下将YUV_420_888转换为位图的图像不正确
使用 Android Camera2 API 进行人脸检测和画圆