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是圖片控件的插頭

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM