網路攝影機觀察一個矩形的圖片時往往只能得到一個扭曲的圖片:
原圖:
實際情況是網路攝影機經常從某個角度觀察圖片:
使用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是圖片控制項的插頭