opencv源码阅读之——iOS的两条接口UIImageToMat()和MatToUIImage()
本文为作者原创,未经允许不得转载;原文由作者发表在博客园: http://www.cnblogs.com/panxiaochun/p/5387743.html
在ios下开发基于opencv的程序时经常会用到两条接口,分别是UIImageToMat()和MatToUIImage(),这两条接口是UIImage与Mat之间的转换。关于这两条api的信息opencv文档里面没有给出太多的信息,所以,需要通过阅读源码来分析。
1.UIImageToMat的细节
关于这条api,我们总想知道返回的mat的一些细节,比如是几通道的,是否带alpha通道,色彩空间是RGBA还BGR的,我们都不清楚,带着这几个问题,我们一起来阅读源码:
void UIImageToMat(const UIImage* image,
cv::Mat& m, bool alphaExist) {
CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);
CGFloat cols = image.size.width, rows = image.size.height;
CGContextRef contextRef;
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;
if (CGColorSpaceGetModel(colorSpace) == )
{
m.create(rows, cols, CV_8UC1); // 8 bits per component, 1 channel
bitmapInfo = kCGImageAlphaNone;
if (!alphaExist)
bitmapInfo = kCGImageAlphaNone;
contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, ,
m.step[], colorSpace,
bitmapInfo);
}
else
{
m.create(rows, cols, CV_8UC4); // 8 bits per component, 4 channels
if (!alphaExist)
bitmapInfo = kCGImageAlphaNoneSkipLast |
kCGBitmapByteOrderDefault;
contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, ,
m.step[], colorSpace,
bitmapInfo);
}
CGContextDrawImage(contextRef, CGRectMake(, , cols, rows),
image.CGImage);
CGContextRelease(contextRef);
}
这个源码是在文件夹modules/imgcodecs/src/ ios_conversions.mm里面的。从源码可以看出,opencv会先把UIImage类型的image转化为CGImga,这是一个位图bitmap图像
@property(nullable, nonatomic,readonly) CGImageRef CGImage; // returns underlying CGImageRef or nil if CIImage based
The CGImageRef opaque type represents bitmap images and bitmap image masks, based on sample data that you supply. A bitmap (or sampled) image is a rectangular array of pixels, with each pixel representing a single sample or data point in a source image.
CGImageGetColorSpace会获取指定图像的色彩空间,如果指定的图像(也不能叫图像)是一个图像蒙板(image mask),则返回NULL,图像蒙板其实就是ps里面的蒙板,蒙板指定的区域才会显示,具体可以看ios文档说明。opencv的c++版不同于java版,java版里面的图像有width和height两个对象,c++里面是cols和rows,分别代表宽和高,其实就是Mat的列数和行数,表示不同。
然后获取图像的色彩模式CGColorSpaceGetModel,得到一个枚举值:
typedef CF_ENUM (int32_t, CGColorSpaceModel) {
kCGColorSpaceModelUnknown = -,
kCGColorSpaceModelMonochrome,
kCGColorSpaceModelRGB,
kCGColorSpaceModelCMYK,
kCGColorSpaceModelLab,
kCGColorSpaceModelDeviceN,
kCGColorSpaceModelIndexed,
kCGColorSpaceModelPattern
};
kCGColorSpaceModelMonochrome是单色图,也就是黑白的灰度图,如果是灰度图则通过CGBitmapContextCreate往cv::Mat类型的m里面的data写数据,
大小和原图一样,色彩空间也是和原图一样,这里就是单色图,没有alpha通道。如果不是灰度图,则把原来图片的色彩空间的色彩写进cv::Mat的data里,得到转换的m。
通过阅读源码可以知道,如果传进来的是单色灰度图,则返回的也是单色灰度图,没有alpha通道。如果传进来的是RGB 或者BGRA的,则会返回原图的色彩空间RGB或者 BGRA,其中A通道如果转换时没有指定,则默认是有的。
2.MatToUIImage的转换细节
下面来了解MatToUIImage的转换细节,源码:
UIImage* MatToUIImage(const cv::Mat& image) {
NSData *data = [NSData dataWithBytes:image.data
length:image.elemSize()*image.total()];
CGColorSpaceRef colorSpace;
if (image.elemSize() == ) {
colorSpace = CGColorSpaceCreateDeviceGray();
} else {
colorSpace = CGColorSpaceCreateDeviceRGB();
}
CGDataProviderRef provider =
CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
// Preserve alpha transparency, if exists
bool alpha = image.channels() == ;
CGBitmapInfo bitmapInfo = (alpha ? kCGImageAlphaLast : kCGImageAlphaNone) | kCGBitmapByteOrderDefault;
// Creating CGImage from cv::Mat
CGImageRef imageRef = CGImageCreate(image.cols,
image.rows,
,
* image.elemSize(),
image.step.p[],
colorSpace,
bitmapInfo,
provider,
NULL,
false,
kCGRenderingIntentDefault
);
// Getting UIImage from CGImage
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return finalImage;
}
首先会获取传入的矩阵的data原始数据,长度为image.elemSize()*image.total(),elemSize()会返回元素的大小(单位:字节bytes),详情可以看opencv的文档说明(其实就是通道数*通道元素大小,例如元素类型为CV_8UC3,它的大小其实就是3字节,每个通道一字节8位bit,三个通道)。image.total()返回图像的所有元素数量。
然后判断image的元素大小,如果为1字节,那么就设置色彩空间是单色灰度图gray(CV_8UC1),如果不是1字节,那么就设置色彩空间为RGB(所以通过MatToUIImage()转换的图像色彩空间都是RGB的),然后判断元素的大小是否为4字节,如果为4字节则是带alpha通道的,因为RGB各占一个通道,也就是各一个字节,第四个字节就是alpha通道。
CGDataProviderCreateWithCFData创建一个CGDataProviderRef对象(_bridge标记是xcode 在Core Foundation和Foundation对象之间的转换要通过Toll-Free bridge来对内存管理进行转换,只在ARC下有效)
CGImageCreate会通过参数创建一个bitmap位图图像,各参数可以看说明文档。再通过bitmap创建UIImage,所以通过阅读源码可以知道,图像的色彩空间是如果原图是单色灰度图,则UIImage的色彩空间为单色灰度图,如果不是,则默认为RGB,如果cv::Mat是带alpha通道,则转换的UIImage带Alpha通道
3.总结

