EasyAR

AR

EasyAR iOS的SDK功能:

匹配場景圖片假哎,在匹配成功的圖片上加載圖像吝梅,3D模型员咽,視頻根暑;

EasyAR iOS的SDK每個類的功能:

http://m.blog.csdn.net/article/details?id=49615303

類名 描述
base.hpp 基類力试,是大多數EasyAR類的基類。
augmenter.hpp Augmenter是一個渲染器排嫌,它從tracker獲取frame畸裳,然后將camera的圖像作為AR場景的背景渲染出來。
barcode.hpp BarCodeScanner實現了二維碼掃描與識別功能淳地。
camera.hpp CameraDevice實現了一個camera設備怖糊。CameraCalibration存儲了camera的標定數據
frame.hpp Frame用來存儲跟蹤到的數據。這個數據包括當前camera的圖像颇象,跟蹤到的target和其它一些信息伍伤。
image.hpp Image存儲了圖像數據,用來表示內存中的圖像遣钳。Image以byte數組的方式提供了對原始數據的訪問扰魂,同時也提供了訪問width/height/stride等信息的接口。
imagetarget.hpp ImageTarget表示平面圖像的target蕴茴,它可以被ImageTracker所跟蹤劝评。
imagetracker.hpp ImageTracker實現了target的檢測和跟蹤。
matrix.hpp Matrix表示m x n的矩陣倦淀。
player.hpp VideoPlayer是視頻播放類蒋畜。EasyAR支持普通的視頻、透明視頻和流媒體播放撞叽。視頻內容會被渲染到傳入SetRenderTexture的texture上姻成。
storage.hpp StorageType表示圖像、json文件愿棋、視頻或其它文件的存放位置科展。StorageType指定了文件存放的根目錄,你可以在所有相關接口中使用相對于這個根目錄的相對路徑初斑。
target.hpp Target是EasyAR里面所有可以被ImageTracker或其它算法跟蹤的目標的基類辛润。target的所有屬性要在加載之后才會有效。
utility.hpp 自我理解:sdk初始化類
iOS EasyAR大概步驟:

配置好環(huán)境:

  1. 注冊sdk见秤;
  2. 初始化openGL繪制上下文砂竖;
  3. 初始化渲染器Augmenter;
  4. 初始化CameraDevice相機鹃答,渲染器關聯相機乎澄;
  5. 加載帶匹配的圖片;
  6. 打開相機测摔,渲染相機圖片到openGL置济,開始匹配解恰;
  7. 匹配跟蹤成功。
iOS EasyAR實現步驟:
//
//  CameraView.m
//  EasyAR
//
//  Created by lv on 2016/12/27.
//  Copyright ? 2016年 Albert. All rights reserved.
//

#import "CameraView.h"
#include "easyar/camera.hpp"
#import <easyar/matrix.hpp>
#import <easyar/augmenter.hpp>
#import <easyar/imagetarget.hpp>
#import <easyar/utility.hpp>
#import <easyar/frame.hpp>
#import <easyar/imagetracker.hpp>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
#include <iostream>
#import <QuartzCore/QuartzCore.h>
#import "renderer.hpp"
#import "SDWebImageManager.h"
@interface CameraView ()
{
    EasyAR::CameraDevice _cameraDevice;    //相機
    EasyAR::ImageTarget _tar;
    EasyAR::Augmenter _augmenter;//渲染器
    EasyAR::Vec2I view_size;
    EasyAR::Vec4I _viewport;
    EasyAR::samples::Renderer  _renderer;
    EasyAR::ImageTracker _tracker;
    CALayer *_imageLayer;
    BOOL _portrait;//設備方向
    
    
}
@property(nonnull,retain)CADisplayLink * displayLink;//定時器浙于。
@property(nonatomic, strong) CAEAGLLayer * eaglLayer;
@property(nonatomic, strong) EAGLContext *context;//上下文
@property(nonatomic) GLuint colorRenderBuffer;
@end

@implementation CameraView

+ (Class)layerClass
{
    return [CAEAGLLayer class];
}
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        
        [self initAll];
    }
    return self;
}
- (void)initAll {
    
    _portrait = NO;
    _augmenter = EasyAR::Augmenter();//創(chuàng)建渲染器
    [self setupGL];
    _renderer.init();
    [self initCamera];

}

- (void)resize:(CGRect)frame orientation:(UIInterfaceOrientation)orientation
{
    BOOL isPortrait = NO;
    switch (orientation)
    {
        case UIInterfaceOrientationPortrait:
        case UIInterfaceOrientationPortraitUpsideDown:
            isPortrait = YES;
            break;
        case UIInterfaceOrientationLandscapeLeft:
        case UIInterfaceOrientationLandscapeRight:
            isPortrait = NO;
            break;
        default:
            break;
    }
    [self setPortrait:isPortrait];
    [self resizeGL:frame.size.width height:frame.size.height];
}

