zoukankan      html  css  js  c++  java
  • 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是图片控件的插头

  • 相关阅读:
    [cf582E]Boolean Function
    [atAGC029F]Construction of a tree
    [atAGC020E]Encoding Subsets
    [gym102769L]Lost Temple
    [atAGC034E]Complete Compress
    [cf566E]Restoring Map
    [atAGC023F]01 on Tree
    [gym102822I]Invaluable Assets
    [gym102900H]Rice Arrangement
    [Offer收割]编程练习赛32
  • 原文地址:https://www.cnblogs.com/jukan/p/7444866.html
Copyright © 2011-2022 走看看