[iOS OpenCV的使用,灰度和二值化]
看网上方法很多,但版本都不够新,我看了网上一些知识,总结了下,来个最新版Xcode6.1的.
最近主要想做iOS端的车牌识别,所以开始了解OpenCV。有兴趣的可以跟我交流下哈。
一.Opencv的使用:
步骤:
1.从官网下载iOS版本的Opencv2.framework。
2.拖进工程,选择copy items if needed
3.进入building settings,设置Framework SearchPath:
设置成$(PROJECT_DIR)/Newtest,这个Newtest是你的项目名,主要是为了定位到你存放的Opencv2.framework所在位置。
4.使用Opencv的方式:第(1)种全局pch:(不推荐)新建pch文件,修改成:
#ifdef __cplusplus
#import <opencv2/opencv.hpp>
#endif
并在building setting里的 Incease Sharing of Precompiled Headers项目处:
设置成$(PROJECT_DIR)/Newtest,同理,这个Newtest是你的项目名,主要是为了定位到你存放的PCH文件所在位置。
PCH文件以前建工程默认生成,是全局性质的import。Xcode6不再自动生成。苹果引导开发者在某个类要用时才用。
第(2)种:在需要的地方#import <opencv2/opencv.hpp>
这里的重点是:使用opencv的类名一定要改成.mm!!
比如你专门写了各一个处理图片的类,Imageprocess。可以在.h里加入。
二:灰度化和二值化的主要实现过程:
其实过程就是这样:
UIImage(iOS图像类)-> cv::Mat(OpenCV图像类) -> Opencv灰度或二值处理函数 -> UIImage
三:Opencv类Imageprocess代码参考:
Imageprocess.h
- //
- // Imageprocess.h
- // Chepaishibie
- //
- // Created by shen on 15/1/28.
- // Copyright (c) 2015年 shen. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import <opencv2/opencv.hpp>
- #import <UIKit/UIKit.h>
- @interface Imageprocess : UIViewController
- - (cv::Mat)cvMatFromUIImage:(UIImage *)image;
- - (UIImage *)UIImageFromCVMat:(cv::Mat)cvMat;
- - (IplImage *)CreateIplImageFromUIImage:(UIImage *)image;
- - (UIImage *)UIImageFromIplImage:(IplImage *)image;
- - (UIImage *)Grayimage:(UIImage *)srcimage;
- - (UIImage *)Erzhiimage:(UIImage *)srcimage;
- int Otsu(unsigned char* pGrayImg , int iWidth , int iHeight);
- @end
Imageprocess.mm 里面包含了很多函数:
主要是 UIImage->cv::Mat ,cv::Mat->UIImage,UIImage->IplImage,IplImage->UIImage, 灰度化,二值化等,还有个OSTU计算阈值的方法。
- //
- // Imageprocess.mm
- // Chepaishibie
- //
- // Created by shen on 15/1/28.
- // Copyright (c) 2015年 shen. All rights reserved.
- //
- #import "Imageprocess.h"
- @implementation Imageprocess
- #pragma mark - opencv method
- // UIImage to cvMat
- - (cv::Mat)cvMatFromUIImage:(UIImage *)image
- {
- CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);
- CGFloat cols = image.size.width;
- CGFloat rows = image.size.height;
- cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels
- CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to data
- cols, // Width of bitmap
- rows, // Height of bitmap
- , // Bits per component
- cvMat.step[], // Bytes per row
- colorSpace, // Colorspace
- kCGImageAlphaNoneSkipLast |
- kCGBitmapByteOrderDefault); // Bitmap info flags
- CGContextDrawImage(contextRef, CGRectMake(, , cols, rows), image.CGImage);
- CGContextRelease(contextRef);
- CGColorSpaceRelease(colorSpace);
- return cvMat;
- }
- // CvMat to UIImage
- -(UIImage *)UIImageFromCVMat:(cv::Mat)cvMat
- {
- NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()];
- CGColorSpaceRef colorSpace;
- if (cvMat.elemSize() == ) {
- colorSpace = CGColorSpaceCreateDeviceGray();
- } else {
- colorSpace = CGColorSpaceCreateDeviceRGB();
- }
- CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
- // Creating CGImage from cv::Mat
- CGImageRef imageRef = CGImageCreate(cvMat.cols, //width
- cvMat.rows, //height
- , //bits per component
- * cvMat.elemSize(), //bits per pixel
- cvMat.step[], //bytesPerRow
- colorSpace, //colorspace
- kCGImageAlphaNone|kCGBitmapByteOrderDefault,// bitmap info
- provider, //CGDataProviderRef
- NULL, //decode
- false, //should interpolate
- kCGRenderingIntentDefault //intent
- );
- // Getting UIImage from CGImage
- UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
- CGImageRelease(imageRef);
- CGDataProviderRelease(provider);
- CGColorSpaceRelease(colorSpace);
- return finalImage;
- }
- //由于OpenCV主要针对的是计算机视觉方面的处理,因此在函数库中,最重要的结构体是IplImage结构。
- // NOTE you SHOULD cvReleaseImage() for the return value when end of the code.
- - (IplImage *)CreateIplImageFromUIImage:(UIImage *)image {
- // Getting CGImage from UIImage
- CGImageRef imageRef = image.CGImage;
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- // Creating temporal IplImage for drawing
- IplImage *iplimage = cvCreateImage(
- cvSize(image.size.width,image.size.height), IPL_DEPTH_8U,
- );
- // Creating CGContext for temporal IplImage
- CGContextRef contextRef = CGBitmapContextCreate(
- iplimage->imageData, iplimage->width, iplimage->height,
- iplimage->depth, iplimage->widthStep,
- colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrderDefault
- );
- // Drawing CGImage to CGContext
- CGContextDrawImage(
- contextRef,
- CGRectMake(, , image.size.width, image.size.height),
- imageRef
- );
- CGContextRelease(contextRef);
- CGColorSpaceRelease(colorSpace);
- // Creating result IplImage
- IplImage *ret = cvCreateImage(cvGetSize(iplimage), IPL_DEPTH_8U, );
- cvCvtColor(iplimage, ret, CV_RGBA2BGR);
- cvReleaseImage(&iplimage);
- return ret;
- }
- // NOTE You should convert color mode as RGB before passing to this function
- - (UIImage *)UIImageFromIplImage:(IplImage *)image {
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- // Allocating the buffer for CGImage
- NSData *data =
- [NSData dataWithBytes:image->imageData length:image->imageSize];
- CGDataProviderRef provider =
- CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
- // Creating CGImage from chunk of IplImage
- CGImageRef imageRef = CGImageCreate(
- image->width, image->height,
- image->depth, image->depth * image->nChannels, image->widthStep,
- colorSpace, kCGImageAlphaNone|kCGBitmapByteOrderDefault,
- provider, NULL, false, kCGRenderingIntentDefault
- );
- // Getting UIImage from CGImage
- UIImage *ret = [UIImage imageWithCGImage:imageRef];
- CGImageRelease(imageRef);
- CGDataProviderRelease(provider);
- CGColorSpaceRelease(colorSpace);
- return ret;
- }
- #pragma mark - custom method
- // OSTU算法求出阈值
- int Otsu(unsigned char* pGrayImg , int iWidth , int iHeight)
- {
- if((pGrayImg==)||(iWidth<=)||(iHeight<=))return -;
- int ihist[];
- int thresholdValue=; // „–÷µ
- int n, n1, n2 ;
- double m1, m2, sum, csum, fmax, sb;
- int i,j,k;
- memset(ihist, , sizeof(ihist));
- n=iHeight*iWidth;
- sum = csum = 0.0;
- fmax = -1.0;
- n1 = ;
- for(i=; i < iHeight; i++)
- {
- for(j=; j < iWidth; j++)
- {
- ihist[*pGrayImg]++;
- pGrayImg++;
- }
- }
- pGrayImg -= n;
- for (k=; k <= ; k++)
- {
- sum += (double) k * (double) ihist[k];
- }
- for (k=; k <=; k++)
- {
- n1 += ihist[k];
- if(n1==)continue;
- n2 = n - n1;
- if(n2==)break;
- csum += (double)k *ihist[k];
- m1 = csum/n1;
- m2 = (sum-csum)/n2;
- sb = (double) n1 *(double) n2 *(m1 - m2) * (m1 - m2);
- if (sb > fmax)
- {
- fmax = sb;
- thresholdValue = k;
- }
- }
- return(thresholdValue);
- }
- -(UIImage *)Grayimage:(UIImage *)srcimage{
- UIImage *resimage;
- //openCV二值化过程:
- /*
- //1.Src的UIImage -> Src的IplImage
- IplImage* srcImage1 = [self CreateIplImageFromUIImage:srcimage];
- //2.设置Src的IplImage的ImageROI
- int width = srcImage1->width;
- int height = srcImage1->height;
- printf("图片大小%d,%d\n",width,height);
- // 分割矩形区域
- int x = 400;
- int y = 1100;
- int w = 1200;
- int h = 600;
- //cvSetImageROI:基于给定的矩形设置图像的ROI(感兴趣区域,region of interesting)
- cvSetImageROI(srcImage1, cvRect(x, y, w , h));
- //3.创建新的dstImage1的IplImage,并复制Src的IplImage
- IplImage* dstImage1 = cvCreateImage(cvSize(w, h), srcImage1->depth, srcImage1->nChannels);
- //cvCopy:如果输入输出数组中的一个是IplImage类型的话,其ROI和COI将被使用。
- cvCopy(srcImage1, dstImage1,0);
- //cvResetImageROI:释放基于给定的矩形设置图像的ROI(感兴趣区域,region of interesting)
- cvResetImageROI(srcImage1);
- resimage = [self UIImageFromIplImage:dstImage1];
- */
- //4.dstImage1的IplImage转换成cvMat形式的matImage
- cv::Mat matImage = [self cvMatFromUIImage:srcimage];
- cv::Mat matGrey;
- //5.cvtColor函数对matImage进行灰度处理
- //取得IplImage形式的灰度图像
- cv::cvtColor(matImage, matGrey, CV_BGR2GRAY);// 转换成灰色
- //6.使用灰度后的IplImage形式图像,用OSTU算法算阈值:threshold
- //IplImage grey = matGrey;
- resimage = [self UIImageFromCVMat:matGrey];
- /*
- unsigned char* dataImage = (unsigned char*)grey.imageData;
- int threshold = Otsu(dataImage, grey.width, grey.height);
- printf("阈值:%d\n",threshold);
- //7.利用阈值算得新的cvMat形式的图像
- cv::Mat matBinary;
- cv::threshold(matGrey, matBinary, threshold, 255, cv::THRESH_BINARY);
- //8.cvMat形式的图像转UIImage
- UIImage* image = [[UIImage alloc ]init];
- image = [self UIImageFromCVMat:matBinary];
- resimage = image;
- */
- return resimage;
- }
- -(UIImage *)Erzhiimage:(UIImage *)srcimage{
- UIImage *resimage;
- //openCV二值化过程:
- /*
- //1.Src的UIImage -> Src的IplImage
- IplImage* srcImage1 = [self CreateIplImageFromUIImage:srcimage];
- //2.设置Src的IplImage的ImageROI
- int width = srcImage1->width;
- int height = srcImage1->height;
- printf("图片大小%d,%d\n",width,height);
- //
- // 分割矩形区域
- int x = 400;
- int y = 1100;
- int w = 1200;
- int h = 600;
- //cvSetImageROI:基于给定的矩形设置图像的ROI(感兴趣区域,region of interesting)
- cvSetImageROI(srcImage1, cvRect(x, y, w , h));
- //3.创建新的dstImage1的IplImage,并复制Src的IplImage
- IplImage* dstImage1 = cvCreateImage(cvSize(w, h), srcImage1->depth, srcImage1->nChannels);
- //cvCopy:如果输入输出数组中的一个是IplImage类型的话,其ROI和COI将被使用。
- cvCopy(srcImage1, dstImage1,0);
- //cvResetImageROI:释放基于给定的矩形设置图像的ROI(感兴趣区域,region of interesting)
- cvResetImageROI(srcImage1);
- resimage = [self UIImageFromIplImage:dstImage1];
- */
- //4.dstImage1的IplImage转换成cvMat形式的matImage
- cv::Mat matImage = [self cvMatFromUIImage:srcimage];
- cv::Mat matGrey;
- //5.cvtColor函数对matImage进行灰度处理
- //取得IplImage形式的灰度图像
- cv::cvtColor(matImage, matGrey, CV_BGR2GRAY);// 转换成灰色
- //6.使用灰度后的IplImage形式图像,用OSTU算法算阈值:threshold
- IplImage grey = matGrey;
- unsigned char* dataImage = (unsigned char*)grey.imageData;
- int threshold = Otsu(dataImage, grey.width, grey.height);
- printf("阈值:%d\n",threshold);
- //7.利用阈值算得新的cvMat形式的图像
- cv::Mat matBinary;
- cv::threshold(matGrey, matBinary, threshold, , cv::THRESH_BINARY);
- //8.cvMat形式的图像转UIImage
- UIImage* image = [[UIImage alloc ]init];
- image = [self UIImageFromCVMat:matBinary];
- resimage = image;
- return resimage;
- }
- @end
四:可能问题:
1.出现'list' file not found: 检查类名是否改成.mm了!还不行的话,在Build Phases 中加入库:libc++.dylib 试试。
2.arm64不支持的问题:在Building settings里Build Active Architecture Only改为No,然后下面Valid Architectures把arm64删了。
五:样例参考:有两个很好的例子,一个是二值,一个是图像匹配。
1.二值 https://github.com/zltqzj/ios_opencv_divide
2.图像匹配 https://github.com/jimple/OpenCVSample
[iOS OpenCV的使用,灰度和二值化]的更多相关文章
- OpenCV图像的全局阈值二值化函数(OTSU)
cv::threshold(GrayImg, Bw, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);//灰度图像二值化 CV_THRESH_OTSU是提取图像最 ...
- OpenCV中对图像进行二值化的关键函数——cvThreshold()。
函数功能:采用Canny方法对图像进行边缘检测 函数原型: void cvThreshold( const CvArr* src, CvArr* dst, double threshold, doub ...
- VB6之图像灰度与二值化
老代码备忘,我对图像处理不是太懂. 注:部分代码引援自网上,话说我到底自己写过什么代码... Private Declare Function GetBitmapBits Lib "gdi3 ...
- opencv 对RGB图像直接二值化
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace st ...
- opencv中对图片的二值化操作并提取特定颜色区域
一.最近因为所在的实习公司要求用opencv视觉库来写一个对图片识别并提取指定区域的程序.看了很多资料,只学会了皮毛,下面附上简单的代码.运行程序之前需要安装opencv库,官网地址为:https:/ ...
- Java基于opencv实现图像数字识别(三)—灰度化和二值化
Java基于opencv实现图像数字识别(三)-灰度化和二值化 一.灰度化 灰度化:在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值:因此,灰度图像每个像素点只需一个字 ...
- OpenCV图像的二值化
图像的二值化: 与边缘检测相比,轮廓检测有时能更好的反映图像的内容.而要对图像进行轮廓检测,则必须要先对图像进行二值化,图像的二值化就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出 ...
- opencv图像二值化的函数cvThreshold()。 cvAdaptiveThreshol
OpenCV中对图像进行二值化的关键函数——cvThreshold(). 函数功能:采用Canny方法对图像进行边缘检测 函数原型: void cvThreshold( const CvArr* sr ...
- opencv-python图像二值化函数cv2.threshold函数详解及参数cv2.THRESH_OTSU使用
cv2.threshold()函数的作用是将一幅灰度图二值化,基本用法如下: #ret:暂时就认为是设定的thresh阈值,mask:二值化的图像 ret,mask = cv2.threshold(i ...
随机推荐
- Caffe学习系列(23):如何将别人训练好的model用到自己的数据上
caffe团队用imagenet图片进行训练,迭代30多万次,训练出来一个model.这个model将图片分为1000类,应该是目前为止最好的图片分类model了. 假设我现在有一些自己的图片想进行分 ...
- Java程序设计的DOS命令基础
Java程序设计的DOS命令基础 用户使用操作系统和软件有两种方式:命令行界面(Command Line Interface,CLI)和图形界面(Graphical User Interface,GU ...
- Word 打包 zip 并提供下载
该篇博客记录Java Web项目将word打包zip并提供下载功能的实现和其中遇到的坑,方便后续自己的查看的参照. 1. 后台处理的java 方法 首先将所有的word生成到uploadword目录下 ...
- Python2.6-原理之类和oop(下)
来自<python学习手册第四版>第六部分 五.运算符重载(29章) 这部分深入介绍更多的细节并看一些常用的重载方法,虽然不会展示每种可用的运算符重载方法,但是这里给出的代码也足够覆盖py ...
- C# 7.0 新特性1: 基于Tuple的“多”返回值方法
本文基于Roslyn项目中的Issue:#347 展开讨论. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: ...
- 【python游戏编程之旅】第七篇---pygame中的冲突检测技术
本系列博客介绍以python+pygame库进行小游戏的开发.有写的不对之处还望各位海涵. 上一个博客我们一起学习了pygame中的Sprite模块和如何加载动画:http://www.cnblogs ...
- 匈牙利算法(codevs2776)
type node=^link; link=record des:longint; next:node; end; var n,m,i,t,num:longint; p:node; nd:..] of ...
- [cross domain] four approachs to cross domain in javascript
four approachs can cross domain in javascript 1.jsonp 2.document.domain(only in frame and they have ...
- Beta版本冲刺———第六天
会议照片: 项目燃尽图: 1.项目进展: 该项目的Beta版本冲刺到今天就大体结束,但是小组依然困在"如何保存每次游戏的分数,并将其排序列在排行榜中"的问题上,小组四个人都在一起解 ...
- 转 为什么文件存储要选用B+树这样的数据结构?
为什么文件存储要选用B+树这样的数据结构? "文件存储要选用B+树这样的数据结构"--没记错的话,这是严蔚敏那本数据结构书上的一句结论.不知道是我没细看还是她没细讲,反正当时纯粹应 ...