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 ...
随机推荐
- Clipboard.js – 现代方式实现复制文本到剪贴板
复制文本到剪贴板应该并不难,目前已经有很成熟的 Flash 方法.但是 Flash 已经在很多场合不适用了,特别是随着 HTML5 技术的发展.今天推荐的这个 Clipboard.js 库不依赖 Fl ...
- MySQL之MySQL常用的函数方法
MySQL常用函数 本篇主要总结了一些在使用MySQL数据库中常用的函数,本篇大部分都是以实例作为讲解,如果有什么建议或者意见欢迎前来打扰. limit Select * from table ord ...
- js获取本机的外网/广域网ip地址
完整源代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...
- [deviceone开发]-do_Viewshower的动画效果示例
一.简介 do_Viewshower组件也支持View之间的过场动画,支持大概12种,这个示例随机的切换12种动画中的一种,而且每次切换的动画时间不一样.直观的展示12种动画的效果.适合初学者. 二. ...
- Flex布局窥探(一)
一.Flex布局是神马? Flex是Flexible Box的缩写,意为‘弹性布局’,用来为盒模型提供最大的灵活性. 任何容器都能被指定为Flex布局: .box{ display: flex; } ...
- Python统计学技术环境
http://www.lfd.uci.edu/~gohlke/pythonlibs/#sympy 1.1. Python 1.1.1. NumPy pip install numpy-1.11.0+m ...
- C C++ TDD单元测试非常好的书
http://product.china-pub.com/199003 测试驱动的嵌入式C语言开发 Test Driven Development for Embedded C <测试驱动的嵌入 ...
- iOS开发之──传感器使用 (转载)
在实际的应用开发中,会用到传感器,下面首先介绍一下iphone4的传感器,然后对一些传感器的开发的API作一简单介绍. AD:WOT2015 互联网运维与开发者大会 热销抢票 在实际的应用开发中,会用 ...
- APP远程调试及网络自动化测试
一:优测 腾讯旗下的测试服务 http://utest.qq.com/ 二:云测 http://www.testin.cn/ 三:testbird 1.进入这个网站,注册并且登录 https://dt ...
- 对URL编码
url支持26个英文字母.数字和少数几个特殊字符,因此,对于url中包含非标准url的字符时,就需要对其进行编码.iOS中提供了函数stringByAddingPercentEscapesUsingE ...