UIImageToMat输出的mat默认带Alpha通道,可以选择不带alpha通道,在UIImageToMat()的第三个参数指定就行,MatToUIImga输出的UIImage默认为RGB类型
opencv源码阅读之——iOS的两条接口UIImageToMat()和MatToUIImage()的更多相关文章
- OpenCV源码阅读(1)---matx.h---mat类与vec类
matx.h matx类是opencv中的一个基础类,其位于core模块中,所执行的操作时opencv矩阵和向量的运算.如果熟悉基于matlab的图像处理,那么很容易想到,所有对图像的操作归根结底都是 ...
- [Go] gocron源码阅读-go语言中的切片接口和类型综合
// getCommands func getCommands() []cli.Command { command := cli.Command{ Name: "web", Usa ...
- OpenCV源码阅读(3)---base.hpp
base.h处于core模块中,是OpenCV的核心类.其作用是定义了OpenCV的基本错误类型,在程序运行出现错误是抛出错误,防止数据溢出.总而言之,其功能主要是考虑程序的健壮性. 头文件 #ifn ...
- OpenCV源码阅读(3)---matx.h---学习心得
在.h文件里定义类,可以通过内联函数的方法完成类基础函数的实现,这样就不需要额外写.cpp文件来写类的内容. 对于操作符重载,可以使用返回应用的方式减小内存开销 _Tp& someclass: ...
- OpenCV源码阅读(2)---matx.h---函数的内联实现
外部矩阵计算函数 namespace internal { template<typename _Tp, int m> struct Matx_DetOp { double operato ...
- 34 网络相关函数(二)——live555源码阅读(四)网络
34 网络相关函数(二)——live555源码阅读(四)网络 34 网络相关函数(二)——live555源码阅读(四)网络 2)socketErr 套接口错误 3)groupsockPriv函数 4) ...
- 【原】AFNetworking源码阅读(六)
[原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...
- 【原】AFNetworking源码阅读(五)
[原]AFNetworking源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中提及到了Multipart Request的构建方法- [AFHTTP ...
- 【原】AFNetworking源码阅读(四)
[原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...
随机推荐
- FingerprintJS - 在浏览器端实现指纹识别
FingerprintJS 是一个快速的浏览器指纹库,纯 JavaScript 实现,没有依赖关系.默认情况下,使用 Murmur Hash 算法返回一个32位整数.Hash 函数可以很容易地更换. ...
- CodeIgniter_2 路由中定义伪静态 直接映射到相关的控制器
某些情况下 隐藏路径信息 使用伪静态定义: RewriteRule ^no/torrent(.*)$ /index.php/torrent/doit/$1 CodeIgniter会自动识别到 no 控 ...
- jQuery 重要的知识点归纳
jQuery 对象 jQuery 对象就是通过 jQuery 包装 DOM 对象后产生的对象. jQuery 对象是 jQuery 独有的. 只有 jQuery 对象才能使用 jQuery 的方法,在 ...
- JavaScript 数据类型判断
JavaScript 的数据类型分为两类:原始类型(基本类型)和对象类型(引用类型).原始类型包括数字.字符串和布尔值,另外有两个特殊的原始值:null 和 undefined,除此之外的都是对象.对 ...
- div,span,p等转换成可编辑
当前它能够将任意不可编辑的标签(span.div.p...等)转换成可编辑的text input.password.textarea.下拉列表(drop-down list)等标签.你可以利用它的ed ...
- Sharepoint学习笔记—习题系列--70-576习题解析 -(Q69-Q71)
Question 69 You are designing an extranet site using SharePoint 2010. This site must allow employees ...
- UIModalPresentationStyle和UIModalTransitionStyle
一.主要用途 弹出模态ViewController是IOS变成中很有用的一个技术,UIKit提供的一些专门用于模态显示的ViewController,如UIImagePickerController等 ...
- 配置redis外网可访问,并只允许指定的ip可访问redis
开启redis 允许外网IP 访问 在 Linux 中安装了redis 服务,当在客户端通过远程连接的方式连接时,报could not connect错误. 错误的原因很简单,就是没有连接上redis ...
- 通过终端编译链接运行C文件
1.创建c文件 touch demo.c 2.编辑c代码 3.编译(预编译.检查语法.编译).链接 3.1.指令:cc -c demo.c 正常情况下,会生成一个demo.o的二进制文件(即:目标 ...
- NSURLConnection获取一个MP3文件
NSURLConnection网络请求 直接上代码-这个没什么说的,你们自己有兴趣可以自己试试 代码 #import "ViewController.h" @interface V ...