DJI IOS开发之三:Step By Step搭建基于DJI Phantom和iOS的计算机视觉及UAV控制开发平台

  • 1 前言

在这之前,世界上有很多研究团队花了大量时间自己造四轴,自己开发硬件,才终于可以研究空中机器人的飞行控制,视觉等方面的问题,了不起在几年前用AR Drone来做。但我们知道AR Drone飞行范围太小,摄像头也很不稳定,因此用AR Drone来做研究有很大的局限性。

现在好了,使用DJI的飞行器,我们轻而易举的拥有了一个非常棒的研究平台,去研究最前沿的问题,或者说最值得去研究的问题,那就是 计算机视觉+机器学习+机器人控制 。把这三个领域结合起来会产生什么令人兴奋的东西呢?

说了一些废话,回到正题。在上一篇文章中,我介绍了如何使用iOS平台来搭建基本的计算机视觉开发环境,在本文中,我将介绍如何搭建基于DJI Phantom和iOS的开发平台。

  • 2 开发环境

Mac OS X 10.10 Yosemite

Xcode 6.1

DJI SDK 1.0.6

OpenCV for iOS 2.4.10

  • 3 搭建步骤

对于基本的建立iOS工程和使用DJI SDK这里就不详细介绍了,

http://blog.csdn.net/songrotek/article/details/44408081

上面这篇Blog介绍了基本的使用DJI SDK的东西。

那么本文主要是说明如何修改DJI SDK的东西使得我们可以直接添加OpenCV的代码对图像进行处理。

技术分享

链接的库如上所示,主要还是加了很多和图像处理有关的库,有的可能用不着。

将DJI SDK中的ViewPreviewer文件夹直接拉进来。

注意lib和header的search path:

技术分享

要对应

我主要在VideoPreviewer和MovieGLView两个文件进行更改

Step 1:在VideoPreviewer中添加UIImageView用于显示

@property (strong,nonatomic) UIImageView *imageView;

 Step 2:在setView:中初始化这个UIImageView

-(BOOL)setView:(UIView *)view
{
    BEGIN_DISPATCH_QUEUE
    if(_glView == nil){
        _glView = [[MovieGLView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, view.frame.size.width/2, view.frame.size.height/2)];
        _status.isGLViewInit = YES;
    }
    
    if (self.imageView == nil) {
        self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(view.frame.size.width/2, 0.0f, view.frame.size.width/2, view.frame.size.height/2)];
    }
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [_glView setFrame:CGRectMake(0.0f, 0.0f, view.frame.size.width/2, view.frame.size.height/2)];
        [view addSubview:_glView];
        [view addSubview:self.imageView];
        
    });
    END_DISPATCH_QUEUE
    return NO;
}

上面的view的大小显然可以自己更改

Step 3:修改startRun的代码

主要是修改下面这一段代码:

if(_status.isGLViewInit && !_status.isPause && !_status.isBackground)
                 {
                     UIImage *image = [_glView render:_renderYUVFrame[_renderFrameIndex]];
                     
                     if(self.delegate !=nil && [self.delegate respondsToSelector:@selector(processImage:)]){
                         dispatch_async(dispatch_get_main_queue(), ^{
                             UIImageToMat(image,matImage);
                             [self.delegate processImage:matImage];
                             self.imageView.image = MatToUIImage(matImage);
                         });
                     } else {
                         dispatch_async(dispatch_get_main_queue(), ^{
                             self.imageView.image = image;
                         });
                     }

                 }

我更改了render这个代码,从而将glview转换为UIImage,然后对UIImage进行Mat格式转换,并设置Delegate从而在外部进行处理,然后在转换回来。使用dispatch_async从而在主线程进行操作。

Step 4:修改render代码

// grabbing image from FBO
    
    NSInteger x = 0, y = 0;
    NSInteger dataLength = _backingWidth * _backingHeight * 4;
    GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));
    
    glPixelStorei(GL_PACK_ALIGNMENT, 4);
    glReadPixels(x, y, _backingWidth, _backingHeight, GL_RGBA, GL_UNSIGNED_BYTE, data);
    CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    CGImageRef iref = CGImageCreate(_backingWidth, _backingHeight, 8, 32, _backingWidth * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
                                    ref, NULL, true, kCGRenderingIntentDefault);
    
    UIGraphicsBeginImageContext(CGSizeMake(_backingWidth, _backingHeight));
    CGContextRef cgcontext = UIGraphicsGetCurrentContext();
    CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
    CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, _backingWidth, _backingHeight), iref);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    free(data);
    CFRelease(ref);
    CGImageRelease(iref);
    
    return image;

在method后部添加了如上的代码实现glview转UIImage。

经过上面的处理,我们在viewController就可以很方便调用了。

Step 5:ViewController的代码

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    // Setup Drone
    self.drone = [[DJIDrone alloc] initWithType:DJIDrone_Phantom];
    self.drone.delegate = self;
    self.drone.camera.delegate = self;
    
    // 设置视频流
    [[VideoPreviewer instance] start];
    [VideoPreviewer instance].delegate = self;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [[VideoPreviewer instance] setView:self.view];
    [self.drone connectToDrone];
}

-(void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    
    [self.drone.camera startCameraSystemStateUpdates];
}

-(void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self.drone disconnectToDrone];
    [self.drone destroy];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - DJICameraDelegate

// OpenCV的处理都在下面这个Method里面
- (void)processImage:(cv::Mat &)image
{
    
    cvtColor(image, image, CV_BGR2GRAY);

}

- (void)camera:(DJICamera *)camera didReceivedVideoData:(uint8_t *)videoBuffer length:(int)length
{
    uint8_t *pBuffer = (uint8_t*)malloc(length);
    memcpy(pBuffer, videoBuffer, length);
    [[[VideoPreviewer instance] dataQueue] push:pBuffer length:length];
}

大家看到,在ViewController的代码可以非常简单,因为整个处理过程都在ViewPreviewer中实现,在这里,可以说我们只要在processImage:里面贴Opencv的代码就OK了。


 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。