[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
                                                    8,                          // Bits per component
                                                    cvMat.step[0],              // Bytes per row
                                                    colorSpace,                 // Colorspace
                                                    kCGImageAlphaNoneSkipLast |
                                                    kCGBitmapByteOrderDefault); // Bitmap info flags

    CGContextDrawImage(contextRef, CGRectMake(0, 0, 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() == 1) {
        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
                                        8,                                          //bits per component
                                        8 * cvMat.elemSize(),                       //bits per pixel
                                        cvMat.step[0],                            //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, 4
                                       );
    // 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(0, 0, image.size.width, image.size.height),
                       imageRef
                       );
    CGContextRelease(contextRef);
    CGColorSpaceRelease(colorSpace);

    // Creating result IplImage
    IplImage *ret = cvCreateImage(cvGetSize(iplimage), IPL_DEPTH_8U, 3);
    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==0)||(iWidth<=0)||(iHeight<=0))return -1;
    int ihist[256];
    int thresholdValue=0; // „–÷µ
    int n, n1, n2 ;
    double m1, m2, sum, csum, fmax, sb;
    int i,j,k;
    memset(ihist, 0, sizeof(ihist));
    n=iHeight*iWidth;
    sum = csum = 0.0;
    fmax = -1.0;
    n1 = 0;
    for(i=0; i < iHeight; i++)
    {
        for(j=0; j < iWidth; j++)
        {
            ihist[*pGrayImg]++;
            pGrayImg++;
        }
    }
    pGrayImg -= n;
    for (k=0; k <= 255; k++)
    {
        sum += (double) k * (double) ihist[k];
    }
    for (k=0; k <=255; k++)
    {
        n1 += ihist[k];
        if(n1==0)continue;
        n2 = n - n1;
        if(n2==0)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, 255, 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

时间: 2024-10-14 10:55:49

[iOS OpenCV的使用,灰度和二值化]的相关文章

VB6之图像灰度与二值化

老代码备忘,我对图像处理不是太懂. 注:部分代码引援自网上,话说我到底自己写过什么代码... Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hbitmap As Long, _ ByVal dwCount As Long, _ lpBits As Any) As Long Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hbitm

OpenCV中对图像进行二值化的关键函数——cvThreshold()。

函数功能:采用Canny方法对图像进行边缘检测 函数原型: void cvThreshold( const CvArr* src, CvArr* dst, double threshold, double max_value, int threshold_type ); 函数说明: 第一个参数表示输入图像,必须为单通道灰度图. 第二个参数表示输出的边缘图像,为单通道黑白图. 第三个参数表示阈值 第四个参数表示最大值. 第五个参数表示运算方法. 在OpenCV的imgproc\types_c.h中

OpenCV图像的全局阈值二值化函数(OTSU)

cv::threshold(GrayImg, Bw, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);//灰度图像二值化 CV_THRESH_OTSU是提取图像最佳阈值算法.该方法在类间方差最大的情况下是最佳的,就图像的灰度值而言,OTSU给出最好的类间分离的阈值. OpenCV阈值分割的几种方法(types_c.h中的定义): /* Threshold types */ enum { CV_THRESH_BINARY =0, /* value = valu

【华为云技术分享】灰度图二值化算法

[摘要] 目前最常用的快速二值化阈值确定方法为根据每一张目标图像来动态的计算平均灰度值.然后将灰度图像中的每个像素灰度值和此平均阈值作对比,高于平均阈值的记为“1”(白色),低于的则设置为“0”(黑色).这种方法虽然会让造成部分背景像素点丢失,但却是最简单高效的处理方法. 灰度图片中都可以用一个具体的灰度值Grav来量化每一个像素点.考虑到实际识别的二值特征,为了让被处理目标答题卡更加简单,计算量更少,速度更快,我们可以直接对灰度图片进行二值化处理. 图像二值化简单来说就是讲整个灰度图片的目标像

OpenCV图像的二值化

图像的二值化: 与边缘检测相比,轮廓检测有时能更好的反映图像的内容.而要对图像进行轮廓检测,则必须要先对图像进行二值化,图像的二值化就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出明显的黑白效果.在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓. 下面就介绍OpenCV中对图像进行二值化的关键函数——cvThreshold(). 函数功能:采用Canny方法对图像进行边缘检测函数原型:void cvThreshold( 

【OpenCV入门指南】第四篇 图像的二值化

[OpenCV入门指南]第四篇 图像的二值化 在上一篇<[OpenCV入门指南]第三篇Canny边缘检测>中介绍了使用Canny算子对图像进行边缘检测.与边缘检测相比,轮廓检测有时能更好的反映图像的内容.而要对图像进行轮廓检测,则必须要先对图像进行二值化,图像的二值化就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出明显的黑白效果.在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓. <OpenCV入门指南>系

基于opencv的视频流 模板匹配 (灰度化 二值化 )

#include <cv.h> #include <highgui.h> #include <windows.h> // 获取直方图 // 1. pImageData 图像数据 // 2. nWidth 图像宽度 // 3. nHeight 图像高度 // 4. nWidthStep 图像行大小 // 5. pHistogram 直方图 BOOL GetHistogram(unsigned char *pImageData, int nWidth, int nHeigh

【OPENCV】图像的预处理(灰度图、二值化、字符矫正(旋转))

1.首先加载原始图片: 2.cvCvtColor(img, source, CV_BGR2GRAY);转化成灰度图像: 3.cvThreshold(source,source_gray,100,255,CV_THRESH_BINARY );进行二值化处理. 由于原始的图片会有一定的角度,需要进行旋转,而旋转的话可以使用OPENCV提供的函数实现,本文中采用的是自己编写的,即通过旋转360,并记录旋转某个角度的时候使得在x轴方向的投影最大化. 如图,经过处理的图片效果如下所示: 完整的工程已经上传

【opencv】统计图像二值化后白色像素点个数

应用:图像特征提取 #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/core/core.hpp" #include <opencv\ml.h> #include <iostream> #include "cv.h" #include "highgui.