OpenCV 之ios 腐蚀与膨胀

2019-11-12  本文已影响0人  充满活力的早晨

OpenCV 之ios 腐蚀与膨胀

目标

本文档尝试解答如下问题:

原理

形态学操作

简单来讲,形态学操作就是基于形状的一系列图像处理操作。通过将 结构元素 作用于输入图像来产生输出图像

最基本的形态学操作有二:腐蚀与膨胀(Erosion 与 Dilation)。 他们的运用广泛:

通过以下图像,我们简要来讨论一下膨胀与腐蚀操作(译者注:注意这张图像中的字母为黑色,背景为白色,而不是一般意义的背景为黑色,前景为白色):


膨胀

放大白色区域,缩小黑色区域

腐蚀

缩小白色区域,放大黑色区域

源码

#ifdef __cplusplus
#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/ios.h>
#import <opencv2/imgproc.hpp>
#import <opencv2/highgui.hpp>
#import <opencv2/core/operations.hpp>

#import <opencv2/core/core_c.h>
using namespace cv;
using namespace std;

#endif
#import "ErodeAndDilateViewController.h"

@implementation ErodeAndDilateViewController

-(void)viewDidLoad{
    [super viewDidLoad];
    UIImage * src1Image = [UIImage imageNamed:@"cat.jpg"];
      Mat src1 = [self cvMatFromUIImage:src1Image];
      UIImageView *imageView;
      imageView = [self createImageViewInRect:CGRectMake(0, 100, 150, 150)];
      [self.view addSubview:imageView];
      imageView.image  = [self UIImageFromCVMat:src1];
    
   __block int erosion_elem = 0;

   __block int dilation_elem = 0;
    int const max_kernel_size = 21;

    ///膨胀
    [self createSliderFrame:CGRectMake(150, 100, 100, 50) maxValue:max_kernel_size minValue:0 block:^(float value) {
        int erosion_type ;
        if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
         else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
         else  { erosion_type = MORPH_ELLIPSE; }

        int erosion_size = value;
        Mat erosion_dst;
        Mat element = getStructuringElement( erosion_type,
                                              cv::Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                                              cv::Point( erosion_size, erosion_size ) );
        erode( src1, erosion_dst, element );
        
        UIImageView *imageView;
        imageView = [self createImageViewInRect:CGRectMake(0, 250, 150, 150)];
        [self.view addSubview:imageView];
        imageView.image  = [self UIImageFromCVMat:erosion_dst];
        
    }];
   
    [self createButtonFrame:CGRectMake(250, 100, 100, 50) title:@"Rect" Block:^NSString * _Nonnull(int hitCount) {
        erosion_elem = hitCount%3;
        if (erosion_elem==0) {
            return @"Rect";
        }else if (erosion_elem==1){
            return @"CROSS";
        }else{
            return @"ELLIPSE";
        }
    }];
    
    
    [self createSliderFrame:CGRectMake(150, 150, 100, 50) maxValue:max_kernel_size minValue:0 block:^(float value) {
        int dilation_type;
        if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
         else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
         else{ dilation_type = MORPH_ELLIPSE; }
          int dilation_size = value;
        Mat dilation_dst;
        Mat element = getStructuringElement( dilation_type,
                                             cv::Size( 2*dilation_size + 1, 2*dilation_size+1 ),
                                             cv::Point( dilation_size, dilation_size ) );
       
        dilate( src1, dilation_dst, element );
        
        UIImageView *imageView;
        imageView = [self createImageViewInRect:CGRectMake(0, 400, 150, 150)];
        [self.view addSubview:imageView];
        imageView.image  = [self UIImageFromCVMat:dilation_dst];

      }];
    [self createButtonFrame:CGRectMake(250, 150, 100, 50) title:@"Rect" Block:^NSString * _Nonnull(int hitCount) {
        dilation_elem  = hitCount%3;
             if (dilation_elem==0) {
                 return @"Rect";
             }else if (dilation_elem==1){
                 return @"CROSS;";
             }else{
                 return @"ELLIPSE";
             }
        }];
}




#pragma mark  - private
//brg
- (cv::Mat)cvMatFromUIImage:(UIImage *)image
{
  CGColorSpaceRef colorSpace =CGColorSpaceCreateDeviceRGB();
    
  CGFloat cols = image.size.width;
  CGFloat rows = image.size.height;
    Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels (color channels + alpha)
  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);
    
    Mat dst;
    Mat src;
    cvtColor(cvMat, dst, COLOR_RGBA2BGRA);
    cvtColor(dst, src, COLOR_BGRA2BGR);

  return src;
}

