opencv-ios开发笔记9 使用透视变换矫正扭曲的图片
http://blog.csdn.net/baixiaozhe/article/details/51762086
摄像头观察一个矩形的图片时往往只能得到一个扭曲的图片:
原图:
实际情况是摄像头经常从某个角度观察图片:
使用OpenCV的透视变换把图片矫正为正视的角度,大概过程:
1、通过灰度、模糊和二值化得到:
2、然后对查找图片外包矩形轮廓,并查找角点得到:
3、通过梯形四个角点和外包矩形的四个顶点得到变换矩阵,进行投射变换,最后得到:
如果图片看不到,请来 http://blog.csdn.NET/baixiaozhe/article/details/51762086
代码如下:
- //图片投射变换
- -(void)wrapImg{
- UIImage *imageInView = [UIImage imageNamed:@"wrap"];
- Mat wrapSrc;
- //默认转为4通道 所以下面Scalar也得是4通道,否则不能正确实现颜色
- UIImageToMat(imageInView, wrapSrc);
- NSLog(@"wrapSrc cols%d rows%d channels%d type%d depth%d elemSize%zu",wrapSrc.cols,wrapSrc.rows,wrapSrc.channels(),wrapSrc.type(),wrapSrc.depth(),wrapSrc.elemSize());
- //灰度
- Mat graymat;
- cvtColor(wrapSrc ,graymat,COLOR_BGR2GRAY);
- blur(graymat, graymat, Size2d(7,7));
- //二值化,灰度大于14的为白色 需要多调整 直至出现白色大梯形
- graymat=graymat>14;
- //Shi-Tomasi 角点算法参数
- int maxCorners=4;
- vector<Point2f> corners;
- double qualityLevel=0.01;
- double minDistance=100;//角点之间最小距离
- int blockSize=7;//轮廓越明显,取值越大
- bool useHarrisDetector=false;
- double k=0.04;
- //Shi-Tomasi 角点检测
- goodFeaturesToTrack(graymat,corners,maxCorners,qualityLevel,minDistance,Mat(),blockSize,useHarrisDetector,k);
- //cout<<"检测到角点数:"<<corners.size()<<endl;
- NSLog(@"检测到角点数:%lu",corners.size());
- int r=10;
- RNG rng;
- //画出来看看 找到的是不是四个顶点 另外角点检测出来的点顺序每次不一定相同
- /*
- if(corners.size()==4){
- circle(wrapSrc,corners[0],r,Scalar(255,0,0,255),2,8,0);//红
- circle(wrapSrc,corners[1],r,Scalar(0,255,0,255),2,8,0);//绿
- circle(wrapSrc,corners[2],r,Scalar(0,0,255,255),2,8,0);//蓝
- circle(wrapSrc,corners[3],r,Scalar(255,255,0,255),2,8,0);//黄
- }
- _imageView.image= MatToUIImage(wrapSrc) ;
- return;
- */
- std::vector<std::vector<cv::Point>> contoursOutLine;
- findContours(graymat,contoursOutLine,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
- // 对轮廓计算其凸包//
- // 边界框
- cv::Rect boudRect;
- vector<Point2i> poly ;
- for( int i = 0; i < contoursOutLine.size(); i++)
- {
- // 边界框
- boudRect= boundingRect(contoursOutLine[i] );
- //面积过滤
- int tmpArea=boudRect.area();
- if(tmpArea>= 50000 )
- {
- rectangle(wrapSrc,cvPoint(boudRect.x,boudRect.y),cvPoint(boudRect.br().x ,boudRect.br().y ),Scalar(128),2);
- }
- }
- //src=wrapSrc(boudRect); 用这种方式截屏有时候会出错 不知咋回事
- //用IOS的 quartz api来截图
- UIImage *image=[UIImage imageWithCGImage:CGImageCreateWithImageInRect([imageInView CGImage], CGRectMake(boudRect.x,boudRect.y,boudRect.width,boudRect.height))];
- Mat src,warp_dst;
- UIImageToMat(image, src);
- warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
- //从梯形srcTri[4] 变换成 外包矩形dstTri[4]
- Point2f srcTri[4];
- Point2f dstTri[4];
- Point2f aRect1=boudRect.tl();
- // 梯形四个顶点 顺序为 左上 右上 左下 右下
- Point2f srcTri0 = Point2f(corners[0].x-aRect1.x ,corners[0].y-aRect1.y );
- Point2f srcTri1 = Point2f(corners[2].x-aRect1.x ,corners[2].y-aRect1.y );
- Point2f srcTri2 = Point2f(corners[1].x-aRect1.x , corners[1].y-aRect1.y );
- Point2f srcTri3 = Point2f(corners[3].x-aRect1.x , corners[3].y-aRect1.y );
- //查找左上点 取出外包矩形的中点,然后把梯形四个顶点与中点进行大小比较,如x,y都小于中点的是左上,x大于中点,y小于中点 则为右上
- Point2f boudRectCenter=Point2f(src.cols/2,src.rows/2);
- if(srcTri0.x>boudRectCenter.x){
- if(srcTri0.y>boudRectCenter.y){//右下
- srcTri[3]=srcTri0;
- }else{//右上
- srcTri[1]=srcTri0;
- }
- }else{
- if(srcTri0.y>boudRectCenter.y){//左下
- srcTri[2]=srcTri0;
- }else{//左上
- srcTri[0]=srcTri0;
- }
- }
- if(srcTri1.x>boudRectCenter.x){
- if(srcTri1.y>boudRectCenter.y){//右下
- srcTri[3]=srcTri1;
- }else{//右上
- srcTri[1]=srcTri1;
- }
- }else{
- if(srcTri1.y>boudRectCenter.y){//左下
- srcTri[2]=srcTri1;
- }else{//左上
- srcTri[0]=srcTri1;
- }
- }
- if(srcTri2.x>boudRectCenter.x){
- if(srcTri2.y>boudRectCenter.y){//右下
- srcTri[3]=srcTri2;
- }else{//右上
- srcTri[1]=srcTri2;
- }
- }else{
- if(srcTri2.y>boudRectCenter.y){//左下
- srcTri[2]=srcTri2;
- }else{//左上
- srcTri[0]=srcTri2;
- }
- }
- if(srcTri3.x>boudRectCenter.x){
- if(srcTri3.y>boudRectCenter.y){//右下
- srcTri[3]=srcTri3;
- }else{//右上
- srcTri[1]=srcTri3;
- }
- }else{
- if(srcTri3.y>boudRectCenter.y){//左下
- srcTri[2]=srcTri3;
- }else{//左上
- srcTri[0]=srcTri3;
- }
- }
- // 画出来 看看顺序对不对
- circle(src,srcTri[0],r,Scalar(255,0,0,255),-1,8,0);//红 左上
- circle(src,srcTri[1],r,Scalar(0,255,0,255),-1,8,0);//绿 右上
- circle(src,srcTri[2],r,Scalar(0,0,255,255),-1,8,0);//蓝 左下
- circle(src,srcTri[3],r,Scalar(255,255,0,255),-1,8,0);//黄 右下
- _imageView.image= MatToUIImage(src) ;
- // return;
- // 外包矩形的四个顶点, 顺序为 左上 右上 左下 右下
- dstTri[0] = Point2f( 0,0 );
- dstTri[1] = Point2f( src.cols - 1, 0 );
- dstTri[2] = Point2f( 0, src.rows - 1 );
- dstTri[3] = Point2f( src.cols - 1, src.rows - 1 );
- //自由变换 透视变换矩阵3*3
- Mat warp_matrix( 3, 3, CV_32FC1 );
- warp_matrix=getPerspectiveTransform(srcTri ,dstTri );
- warpPerspective( src, warp_dst, warp_matrix, warp_dst.size(),WARP_FILL_OUTLIERS);
- _imageView.image= MatToUIImage(warp_dst) ;
- }
_imageView是图片控件的插头
opencv-ios开发笔记9 使用透视变换矫正扭曲的图片的更多相关文章
- iOS开发笔记7:Text、UI交互细节、两个动画效果等
Text主要总结UILabel.UITextField.UITextView.UIMenuController以及UIWebView/WKWebView相关的一些问题. UI细节主要总结界面交互开发中 ...
- iOS开发笔记-两种单例模式的写法
iOS开发笔记-两种单例模式的写法 单例模式是开发中最常用的写法之一,iOS的单例模式有两种官方写法,如下: 不使用GCD #import "ServiceManager.h" ...
- iOS开发笔记--什么时候调用layoutSubviews
iOS开发笔记--什么时候调用layoutSubviews 分类: iOS2014-04-22 16:15 610人阅读 评论(0) 收藏 举报 今天在写程序时候遇见layoutSubviews触发时 ...
- IOS开发笔记(4)数据离线缓存与读取
IOS开发笔记(4)数据离线缓存与读取 分类: IOS学习2012-12-06 16:30 7082人阅读 评论(0) 收藏 举报 iosiOSIOS 方法一:一般将服务器第一次返回的数据保存在沙盒里 ...
- IOS开发笔记 IOS如何访问通讯录
IOS开发笔记 IOS如何访问通讯录 其实我是反对这类的需求,你说你读我的隐私,我肯定不愿意的. 幸好ios6.0 以后给了个权限控制.当打开app的时候你可以选择拒绝. 实现方法: [plain] ...
- 【Swift】iOS开发笔记(二)
前言 这个系列主要是一些开发中遇到的坑记录分享,有助于初学者跨过这些坑,攒够 7 条发一篇. 声明 欢迎转载,但请保留文章原始出处:) 博客园:http://www.cnblogs.com 农民伯 ...
- 菜鸟手下的iOS开发笔记(swift)
在阳春4月的一天晨会上,有一个老板和蔼的对他的一个菜鸟手下说:“你既然会Android,那你能不能开发iOS?” 不是说好的要外包的吗?内心跌宕,但是表面淡定的菜鸟手下弱弱的回道:“可以试试”. 第二 ...
- OpenCV iOS开发(一)——安装(转)
OpenCV是一个开源跨平台的的计算机视觉和机器学习库,可以用来做图片视频的处理.图形识别.机器学习等应用.本文将介绍OpenCV iOS开发中的Hello World起步. 安装 OpenCV安装的 ...
- 李洪强iOS开发之 - 实现九宫格并使用SDWebImage下载图片
李洪强iOS开发之 - 实现九宫格并使用SDWebImage下载图片 源码: // // ViewController.m // 08-九宫格扩展 // // Created by 李洪强 ...
随机推荐
- 定义了一个UIImageView如何使加载的图片不会失真 UIImageView的Frame值是固定的
定义了一个UIImageView如何使加载的图片不会失真 UIImageView的Frame值是固定的 UIViewContentModeScaleToFill, 缩放内容到合适比例大小 UIVie ...
- Java自动类型转换
■ 自动类型转换:容量小的数据类型可以自动转换为容量大的数据类型. ■ 特例:可以讲整型常量直接赋给byte,short,char等类型变量,而不需要强制类型转换,只要不超出其表数范围. ■ 强制类型 ...
- 是否可以从一个static(静态)方法内部调用非static(非静态)方法?
不可以.static方法调用时不需要创建对象(可直接调用),当一个static方法被调用时,可能还没有创建任何实例对象,也就不可能调用非静态方法.
- django restframework 教程之Serialization(序列化)
介绍 本教程将会通过创建一个简单的粘贴代码项目,突出显示WebAPI,过程中,会介绍组成REST框架的各种组件,让你全面了解如何配合使用. 环境设置 建议使用virtualenv建立新的虚拟环境,确保 ...
- 解决 ssh 登录到ubuntu server 慢的问题
最近在服务器上使用ubuntu系统,服务器上开启sshd服务,在客户端处使用ssh登录到服务器的时候出现卡顿的现象. 在网上搜索了解决方案,主要是: 1. 修改服务器的 /etc/ssh/sshd_c ...
- java基础---->FilenameFilter之文件过滤
FilenameFilter用于对列表中文件名的过滤,今天我们就开始java中FilenameFilter的学习.好多年了,你一直在我的伤口中幽居,我放下过天地,却从未放下过你,我生命中的千山万水,任 ...
- 【BZOJ3156】防御准备 斜率优化
[BZOJ3156]防御准备 Description Input 第一行为一个整数N表示战线的总长度. 第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai. Output 共一个整数,表示最小 ...
- dubbo有什么作用
转自:http://blog.csdn.net/ichsonx/article/details/39008519 1. Dubbo是什么? Dubbo是一个分布式服务框架,致力于提供高性能和透明化的R ...
- python下几种打开文件的方式
昨天看完了这本python进阶,感觉这本书对我启发很大,做了三张纸的笔记,方便我在遇到问题的时候翻阅,然后寻找可能的解决方案.作为一个使用Python一年的小白,虽然说不是小白,但是这一年来基本上是用 ...
- MS-SQL数据库定时自动备份
在SQL Server中出于数据安全的考虑,所以需要定期的备份数据库.而备份数据库一般又是在凌晨时间基本没有数据库操作的时候进行,所以我们不可能要求管理员每天守到晚上1点去备份数据库.要实现数据库的定 ...