- (void)setOrientation:(UIInterfaceOrientation)orientation
{
    switch (orientation)
    {
        case UIInterfaceOrientationPortrait:
            EasyAR::setRotationIOS(270);
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            EasyAR::setRotationIOS(90);
            break;
        case UIInterfaceOrientationLandscapeLeft:
            EasyAR::setRotationIOS(180);
            break;
        case UIInterfaceOrientationLandscapeRight:
            EasyAR::setRotationIOS(0);
            break;
        default:
            break;
    }
}

-(void)setPortrait:(BOOL)portrait
{
    _portrait = portrait;
}

-(void)resizeGL:(float )width height:(float)height
{
    EasyAR::Vec2I size = EasyAR::Vec2I(1, 1);
    if(_cameraDevice.isOpened())
        size = _cameraDevice.size();
    if (size[0] == 0 || size[1] == 0)
        return;
    if(_portrait)
        std::swap(size[0], size[1]);
    float scaleRatio = std::max((float)width / (float)size[0], (float)height / (float)size[1]);
    EasyAR::Vec2I viewport_size = EasyAR::Vec2I((int)(size[0] * scaleRatio), (int)(size[1] * scaleRatio));
    _viewport = EasyAR::Vec4I(0, height - viewport_size[1], viewport_size[0], viewport_size[1]);
}

//開始掃描
-(void)start
{

    BOOL isOpen = [self cameraStart];
    
    NSLog(@"打開相機 = %zd",isOpen);
}

//掃描中
- (void)displayLinkCallback:(CADisplayLink*)displayLink
{
    
    [self render];

    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
    [_context presentRenderbuffer:GL_RENDERBUFFER];
}

//openGL繪制層
- (void)setupGL
{
    _eaglLayer = (CAEAGLLayer*) self.layer;
    _eaglLayer.opaque = YES;
    
    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
    _context = [[EAGLContext alloc] initWithAPI:api];
    if (!_context)
        NSLog(@"Failed to initialize OpenGLES 2.0 context");
    if (![EAGLContext setCurrentContext:_context])
        NSLog(@"Failed to set current OpenGL context");
    
    GLuint frameBuffer;
    glGenFramebuffers(1, &frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    
    glGenRenderbuffers(1, &_colorRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer);
    
    int width, height;
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
    
    GLuint depthRenderBuffer;
    glGenRenderbuffers(1, &depthRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBuffer);
}

//核心部分:從augmenter中取出相機圖像繪制到屏幕中护盈,并檢測匹配跟蹤
-(void)render
{
    glClearColor(0.f, 0.f, 0.f, 1.f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    EasyAR::Frame frame = _augmenter.newFrame();
    if(view_size[0] > 0){
        int width = view_size[0];
        int height = view_size[1];
        EasyAR::Vec2I size = EasyAR::Vec2I(1, 1);
        if (_cameraDevice && _cameraDevice.isOpened())
            size = _cameraDevice.size();
        if(_portrait)
            std::swap(size[0], size[1]);
        float scaleRatio = std::max((float)width / (float)size[0], (float)height / (float)size[1]);
        EasyAR::Vec2I viewport_size = EasyAR::Vec2I((int)(size[0] * scaleRatio), (int)(size[1] * scaleRatio));
        if(_portrait){
         
            _viewport = EasyAR::Vec4I(0, height - viewport_size[1], viewport_size[0], viewport_size[1]);
        }
        else
        {
            NSLog(@"_portrait==>%dx==>%dy==>%dz==>%d",_portrait,(width - height),viewport_size[0],viewport_size[1]);
            _viewport = EasyAR::Vec4I(0, width - height, viewport_size[0], viewport_size[1]);
        }
        if(_cameraDevice && _cameraDevice.isOpened())
            view_size[0] = -1;
    }
    _augmenter.setViewPort(_viewport);
    _augmenter.drawVideoBackground();
    
    glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]);//調用glViewPort函數來決定視見區(qū)域,告訴OpenGL應把渲染之后的圖形繪制在窗體的哪個部位
 
    for (int i = 0; i < frame.targets().size(); ++i) {
        EasyAR::AugmentedTarget::Status status = frame.targets()[i].status();
        
        //圖像匹配成功
        if(status == EasyAR::AugmentedTarget::kTargetStatusTracked) {
            
            //加載3D模型
//            EasyAR::Matrix44F projectionMatrix = EasyAR:: getProjectionGL(_cameraDevice.cameraCalibration(), 0.2f, 500.f);
//            EasyAR::Matrix44F cameraview = getPoseGL(frame.targets()[i].pose());
//            EasyAR::ImageTarget target = frame.targets()[i].target().cast_dynamic<EasyAR::ImageTarget>();
//            _renderer.render(projectionMatrix, cameraview, target.size());
            
            
//            NSLog(@"status===%zd",status);
//            if (![self.layer.sublayers  containsObject:_imageLayer])
//            {
//                _imageLayer = (CALayer *)[self initBonus:[UIImage imageNamed:@"Bonus"]];
//                [_imageLayer removeFromSuperlayer];
//                [self.layer addSublayer:_imageLayer];
//                [self bonusAnimation];
//            }

            
            _matchBlock(status);
        }
     
    }
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    CGPoint point = [[touches anyObject] locationInView:self];
    CGPoint imgaelayerPiont = [_imageLayer convertPoint:point fromLayer:self.layer];
    if ([self.layer containsPoint:imgaelayerPiont]) {
        
        [_imageLayer removeFromSuperlayer];
        
    }

}

