opencv-ios開發筆記9 使用透視變換矯正扭曲的圖片

來源:互聯網
上載者:User

網路攝影機觀察一個矩形的圖片時往往只能得到一個扭曲的圖片:

原圖:


實際情況是網路攝影機經常從某個角度觀察圖片:

 

使用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是圖片控制項的插頭

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.