先看效果图
原图
拼接后的效果图
下面开始介绍拼接图片过程
请看项目目录
在Github
上面搜索CVWrapper
,选择Objective-C
部分,将上图中的文件导入到项目中。ImageUnti
是我另外添加的裁剪图片的工具类,你们可以在我之前的文章中找一下源代码。
由于opencv
库太大,在github
上面下载的项目中,里面会没有相应的framework
文件,这时候,可以去github
或百度上面另外下载。
编译一下项目,如果没有出错,就可以继续使用了。
使用过程
请看代码
#import "ViewController.h"
#import "CVWrapper.h"
#import "ImageUtil.h"
@interface ViewController ()<UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (nonatomic,strong) UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *indictor;
@end
@implementation ViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.indictor.center = self.view.center;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.imageView.contentMode = UIViewContentModeScaleToFill;
[self createFullShotImages];
}
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark 异步线程 拼接全景图片
- (void)createFullShotImages
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.indictor startAnimating];
CGSize size = CGSizeMake(720, 960);
NSMutableArray *images = [NSMutableArray array];
for (int i = 0; i<7; i++)
{
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg",i]];
NSAssert(image != nil, @"image 数据不能为空");
[images addObject:[ImageUtil resizeImageWithImage:image targetSize:CGSizeMake(640, 360)]];
}
//TODO:在这里传入需要拼接的图片数组,返回拼接后的图片
UIImage *fullShotImage = [CVWrapper processWithArray:images];
//回到主线程中显示拼接后的image
dispatch_async(dispatch_get_main_queue(), ^{
UIImageView *midImageView = [[UIImageView alloc]initWithImage:fullShotImage];
self.imageView = midImageView;
[self.scrollView addSubview:self.imageView];
//利用scrollView控制全景图片的缩放
self.scrollView.backgroundColor = [UIColor darkGrayColor];
self.scrollView.contentSize = self.imageView.bounds.size;
self.scrollView.maximumZoomScale = 4.0;
self.scrollView.minimumZoomScale = 0.5;
self.scrollView.delegate = self;
CGFloat pointX = -(self.scrollView.bounds.size.width - self.imageView.bounds.size.width)/2.0;
CGFloat pointY = -(self.scrollView.bounds.size.height - self.imageView.bounds.size.height)/2.0;
self.scrollView.contentOffset = CGPointMake(pointX, pointY);
[self.indictor stopAnimating];
self.indictor.hidesWhenStopped = YES;
});
});
}
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
主要代码使用起来很简单,但是还有几点需要注意
- 每两个相邻的拼接图片之间需要有重叠的部分
- 所有需要拼接的图片需要处于同一水平线上,不然可能会有拼接失败或图片混乱的情况
libjpeg.a
文件是辅助opencv
使用的,这个也不可缺少。
至于制作全景相机的思路,我们可以使用自定义相机,利用重力感应控制好输出图片的水平位置,然后拍摄和拼接图片。我的思路不一定是最简单和正确的,还请各位多多指教。
要源码的人太多了,这里就把完整版的项目上传一下,地址完整版项目+OpenCV.Framework,密码:xr0u。代码在分享的过程中才能更加完善,谢谢各位的指导,喜欢的小伙伴可以给一个小心心(笑哭),打赏就不用了。
补充
当单个图片分辨率过大时,在合成的过程中会因为数据越界出现下面的错误提示
OpenCV Error: Assertion failed ((globalDescIdx>=0) && (globalDescIdx < size())) in getLocalIdx, file /Volumes/build-storage/build/2_4_iOS-mac/opencv/modules/features2d/src/matchers.cpp, line 163
libc++abi.dylib: terminating with uncaught exception of type cv::Exception: /Volumes/build-storage/build/2_4_iOS-mac/opencv/modules/features2d/src/matchers.cpp:163: error: (-215) (globalDescIdx>=0) && (globalDescIdx < size()) in function getLocalIdx
这时可以降低一下图片的分辨率,使用ImageUtil
这个类中的resizeImageWithImage: targetSize:
方法即可。