-(id)initBonus:(UIImage *)image
{
    CALayer * imageLayer = [CALayer layer];
    imageLayer.frame = CGRectMake((SIZE.width-128)/2, (SIZE.height-192)/2, 128, 192);
    imageLayer.cornerRadius = 10.0;
    imageLayer.masksToBounds = YES;
    imageLayer.contents = (id)image.CGImage;
    return (id)imageLayer;
    
}

-(void)bonusAnimation
{
    CAKeyframeAnimation *theAnimation = [CAKeyframeAnimation animation];
    
    //    CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z); 第一個參數是旋轉角度羞酗,后面三個參數形成一個圍繞其旋轉的向量腐宋,起點位置由UIView的center屬性標識。
    theAnimation.values = [NSArray arrayWithObjects:
                           [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0, 0, 0.5, 0)],
                           [NSValue valueWithCATransform3D:CATransform3DMakeRotation(3.13, 0, 0.5, 0)],
                           [NSValue valueWithCATransform3D:CATransform3DMakeRotation(6.26, 0, 0.5, 0)],
                           nil];
    theAnimation.cumulative = YES;
    //    每個幀的時間=總duration/(values.count - 1)
    // 間隔時間 頻率
    theAnimation.duration = 1;
    // 重復次數
    theAnimation.repeatCount = 0;
    // 取消反彈// 告訴在動畫結束的時候不要移除
    theAnimation.removedOnCompletion = NO;
    // 始終保持最新的效果
    theAnimation.fillMode = kCAFillModeForwards;
    theAnimation.delegate = self;
    _imageLayer.zPosition = 50;
    [_imageLayer addAnimation:theAnimation forKey:@"transform"];
    

}

#pragma mark 初始化相機
-(BOOL)initCamera
{
    BOOL status = YES;
    status = _cameraDevice.open();
    _cameraDevice.setSize( EasyAR::Vec2I(1280, 720));
    _cameraDevice.setFocusMode(EasyAR::CameraDevice::kFocusModeContinousauto);
    status = _augmenter.attachCamera(_cameraDevice);
    status = _tracker.attachCamera(_cameraDevice);
//    [self loadImage:@"namecard.jpg"];
    
    NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/test.jpg"];
//    NSString *savePath = @"$(SRCROOT)/Documents/test.jpg";
    NSLog(@"savePath= %@",savePath);
//    [self downLoadImg:strURL savePath:savePath imgDownFinish:^(id image) {
    [self loadImage:savePath];
//    }];
    

//    [self loadImagePath];

//    [self loadImagePath];
    [self loadImage:savePath];

    

    
    
    return status;
}

-(BOOL)cameraStart
{
    BOOL status = YES;
    status = _cameraDevice.start();
    status = _tracker.start();
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkCallback:)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
    return status;
}

#pragma mark 加載圖片
-(void)loadImage:(NSString *)path
{
    NSArray *arrName = [path componentsSeparatedByString:@"."];
    
    NSString *str=[NSString stringWithFormat:@"{\"images\":[{\"image\":\"%@\",\"name\":\"%@\"}]}",path,@"test"];
    NSLog(@"strJson=%@",str);
    BOOL readImage = _tar.load([str UTF8String], EasyAR::kStorageAbsolute | EasyAR::kStorageJson| EasyAR::kStorageApp);
    
    _tracker.loadTarget(_tar, nil);
    NSLog(@"讀取圖片 = %zd",readImage);
}