-(UIImage *)UIImageFromCVMat:(cv::Mat)cvMat
{
//    mat 是brg 而 rgb
    Mat src;
    NSData *data=nil;
    CGBitmapInfo info =kCGImageAlphaNone|kCGBitmapByteOrderDefault;
    CGColorSpaceRef colorSpace;
    if (cvMat.depth()!=CV_8U) {
        Mat result;
        cvMat.convertTo(result, CV_8U,255.0);
        cvMat = result;
    }
  if (cvMat.elemSize() == 1) {
      colorSpace = CGColorSpaceCreateDeviceGray();
      data= [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()];
  } else if(cvMat.elemSize() == 3){
      cvtColor(cvMat, src, COLOR_BGR2RGB);
       data= [NSData dataWithBytes:src.data length:src.elemSize()*src.total()];
      colorSpace = CGColorSpaceCreateDeviceRGB();
  }else if(cvMat.elemSize() == 4){
      colorSpace = CGColorSpaceCreateDeviceRGB();
      cvtColor(cvMat, src, COLOR_BGRA2RGBA);
      data= [NSData dataWithBytes:src.data length:src.elemSize()*src.total()];
      info =kCGImageAlphaNoneSkipLast | kCGBitmapByteOrderDefault;
  }else{
      NSLog(@"[error:] 错误的颜色通道");
      return nil;
  }
  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
                                     kCGRenderingIntentAbsoluteColorimetric                   //intent
                                     );
  // Getting UIImage from CGImage
  UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
  CGImageRelease(imageRef);
  CGDataProviderRelease(provider);
  CGColorSpaceRelease(colorSpace);
  return finalImage;
 }
@end

解释

Erosion

int erosion_type ;
        if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
         else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
         else  { erosion_type = MORPH_ELLIPSE; }

        int erosion_size = value;
        Mat erosion_dst;
        Mat element = getStructuringElement( erosion_type,
                                              cv::Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                                              cv::Point( erosion_size, erosion_size ) );
        erode( src1, erosion_dst, element );
        
        UIImageView *imageView;
        imageView = [self createImageViewInRect:CGRectMake(0, 250, 150, 150)];
        [self.view addSubview:imageView];
        imageView.image  = [self UIImageFromCVMat:erosion_dst];

进行 腐蚀 操作的函数是 erode 。 它接受了三个参数:

Mat element = getStructuringElement( erosion_type,
                                     Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                                     Point( erosion_size, erosion_size ) );

我们可以为我们的内核选择三种形状之一:

矩形: MORPH_RECT
交叉形: MORPH_CROSS
椭圆形: MORPH_ELLIPSE

然后,我们还需要指定内核大小,以及 锚点 位置。不指定锚点位置,则默认锚点在内核中心位置。

就这些了,我们现在可以对图像进行腐蚀操作了。

Dilation

膨胀和腐蚀是差不多的操作的.这里就不过于解释了

结果

最终结果如图所示

内核形状

其实看到这个内核形状,我是一脸懵逼.当时记得还查了不少资料,也没看懂大家到底说的是啥.其实最直管的表现是把核形状打印出来看看不就行了
我们都以核大小7做参考

矩形内核

[  1,   1,   1,   1,   1,   1,   1;
   1,   1,   1,   1,   1,   1,   1;
   1,   1,   1,   1,   1,   1,   1;
   1,   1,   1,   1,   1,   1,   1;
   1,   1,   1,   1,   1,   1,   1;
   1,   1,   1,   1,   1,   1,   1;
   1,   1,   1,   1,   1,   1,   1]

交叉形

[  0,   0,   0,   1,   0,   0,   0;
   0,   0,   0,   1,   0,   0,   0;
   0,   0,   0,   1,   0,   0,   0;
   1,   1,   1,   1,   1,   1,   1;
   0,   0,   0,   1,   0,   0,   0;
   0,   0,   0,   1,   0,   0,   0;
   0,   0,   0,   1,   0,   0,   0]

椭圆形

[  0,   0,   0,   1,   0,   0,   0;
   0,   1,   1,   1,   1,   1,   0;
   1,   1,   1,   1,   1,   1,   1;
   1,   1,   1,   1,   1,   1,   1;
   1,   1,   1,   1,   1,   1,   1;
   0,   1,   1,   1,   1,   1,   0;
   0,   0,   0,   1,   0,   0,   0]

github 地址

摘录博客

上一篇下一篇

猜你喜欢

热点阅读