opencv-ios开发笔记9 使用透视变换矫正扭曲的图片
2016-06-26 12:08
866 查看
摄像头观察一个矩形的图片时往往只能得到一个扭曲的图片:
原图:
实际情况是摄像头经常从某个角度观察图片:
使用opencv的透视变换把图片矫正为正视的角度,大概过程:
1、通过灰度、模糊和二值化得到:
2、然后对查找图片外包矩形轮廓,并查找角点得到:
3、通过梯形四个角点和外包矩形的四个顶点得到变换矩阵,进行投射变换,最后得到:
如果图片看不到,请来 http://blog.csdn.net/baixiaozhe/article/details/51762086
代码如下:
_imageView是图片控件的插头
原图:
实际情况是摄像头经常从某个角度观察图片:
使用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是图片控件的插头
相关文章推荐
- python中使用OpenCV进行人脸检测的例子
- opencv 做人脸识别 opencv 人脸匹配分析
- 使用opencv拉伸图像扩大分辨率示例
- Objective-C的内省(Introspection)用法小结
- Android Studio中配置OpenCV库开发环境的教程
- 基于C++实现kinect+opencv 获取深度及彩色数据
- visual studio 2012安装配置方法图文教程 附opencv配置教程
- OpenCV 2.4.3 C++ 平滑处理分析
- Objective-C中常用的结构体NSRange,NSPoint,NSSize(CGSize),NSRect实例分析
- Objective-C中使用NSString类操作字符串的方法小结
- Objective-C中NSNumber与NSDictionary的用法简介
- Objective-C实现冒泡排序算法的简单示例
- Objective-C中NSLog输出格式大全
- Objective-C实现自定义的半透明导航
- 浅析Objective-C的程序结构及面向对象的编程方式
- Objective-C的入门学习笔记
- Objective-C实现无限循环轮播器
- Python中使用OpenCV库来进行简单的气象学遥感影像计算
- 利用Python和OpenCV库将URL转换为OpenCV格式的方法
- python结合opencv实现人脸检测与跟踪