OpenCV 之ios 图像平滑处理

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

OpenCV 之ios 图像平滑处理

目标

本教程教您怎样使用各种线性滤波器对图像进行平滑处理,相关OpenCV函数如下:

原理

归一化块滤波器 (Normalized Box Filter)

最简单的滤波器, 输出像素值是核窗口内像素值的 均值 ( 所有像素加权系数相等)
核如下:


掩码矩阵(也称作核)

高斯滤波器 (Gaussian Filter)

最有用的滤波器 (尽管不是最快的)。 高斯滤波是将输入数组的每一个像素点与 高斯内核 卷积将卷积和当作输出像素值。

还记得1维高斯函数的样子吗?



假设图像是1维的,那么观察上图,不难发现中间像素的加权系数是最大的, 周边像素的加权系数随着它们远离中间像素的距离增大而逐渐减小。

Note 2维高斯函数可以表达为 :



其中 μ 为均值 (峰值对应位置), σ代表标准差 (变量x和 变量 y 各有一个均值,也各有一个标准差)

中值滤波器 (Median Filter)

中值滤波将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的 中值 代替 。

双边滤波 (Bilateral Filter)

源码

#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 "DealImageViewController.h"

@interface DealImageViewController ()

@end

@implementation DealImageViewController
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;
- (void)viewDidLoad {
    [super viewDidLoad];
     UIImage * src1Image = [UIImage imageNamed:@"lena.jpg"];
    Mat src1 = [self cvMatFromUIImage:src1Image];
    Mat src;
    cvtColor(src1, src, COLOR_BGRA2BGR);
    UIImageView *imageView;
    imageView = [self createImageViewInRect:CGRectMake(0, 100, 150, 150)];
    [self.view addSubview:imageView];
    imageView.image  = [self UIImageFromCVMat:src];
    ///均值平滑
    Mat dst;
    {
        for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){
            blur( src, dst, cv::Size( i, i ), cv::Point(-1,-1));
        }
        imageView = [self createImageViewInRect:CGRectMake(0, 250, 150, 150)];
        [self.view addSubview:imageView];
        imageView.image  = [self UIImageFromCVMat:dst];
    }
    /// 高斯平滑
    {
        for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){
            GaussianBlur( src, dst, cv::Size( i, i ), 0, 0 );
        }
        imageView = [self createImageViewInRect:CGRectMake(0, 400, 150, 150)];
        [self.view addSubview:imageView];
        imageView.image  = [self UIImageFromCVMat:dst];
    }

    ///中值平滑
    {
        for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) {
            medianBlur ( src, dst, I );
        }
        imageView = [self createImageViewInRect:CGRectMake(150, 250, 150, 150)];
        [self.view addSubview:imageView];
        imageView.image  = [self UIImageFromCVMat:dst];
    }

    ///双边平滑
    {
        for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){
                bilateralFilter ( src, dst, i, i*2, i/2 );
        }
        imageView = [self createImageViewInRect:CGRectMake(150, 100, 150, 150)];
        [self.view addSubview:imageView];
        imageView.image  = [self UIImageFromCVMat:dst];
    }
}

#pragma mark  - private
//brgx
- (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;
    cvtColor(cvMat, dst, COLOR_RGBA2BGRA);

  return dst;
}

-(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

解释

1.归一化块滤波器:

OpenCV函数 blur 执行了归一化块平滑操作。

for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){
            blur( src, dst, cv::Size( i, i ), cv::Point(-1,-1));
        }

我们输入4个实参 (详细的解释请参考 Reference):

2.高斯滤波器:

OpenCV函数 GaussianBlur 执行高斯平滑 :

  for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){
            GaussianBlur( src, dst, cv::Size( i, i ), 0, 0 );
        }

我们输入4个实参 (详细的解释请参考 Reference):

3.中值滤波器:

OpenCV函数 medianBlur 执行中值滤波操作:

 for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) {
            medianBlur ( src, dst, I );
        }

我们用了3个参数:
src: 输入图像
dst: 输出图像, 必须与 src 相同类型
i: 内核大小 (只需一个值,因为我们使用正方形窗口),必须为奇数。

4.双边滤波器

OpenCV函数 bilateralFilter 执行双边滤波操作:

 for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ){
                bilateralFilter ( src, dst, i, i*2, i/2 );
        }
  1. 我们使用了5个参数:
    • src: 输入图像
    • dst: 输出图像
    • d: 像素的邻域直径
    • σColor: 颜色空间的标准方差
    • σSpace: 坐标空间的标准方差(像素单位)

结果


github 地址

摘录博客

上一篇下一篇

猜你喜欢

热点阅读