2012-10-27 23 views
8

मैं आईओएस में खुले सीवी का उपयोग कर रहा हूं। मैंने छवि में शो के रूप में पहले से ही एक छवि में पेपर शीट की सीमा का पता लगाया है, और अब मुझे फसल फ्रेम को समायोजित करने के लिए इन सीमा रेखा को स्पर्श पर खींचना होगा। हम सीमा रेखा को कैसे समायोजित कर सकते हैं और हम सीमा के अंदर छवि को कैसे फसल कर सकते हैं?कोनों को समायोजित करें और छवि को खोलें सीसी

ओपनसीवी में यह संभव है या मैं इसके लिए ओपनजीएल का उपयोग करता हूं?

@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

के बाद आप कोनों मिल गया आप एक नई छवि को कागज deskewing और "निकालने" यह करने के लिए है।

  1. क्रमबद्ध कोने अंक (क्रम मामलों, वे दोनों वैक्टर में एक ही क्रम में होना चाहिए)
  2. cv::getAffineTransform
  3. cv::warpAffine

मैं:

आप निम्न करना चाहिए अपने आप को लिखा एक सहायक समारोह, यू में शुरुआत जो उस में चार cv::Point के साथ एक std::vector लेता है और उन्हें दक्षिणावर्त क्रम में सॉर्ट करता पेपर छोड़ दिया।इस विषय पर अधिक जानकारी के लिए इन धागा पर एक नज़र डालें:

एक और बात आप ध्यान में रखना चाहिए कि आप करना चाहते हैं कागज के आकार है निकालें। मेरे उदाहरण में मुझे लगता है कि आप एक डीआईएन ए 4 पेपर निकालने जा रहे हैं (210x297 मिमी)। मेरे कोड के अंदर paperWidth और paperHeight संपादित करने के लिए स्वतंत्र महसूस करें।

संयोजन सब कुछ इस तरह दिखता है:

// 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

आपकी मदद के लिए धन्यवाद, इसे बिना किसी त्रुटि के निष्पादित किया गया है, लेकिन आउटपुट में छवि नहीं दिखायी गई है, कभी-कभी छवि काले और कभी-कभी ग्रे, कोई विचार है? – QueueOverFlow

+0

मैंने सवाल संपादित किया कृपया एक नज़र डालें। – QueueOverFlow

1

क्या करना चाहिए है:

  1. फ़ीड 4 कोनों कि आपने पाया है और छवि के 4 वास्तविक कोनों कोपर मिला है। यह आपको परिप्रेक्ष्य परिवर्तन का एक मैट्रिक्स देगा जो पूरी छवि में चतुर्भुज को घुमाएगा।

  2. अपनी इच्छित छवि बनाने के लिए cv::WarpPerspective का उपयोग करें।

लिंक प्रलेखन के लिए ले जाएगा।

संपादित करें: आप cv::findHomography इस्तेमाल कर सकते हैं चरण 1 करने के लिए लेकिन यह इसी अंक और बाहरी कारकों के कारण का एक बहुत होने के बारे में अधिक है।

संपादित करें: यहां एक उदाहरण है। यह सी इंटरफेस के साथ है, लेकिन आप आसानी से इसे 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

जोड़ा गया कोड नमूना। –

संबंधित मुद्दे