-(void)loadImagePath
{
    NSString *jstr = [NSString stringWithFormat:@"{\"images\":[{\"image\":\"%@\",\"name\":\"%@\"}]}",@"namecard.jpg",@"namecard"];
    NSLog(@"jstr==>%@",jstr);
    BOOL readImage = _tar.load([jstr UTF8String],  EasyAR::kStorageAssets | EasyAR::kStorageJson);
     NSLog(@"讀取圖片 = %zd",readImage);
    _tracker.loadTarget(_tar,0);
    
}

-(void)downLoadImg:(NSString *)strURL savePath:(NSString *)savePath imgDownFinish:(imgDownFinish)finish
{
    [[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:strURL] options:0
                                                   progress:^(NSInteger receivedSize, NSInteger expectedSize)
     {
         //處理下載進度
     } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
         
         if (error)
         {
             NSLog(@"error is %@",error);
             
           
             if (finish) {
                 finish(nil);
             }
             
         }
         if (image)
         {
             
             NSArray *arrType = [strURL componentsSeparatedByString:@"."];
             NSData *data = nil;
             
             if ([[arrType lastObject] isEqualToString:@"png"]||[[arrType lastObject] isEqualToString:@"PNG"])
             {
                 data = UIImageJPEGRepresentation(image,1);
             }
             
             if ([[arrType lastObject] isEqualToString:@"jpg"]||[[arrType lastObject] isEqualToString:@"JPG"])
             {
                 data = UIImagePNGRepresentation(image);
             }
             
             
             if (data) {
                 if([data writeToFile:savePath atomically:YES])
                 {
                     NSLog(@"保存成功");
                 }
                 
                 if (finish) {
                     finish(image);
                 }
             }
             else
             {
                 if (finish) {
                     finish(nil);
                 }
             }
         }
     
     }];
}

-(void)dealloc
{

}

-(void)clear
{
    _tracker.stop();
    _cameraDevice.stop();
    _cameraDevice.close();
    _cameraDevice.clear();
    _augmenter.clear();
}

@end
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末檀轨,一起剝皮案震驚了整個濱河市胸竞,隨后出現的幾起案子,更是在濱河造成了極大的恐慌参萄,老刑警劉巖卫枝,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異讹挎,居然都是意外死亡校赤,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門淤袜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來痒谴,“玉大人衰伯,你說我怎么就攤上這事铡羡。” “怎么了意鲸?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵烦周,是天一觀的道長。 經常有香客問我怎顾,道長读慎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任槐雾,我火速辦了婚禮夭委,結果婚禮上,老公的妹妹穿的比我還像新娘募强。我一直安慰自己株灸,他們只是感情好,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布擎值。 她就那樣靜靜地躺著慌烧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鸠儿。 梳的紋絲不亂的頭發(fā)上屹蚊,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天厕氨,我揣著相機與錄音,去河邊找鬼汹粤。 笑死命斧,一個胖子當著我的面吹牛,可吹牛的內容都是我干的嘱兼。 我是一名探鬼主播冯丙,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼遭京!你這毒婦竟也來了胃惜?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤哪雕,失蹤者是張志新(化名)和其女友劉穎船殉,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體斯嚎,經...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡利虫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了堡僻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糠惫。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖钉疫,靈堂內的尸體忽然破棺而出硼讽,到底是詐尸還是另有隱情,我是刑警寧澤牲阁,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布固阁,位于F島的核電站,受9級特大地震影響城菊,放射性物質發(fā)生泄漏备燃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一凌唬、第九天 我趴在偏房一處隱蔽的房頂上張望并齐。 院中可真熱鬧,春花似錦客税、人聲如沸况褪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窝剖。三九已至,卻和暖如春酥夭,著一層夾襖步出監(jiān)牢的瞬間赐纱,已是汗流浹背脊奋。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留疙描,地道東北人诚隙。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像起胰,于是被迫代替她去往敵國和親久又。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,517評論 25 707
  • 1.0 免費版本 EasyAR Demo 下載頁面 基礎版 Demo 2.1.0 下載地址 Pro 版 Demo ...
    zyl06閱讀 5,405評論 5 6
  • 早上聽媽媽說效五,他們要在老家蓋房地消,以后回去住。聽到這個消息不免有點心酸畏妖,但是我還是支持他們的決定脉执。父母是2000年出...
    靳善靳美閱讀 797評論 1 1
  • 從小到大我就是個很沒有主見人,別人說什么我就照聽戒劫,然后就按著他們的想法去做半夷,但是我感覺很累很累,很多東西都不是我想...
    櫻木蘭閱讀 219評論 0 2