我们都知道在我们android程序中一个图片的表达是使用的Bitamp来存储的,而在Opencv中图片的存储是Mat矩阵的形式。所以如果我们想把我们android的图片传给opencv,就要先把bitmap转成Mat类型,所以我们先来了解以下Mat是个什么东西。
一个图片都是有很多像素点组成的,所以mat矩阵就是保存我们这个图片的像素点的集合。每个像素点又都是又RGBA颜色组成,所以在Opencv中Mat分为单通道和多通道存储,这个就很好理解了,比如我们有一个灰色图片Mat在存储是就是单通道的,还有我们的图片是彩色的BGR这个在Mat中就是三通道,BGRA四通到等等。这个大家可以自行去百度了解。
在我们把Bitmap转成Mat之前我们要知道一个对应关系,由上面介绍可以Mat矩阵保存图片时候是分不同的通道的。我们知道android中bitmap在创建的时候也是有类型的比如:RGBA_8888,所以对应关系如下:
RGBA_8888 -> CV_8UC4 四颜色通道
RGB_565 -> CV_8UC2 三颜色通道
GRAY -> CV_8UC1 单通道(黑白)
所以我们在做Bitmap转Mat时候要根据Bitamp的类型来转化使用不同的通道,不然会出错。因为不同的通道代表的mat开辟的内存不一样,比如我们Mat矩阵中的一个像素点A:
如果我们的图片是 单通道 A = 白色/黑色(0--255)大小;
三颜色通道 A = R(0--255)G(0--255)B(0--255);
四颜色通道 A = R(0--255)G(0--255)B(0--255)A(0--255);
由此可见通道不一样,创建Mat的大小是不一样的,所以要一一对应。
通过上述的分析我们简单的了解了Mat,那么下面就上代码:
Bitmap转Mat:
int BitmapUtils::Bitmap2mat(JNIEnv *env, jobject bitmap, Mat *mat) {
void *addrPtr;
AndroidBitmap_lockPixels(env, bitmap, &addrPtr);
AndroidBitmapInfo bitmapInfo;
AndroidBitmap_getInfo(env, bitmap, &bitmapInfo);
Mat createM(bitmapInfo.height, bitmapInfo.width, CV_8UC4);
if (bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
Mat tep(bitmapInfo.height, bitmapInfo.width, CV_8UC4, addrPtr);
tep.copyTo(createM);
} else if (bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGB_565) {
Mat tep(bitmapInfo.height, bitmapInfo.width, CV_8UC2, addrPtr);
cvtColor(tep, createM, COLOR_BGR5652RGBA);
}
createM.copyTo(*mat);
createM.release();
AndroidBitmap_unlockPixels(env, bitmap);
return 0;
}
里面有一些android ndk 提供的类 AndroidBitmapInfo 我们还记得上一篇中我们在CMakeList中添加了一个库 ‘jnigraphics’这个就是我们android底层的C++代码,我们用的Bitamp就是用这个库转化到native层然后进行处理的。也是我们android源码的一部分。
Mat转Bitmap:
int BitmapUtils::Mat2Bitmap(JNIEnv *env, jobject bitmap, Mat &mat) {
AndroidBitmapInfo info;
AndroidBitmap_getInfo(env, bitmap, &info);
void *pixels;
//锁定 bitmap
AndroidBitmap_lockPixels(env, bitmap, &pixels);
__android_log_print(ANDROID_LOG_ERROR, "Mat2Bitmap-RECT-", "%d", mat.cols);
if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) { //bitmap
Mat tmp(info.height, info.width, CV_8UC4, pixels);
if (mat.type() == CV_8UC1) {
cvtColor(mat, tmp, COLOR_GRAY2RGBA);
} else if (mat.type() == CV_8UC2) {
cvtColor(mat, tmp, COLOR_BGR5652BGRA);
} else if (mat.type() == CV_8UC4) {
mat.copyTo(tmp);
}
} else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) {
Mat tmp(info.height, info.width, CV_8UC2, pixels);
if (mat.type() == CV_8UC1) {
cvtColor(mat, tmp, COLOR_GRAY2BGR565);
} else if (mat.type() == CV_8UC2) {
mat.copyTo(tmp);
} else if (mat.type() == CV_8UC4) {
cvtColor(mat, tmp, COLOR_RGBA2BGR565);
}
}
return 0;
}
简单了解图像在Opencv中储存的形式和怎么把android的图片转化成OPencv能处理的图片,从bitmap转化成Mat之后,接下来就是对图像数据的操作。