1. 程式人生 > >iOS AR 高通Vuforia —— 獲取攝像頭幀圖片

iOS AR 高通Vuforia —— 獲取攝像頭幀圖片

最近有一個獲取Vuforia 框架下攝像頭的幀圖片的需求就研究了一下,其實官方是有相關API的,裡面有java和c++兩種語言

https://library.vuforia.com/articles/Solution/Working-with-the-Camera#How-To-Access-the-Camera-Image-in-Native

(有一點不好的是,官方給的地址會變,以前的版本和現在的版本地址都不一樣)vuforia裡面的圖片格式有兩種,RGB565和RGB888

RGB888

    首先需要在start出現的地方設定圖片格式setFrameFormat(startCamera和resumeAR中

        if (!Vuforia::CameraDevice::getInstance().start()) {
            [self NSErrorWithCode:E_STARTING_CAMERA error:error];
            return NO;
        }
        Vuforia::setFrameFormat(Vuforia::RGB888, true);

    然後vuforia_onUpdate函式中新增下面的程式碼

- (void) Vuforia_onUpdate:(Vuforia::State *) state {
    Vuforia::Image *imageRGB888 = NULL;
    Vuforia::Frame frame = state->getFrame();

    for (int i = 0; i < frame.getNumImages(); ++i) {
        const Vuforia::Image *image = frame.getImage(i);
        if (image->getFormat() == Vuforia::RGB888) {
            imageRGB888 = (Vuforia::Image*)image;

            break;
        }
    }
    if (imageRGB888) {
        int width = imageRGB888->getWidth();
        int height = imageRGB888->getHeight();
        int bitsPerComponent = 8;
        int bitsPerPixel = Vuforia::getBitsPerPixel(Vuforia::RGB888);
        int bytesPerRow = imageRGB888->getBufferWidth() * bitsPerPixel / bitsPerComponent;
        CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
        CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNone;
        CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
        
        CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, imageRGB888->getPixels(), Vuforia::getBufferSize(width, height, Vuforia::RGB888), NULL);
        
        CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
        UIImage *result = [UIImage imageWithCGImage:imageRef];//得到UIImage
        
        CGDataProviderRelease(provider);
        CGColorSpaceRelease(colorSpaceRef);
        CGImageRelease(imageRef);

    }
    
  
    if ((self.delegate != nil) && [self.delegate respondsToSelector:@selector(onVuforiaUpdate:)]) {
        [self.delegate onVuforiaUpdate:state];
    }
}


RGB565

首先需要在start出現的地方設定圖片格式(startCamera和resumeAR中用到了start

        if (!Vuforia::CameraDevice::getInstance().start()) {
            [self NSErrorWithCode:E_STARTING_CAMERA error:error];
            return NO;
        }
        Vuforia::setFrameFormat(Vuforia::RGB565, true);

然後vuforia_onUpdate函式中新增下面的程式碼

- (void) Vuforia_onUpdate:(Vuforia::State *) state {
    Vuforia::Image *imageRGB565 = NULL;
    Vuforia::Frame frame = state->getFrame();
    
    for (int i = 0; i < frame.getNumImages(); ++i) {
        const Vuforia::Image *image = frame.getImage(i);
        if (image->getFormat() == Vuforia::RGB565) {
            imageRGB565 = (Vuforia::Image*)image;
            
            break;
        }
    }
    if (imageRGB565) {
    
        
        int width = imageRGB565->getWidth();
        int height = imageRGB565->getHeight();
        const size_t bufferLength = width * height * 2;
        const short* pixels = (const short*) imageRGB565->getPixels();
        NSData *data = [NSData dataWithBytes:pixels length:bufferLength];

        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);
        NSLog(@"bits per pixel %d",Vuforia::getBitsPerPixel(Vuforia::RGB565));
        // Creating CGImage from cv::Mat
        CGImageRef imageRef = CGImageCreate(width,          //width
                                            height,         //height
                                            5,              //bits per component
                                            Vuforia::getBitsPerPixel(Vuforia::RGB565),             //bits per pixel
                                            width * 2,      //bytesPerRow
                                            colorSpace,     //colorspace
                                            kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Little,// 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);

    }
    
    if ((self.delegate != nil) && [self.delegate respondsToSelector:@selector(onVuforiaUpdate:)]) {
        [self.delegate onVuforiaUpdate:state];
    }
}

但是需要注意的是用RGB888轉換成的UIImage是正常的,而RGB565轉成的UIImage是非正常的,因為正常的RGB24是由24位即3個位元組來描述一個畫素,R、G、B各8位。而實際使用中為了減少影象資料的尺寸,如視訊領域,對R、G、B所使用的位數進行的縮減,如RGB565和RGB555。
RGB565 就是R-5bit,G-6bit,B-5bit
RGB555 就是R-5bit,G-5bit,B-5bit

RGB888 就是R-8bit,G-8bit,B-8bit 

使用RGB565,會導致圖片資料的缺失,影響精度,在前端顯示的時候還是建議用RGB888