2012-10-27 140 views
8

我在IOS中使用打開的CV。我已經在圖像中顯示圖像中的紙張邊界,並且現在我必須拖動這些邊界線來調整裁剪框。我們如何調整邊界線以及如何在邊界內裁剪圖像?調整角落並裁剪圖像openCV

這是可能的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; 

} 

感謝所有

enter image description here

+0

你是如何創建的網格?你願意分享一些示例代碼嗎?我有類似的問題,張貼在這裏:http://stackoverflow.com/questions/13269432/perspective-transform-crop-in-ios-with-opencv – mmackh

+0

@Gryphon我很想知道這一點。你是如何創建網格的? – alandalusi

+0

@Gryphon請看我的帖子http://stackoverflow.com/questions/13594391/ios-drawing-a-rectangle-on-an-imageview-and-adjusting-borders – alandalusi

回答

9

後你得到了拐角處,有抗扭斜紙和「解壓」,它以全新的形象。

你應該做到以下幾點:

  1. 排序角點(該命令的事項;他們必須是在兩個矢量相同的順序)
  2. cv::getAffineTransform
  3. cv::warpAffine

我寫了一個幫助函數,它需要一個std::vector,其中有四個cv::Point,並按順時針順序排列它們,從u pper離開。有關此主題的更多信息,看看這些線程:

你應該考慮的另一件事情就是你要的紙張尺寸提取。在我的例子中,我假設你正在提取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); 
+0

感謝您的答案,我正在嘗試這個 – QueueOverFlow

+0

感謝您的幫助,它沒有任何錯誤地執行,但圖像沒有在輸出中顯示,有時imageView是黑色的,有時是灰色的,任何想法? – QueueOverFlow

+0

我編輯了這個問題,請看看。 – QueueOverFlow

1

你應該做的是:

  1. 飼料4個角是你已經找到了和圖像的4個真實的角落cv::getPerspectiveTransform。它會給你一個透視變換的矩陣,使四邊形翹曲到整個圖像。

  2. 使用cv::WarpPerspective來創建你想要的圖像。

鏈接將帶您到文檔。

編輯:你可以使用cv::findHomography做第1步。但這更多的是有很多相應的點和異常值。

編輯:這裏是一個例子。它與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

編輯:這裏有一些樣品。我沒有看到他們很好。

Geometric Image Transformations

cvGetPerspectiveTransform

+0

你能提供任何關於此的鏈接或示例。 – QueueOverFlow

+0

添加了代碼示例。 –