调整angular落和裁剪图像openCV

我在IOS中使用公开简历。 我已经在图像中显示了图像中的纸张边界,现在我必须拖动这些边界线来调整裁剪框。 我们如何调整边界线以及如何在边界内裁剪图像?

这是可能的openCV或我使用OpenGL的呢?

@moosgummi:我在下面的方法中调用你的方法

- (cv::Mat)finshWork:(cv::Mat &)image { Mat img0 =image; Mat img1; cvtColor(img0, img1, CV_RGB2GRAY); // apply your filter Canny(img1, img1, 100, 200); // find the contours vector< vector<cv::Point> > contours; findContours(img1, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); // you could also reuse img1 here Mat mask = Mat::zeros(img1.rows, img1.cols, CV_8UC1); // CV_FILLED fills the connected components found drawContours(mask, contours, -1, Scalar(255), CV_FILLED); // let's create a new image now Mat crop(img0.rows, img0.cols, CV_8UC3); // set background to green crop.setTo(Scalar(0,255,0)); // and copy the magic apple img0.copyTo(crop, mask); // normalize so imwrite(...)/imshow(...) shows the mask correctly! normalize(mask.clone(), mask, 0.0, 255.0, CV_MINMAX, CV_8UC1); std::vector<cv::Point> biggestContour = contours[contours.size()-1]; NSLog(@"%d",biggestContour[0].x); NSLog(@"%d",biggestContour[0].y); cv::Mat paperImage =[self getPaperAreaFromImage:image:biggestContour]; //return crop; return paperImage; } 

谢谢大家

在这里输入图像说明

在得到angular落之后,您必须将纸张倾斜并“提取”成新的图像。

您应该执行以下操作:

  1. 排列angular点(顺序很重要;它们必须在两个vector中的顺序相同)
  2. cv::getAffineTransform
  3. cv::warpAffine

我自己写了一个帮助函数,它将一个带有四个cv::Pointstd::vector从左上angular开始顺时针sorting。 有关此主题的更多信息,请看这些主题:

  • 按顺时针sorting点?
  • 按顺序排列四点
  • 二维空间中的点sorting

你应该考虑的另一件事是你想要提取的纸张的大小。 在我的例子中,我假设你正在提取DIN A4纸(210x297mm)。 随意编辑我的代码中的paperWidthpaperHeight

结合一切看起来像这样:

 // Helper cv::Point getCenter( std::vector<cv::Point> points ) { cv::Point center = cv::Point( 0.0, 0.0 ); for( size_t i = 0; i < points.size(); i++ ) { center.x += points[ i ].x; center.y += points[ i ].y; } center.x = center.x / points.size(); center.y = center.y / points.size(); return center; } // Helper; // 0----1 // | | // | | // 3----2 std::vector<cv::Point> sortSquarePointsClockwise( std::vector<cv::Point> square ) { cv::Point center = getCenter( square ); std::vector<cv::Point> sorted_square; for( size_t i = 0; i < square.size(); i++ ) { if ( (square[i].x - center.x) < 0 && (square[i].y - center.y) < 0 ) { switch( i ) { case 0: sorted_square = square; break; case 1: sorted_square.push_back( square[1] ); sorted_square.push_back( square[2] ); sorted_square.push_back( square[3] ); sorted_square.push_back( square[0] ); break; case 2: sorted_square.push_back( square[2] ); sorted_square.push_back( square[3] ); sorted_square.push_back( square[0] ); sorted_square.push_back( square[1] ); break; case 3: sorted_square.push_back( square[3] ); sorted_square.push_back( square[0] ); sorted_square.push_back( square[1] ); sorted_square.push_back( square[2] ); break; } break; } } return sorted_square; } // Helper float distanceBetweenPoints( cv::Point p1, cv::Point p2 ) { if( p1.x == p2.x ) { return abs( p2.y - p1.y ); } else if( p1.y == p2.y ) { return abs( p2.x - p1.x ); } else { float dx = p2.x - p1.x; float dy = p2.y - p1.y; return sqrt( (dx*dx)+(dy*dy) ); } } cv::Mat getPaperAreaFromImage( cv::Mat image, std::vector<cv::Point> square ) { // declare used vars int paperWidth = 210; // in mm, because scale factor is taken into account int paperHeight = 297; // in mm, because scale factor is taken into account cv::Point2f imageVertices[4]; float distanceP1P2; float distanceP1P3; BOOL isLandscape = true; int scaleFactor; cv::Mat paperImage; cv::Mat paperImageCorrected; cv::Point2f paperVertices[4]; // sort square corners for further operations square = sortSquarePointsClockwise( square ); // rearrange to get proper order for getPerspectiveTransform() imageVertices[0] = square[0]; imageVertices[1] = square[1]; imageVertices[2] = square[3]; imageVertices[3] = square[2]; // get distance between corner points for further operations distanceP1P2 = distanceBetweenPoints( imageVertices[0], imageVertices[1] ); distanceP1P3 = distanceBetweenPoints( imageVertices[0], imageVertices[2] ); // calc paper, paperVertices; take orientation into account if ( distanceP1P2 > distanceP1P3 ) { scaleFactor = ceil( lroundf(distanceP1P2/paperHeight) ); // we always want to scale the image down to maintain the best quality possible paperImage = cv::Mat( paperWidth*scaleFactor, paperHeight*scaleFactor, CV_8UC3 ); paperVertices[0] = cv::Point( 0, 0 ); paperVertices[1] = cv::Point( paperHeight*scaleFactor, 0 ); paperVertices[2] = cv::Point( 0, paperWidth*scaleFactor ); paperVertices[3] = cv::Point( paperHeight*scaleFactor, paperWidth*scaleFactor ); } else { isLandscape = false; scaleFactor = ceil( lroundf(distanceP1P3/paperHeight) ); // we always want to scale the image down to maintain the best quality possible paperImage = cv::Mat( paperHeight*scaleFactor, paperWidth*scaleFactor, CV_8UC3 ); paperVertices[0] = cv::Point( 0, 0 ); paperVertices[1] = cv::Point( paperWidth*scaleFactor, 0 ); paperVertices[2] = cv::Point( 0, paperHeight*scaleFactor ); paperVertices[3] = cv::Point( paperWidth*scaleFactor, paperHeight*scaleFactor ); } cv::Mat warpMatrix = getPerspectiveTransform( imageVertices, paperVertices ); cv::warpPerspective(_image, paperImage, warpMatrix, paperImage.size(), cv::INTER_LINEAR, cv::BORDER_CONSTANT ); // we want portrait output if ( isLandscape ) { cv::transpose(paperImage, paperImageCorrected); cv::flip(paperImageCorrected, paperImageCorrected, 1); return paperImageCorrected; } return paperImage; } 

用法:

 // ... get paper square ... cv::Mat paperImage = getPaperAreaFromImage( srcImage, paperSquare ); 

你应该做的是:

  1. 将你find的4个angular落和图像的4个真实angular落送到cv::getPerspectiveTransform 。 它会给你一个matrix的透视变换,将四边形扭曲到整个图像。

  2. 使用cv::WarpPerspective创build你想要的图像。

链接将带你到文档。

编辑:你可以使用cv::findHomography做第1步。但是这更多的是有很多相应的点和exception值。

编辑:这是一个例子。 它是与C接口,但你可以很容易地使其与C ++的工作

 #include <stdio.h> #include "highgui.h" #include "cv.h" int main( int argc, char** argv ) { // cvLoadImage determines an image type and creates datastructure with appropriate size IplImage* img = cvLoadImage( argv[1], CV_LOAD_IMAGE_COLOR); IplImage* img1 = cvCreateImage( cvSize(img->width, img->height), img->depth, img->nChannels ); cvNamedWindow( "out", CV_WINDOW_AUTOSIZE ); cvShowImage( "out", img1 ); // create a window. Window name is determined by a supplied argument cvNamedWindow( argv[1], CV_WINDOW_AUTOSIZE ); // Display an image inside and window. Window name is determined by a supplied argument cvShowImage( argv[1], img ); // The part you need // Here is the points that you take the image from (the small quadrangle) CvPoint2D32f first[4] = { {0,0}, {(img->width /4)* 3, img->height /4 }, { img->width /4 ,(img->height /4) *3}, {(img->width /4)* 3,(img->height /4) *3}, }; // Here are the points that you draw the quadrangle into (the four corners) CvPoint2D32f second[4] = { {0,0}, {img->width,0}, {0,img->height}, {img->width,img->height} }; // The part you need CvMat *transform = cvCreateMat(3,3, CV_32F); cvGetPerspectiveTransform(first,second, transform); cvWarpPerspective(img, img1, transform, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, cvScalarAll(0)); // End of part you need cvShowImage( "out", img1 ); // wait indefinitely for keystroke cvWaitKey(0); // release pointer to an object cvReleaseImage( &img ); // Destroy a window cvDestroyWindow( argv[1] ); } 

您应该first用已find的四边形的端点replace数组。

编辑:这里是一些样品。 我没有看到他们很好。

几何图像转换

cvGetPerspectiveTransform