opencv-ios开发笔记9 使用透视变换矫正扭曲的图片

http://blog.csdn.net/baixiaozhe/article/details/51762086

摄像头观察一个矩形的图片时往往只能得到一个扭曲的图片:

原图:

实际情况是摄像头经常从某个角度观察图片:

 

使用OpenCV的透视变换把图片矫正为正视的角度,大概过程:

1、通过灰度、模糊和二值化得到:

2、然后对查找图片外包矩形轮廓,并查找角点得到:

3、通过梯形四个角点和外包矩形的四个顶点得到变换矩阵,进行投射变换,最后得到:

如果图片看不到,请来 http://blog.csdn.NET/baixiaozhe/article/details/51762086

代码如下:

 

[objc] view plain copy
 
  1. //图片投射变换  
  2. -(void)wrapImg{  
  3.     UIImage *imageInView  = [UIImage imageNamed:@"wrap"];  
  4.     Mat wrapSrc;  
  5.     //默认转为4通道 所以下面Scalar也得是4通道,否则不能正确实现颜色  
  6.     UIImageToMat(imageInView, wrapSrc);  
  7.      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());  
  8.    
  9.      //灰度  
  10.     Mat graymat;  
  11.     cvtColor(wrapSrc ,graymat,COLOR_BGR2GRAY);  
  12.      blur(graymat, graymat, Size2d(7,7));  
  13.      //二值化,灰度大于14的为白色 需要多调整 直至出现白色大梯形  
  14.     graymat=graymat>14;  
  15.       
  16.      //Shi-Tomasi 角点算法参数  
  17.     int maxCorners=4;  
  18.     vector<Point2f> corners;  
  19.     double qualityLevel=0.01;  
  20.     double minDistance=100;//角点之间最小距离  
  21.     int blockSize=7;//轮廓越明显,取值越大  
  22.     bool useHarrisDetector=false;  
  23.     double k=0.04;  
  24.      //Shi-Tomasi 角点检测  
  25.     goodFeaturesToTrack(graymat,corners,maxCorners,qualityLevel,minDistance,Mat(),blockSize,useHarrisDetector,k);  
  26.      //cout<<"检测到角点数:"<<corners.size()<<endl;  
  27.     NSLog(@"检测到角点数:%lu",corners.size());  
  28.     int r=10;  
  29.     RNG rng;  
  30.     //画出来看看 找到的是不是四个顶点 另外角点检测出来的点顺序每次不一定相同  
  31.     /* 
  32.     if(corners.size()==4){ 
  33.         circle(wrapSrc,corners[0],r,Scalar(255,0,0,255),2,8,0);//红 
  34.         circle(wrapSrc,corners[1],r,Scalar(0,255,0,255),2,8,0);//绿 
  35.         circle(wrapSrc,corners[2],r,Scalar(0,0,255,255),2,8,0);//蓝 
  36.         circle(wrapSrc,corners[3],r,Scalar(255,255,0,255),2,8,0);//黄 
  37.     } 
  38.       _imageView.image= MatToUIImage(wrapSrc) ; 
  39.      return; 
  40.     */  
  41.     std::vector<std::vector<cv::Point>> contoursOutLine;  
  42.     findContours(graymat,contoursOutLine,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);  
  43.     // 对轮廓计算其凸包//  
  44.     // 边界框  
  45.     cv::Rect boudRect;  
  46.     vector<Point2i>  poly ;  
  47.     for( int i = 0; i < contoursOutLine.size();  i++)  
  48.     {  
  49.         // 边界框  
  50.         boudRect=  boundingRect(contoursOutLine[i] );  
  51.         //面积过滤  
  52.         int tmpArea=boudRect.area();  
  53.         if(tmpArea>= 50000 )  
  54.         {  
  55.             rectangle(wrapSrc,cvPoint(boudRect.x,boudRect.y),cvPoint(boudRect.br().x ,boudRect.br().y ),Scalar(128),2);  
  56.         }  
  57.     }  
  58.      //src=wrapSrc(boudRect); 用这种方式截屏有时候会出错 不知咋回事  
  59.     //用IOS的 quartz api来截图  
  60.      UIImage *image=[UIImage imageWithCGImage:CGImageCreateWithImageInRect([imageInView CGImage], CGRectMake(boudRect.x,boudRect.y,boudRect.width,boudRect.height))];  
  61.      Mat src,warp_dst;  
  62.     UIImageToMat(image, src);  
  63.    
  64.       
  65.      warp_dst = Mat::zeros( src.rows, src.cols, src.type() );  
  66.       
  67.     //从梯形srcTri[4] 变换成 外包矩形dstTri[4]  
  68.     Point2f srcTri[4];  
  69.     Point2f dstTri[4];  
  70.      
  71.     Point2f aRect1=boudRect.tl();  
  72.      // 梯形四个顶点 顺序为 左上  右上  左下  右下  
  73.     Point2f srcTri0 = Point2f(corners[0].x-aRect1.x  ,corners[0].y-aRect1.y );  
  74.     Point2f srcTri1 = Point2f(corners[2].x-aRect1.x  ,corners[2].y-aRect1.y );  
  75.     Point2f srcTri2 = Point2f(corners[1].x-aRect1.x  , corners[1].y-aRect1.y );  
  76.     Point2f srcTri3 = Point2f(corners[3].x-aRect1.x  , corners[3].y-aRect1.y );  
  77.     //查找左上点 取出外包矩形的中点,然后把梯形四个顶点与中点进行大小比较,如x,y都小于中点的是左上,x大于中点,y小于中点 则为右上  
  78.     Point2f boudRectCenter=Point2f(src.cols/2,src.rows/2);  
  79.     if(srcTri0.x>boudRectCenter.x){  
  80.         if(srcTri0.y>boudRectCenter.y){//右下  
  81.             srcTri[3]=srcTri0;  
  82.         }else{//右上  
  83.             srcTri[1]=srcTri0;  
  84.         }  
  85.     }else{  
  86.         if(srcTri0.y>boudRectCenter.y){//左下  
  87.           srcTri[2]=srcTri0;  
  88.         }else{//左上  
  89.             srcTri[0]=srcTri0;  
  90.         }  
  91.     }  
  92.     if(srcTri1.x>boudRectCenter.x){  
  93.         if(srcTri1.y>boudRectCenter.y){//右下  
  94.             srcTri[3]=srcTri1;  
  95.         }else{//右上  
  96.             srcTri[1]=srcTri1;  
  97.         }  
  98.     }else{  
  99.         if(srcTri1.y>boudRectCenter.y){//左下  
  100.             srcTri[2]=srcTri1;  
  101.         }else{//左上  
  102.             srcTri[0]=srcTri1;  
  103.         }  
  104.     }  
  105.   
  106.     if(srcTri2.x>boudRectCenter.x){  
  107.         if(srcTri2.y>boudRectCenter.y){//右下  
  108.             srcTri[3]=srcTri2;  
  109.         }else{//右上  
  110.             srcTri[1]=srcTri2;  
  111.         }  
  112.     }else{  
  113.         if(srcTri2.y>boudRectCenter.y){//左下  
  114.             srcTri[2]=srcTri2;  
  115.         }else{//左上  
  116.             srcTri[0]=srcTri2;  
  117.         }  
  118.     }  
  119.   
  120.     if(srcTri3.x>boudRectCenter.x){  
  121.         if(srcTri3.y>boudRectCenter.y){//右下  
  122.             srcTri[3]=srcTri3;  
  123.         }else{//右上  
  124.             srcTri[1]=srcTri3;  
  125.         }  
  126.     }else{  
  127.         if(srcTri3.y>boudRectCenter.y){//左下  
  128.             srcTri[2]=srcTri3;  
  129.         }else{//左上  
  130.             srcTri[0]=srcTri3;  
  131.         }  
  132.     }  
  133.       // 画出来 看看顺序对不对  
  134.     circle(src,srcTri[0],r,Scalar(255,0,0,255),-1,8,0);//红 左上  
  135.     circle(src,srcTri[1],r,Scalar(0,255,0,255),-1,8,0);//绿 右上  
  136.     circle(src,srcTri[2],r,Scalar(0,0,255,255),-1,8,0);//蓝 左下  
  137.     circle(src,srcTri[3],r,Scalar(255,255,0,255),-1,8,0);//黄 右下  
  138.       
  139.      _imageView.image= MatToUIImage(src) ;  
  140.      //  return;  
  141.       
  142.     // 外包矩形的四个顶点, 顺序为 左上  右上  左下  右下  
  143.     dstTri[0] = Point2f( 0,0 );  
  144.     dstTri[1] = Point2f( src.cols - 1, 0 );  
  145.     dstTri[2] = Point2f( 0, src.rows - 1 );  
  146.     dstTri[3] = Point2f( src.cols - 1, src.rows - 1 );  
  147.     //自由变换 透视变换矩阵3*3  
  148.     Mat warp_matrix( 3, 3, CV_32FC1 );  
  149.     warp_matrix=getPerspectiveTransform(srcTri  ,dstTri  );  
  150.     warpPerspective( src, warp_dst, warp_matrix, warp_dst.size(),WARP_FILL_OUTLIERS);  
  151.       
  152.      _imageView.image= MatToUIImage(warp_dst) ;  
  153.  }  


_imageView是图片控件的插头

 

posted @ 2017-08-28 17:33  mydddfly  阅读(3489)  评论(0编辑  收藏  举报