2012-11-07 11 views
49

के साथ आईओएस में परिप्रेक्ष्य परिवर्तन + फसल मैं आने वाले ऐप में & परिप्रेक्ष्य सुधार सुविधा को लागू करने की कोशिश कर रहा हूं। अनुसंधान कर रहे हैं जबकि, मैं भर में आया था:ओपनसीवी

Executing cv::warpPerspective for a fake deskewing on a set of cv::Point

http://sudokugrab.blogspot.ch/2009/07/how-does-it-all-work.html

तो मैं OpenCV के साथ यह सुविधा लागू करने की कोशिश करने का फैसला किया - ढांचा है तो स्थापना तेजी से किया गया था। (2 चित्र परिणाम है)

Original Photo & cropping box

Cropped Photo, bad result

मैं Xcode और ट्रिपल निर्देशांक जाँच के साथ काम करने के लिए सभी कोड अनुवाद किया है: हालांकि, मैं परिणाम मैं के लिए आशा व्यक्त की नहीं हो रही है । क्या आप मुझे बता सकते हैं कि मेरे कोड में क्या गलत है?

- (void)confirmedImage 
{ 
    if ([_adjustRect frameEdited]) { 

    cv::Mat src = [self cvMatFromUIImage:_sourceImage]; 

    // My original Coordinates 
    // 4-------3 
    // |  | 
    // |  | 
    // |  | 
    // 1-------2 

    CGFloat scaleFactor = [_sourceImageView contentScale]; 
    CGPoint p1 = [_adjustRect coordinatesForPoint:4 withScaleFactor:scaleFactor]; 
    CGPoint p2 = [_adjustRect coordinatesForPoint:3 withScaleFactor:scaleFactor]; 
    CGPoint p3 = [_adjustRect coordinatesForPoint:1 withScaleFactor:scaleFactor]; 
    CGPoint p4 = [_adjustRect coordinatesForPoint:2 withScaleFactor:scaleFactor]; 

    std::vector<cv::Point2f> c1; 
    c1.push_back(cv::Point2f(p1.x, p1.y)); 
    c1.push_back(cv::Point2f(p2.x, p2.y)); 
    c1.push_back(cv::Point2f(p3.x, p3.y)); 
    c1.push_back(cv::Point2f(p4.x, p4.y)); 

    cv::RotatedRect box = minAreaRect(cv::Mat(c1)); 
    cv::Point2f pts[4]; 
    box.points(pts); 

    cv::Point2f src_vertices[3]; 
    src_vertices[0] = pts[0]; 
    src_vertices[1] = pts[1]; 
    src_vertices[2] = pts[3]; 

    cv::Point2f dst_vertices[4]; 
    dst_vertices[0].x = 0; 
    dst_vertices[0].y = 0; 

    dst_vertices[1].x = box.boundingRect().width-1; 
    dst_vertices[1].y = 0; 

    dst_vertices[2].x = 0; 
    dst_vertices[2].y = box.boundingRect().height-1; 

    dst_vertices[3].x = box.boundingRect().width-1; 
    dst_vertices[3].y = box.boundingRect().height-1; 

    cv::Mat warpAffineMatrix = getAffineTransform(src_vertices, dst_vertices); 

    cv::Mat rotated; 
    cv::Size size(box.boundingRect().width, box.boundingRect().height); 
    warpAffine(src, rotated, warpAffineMatrix, size, cv::INTER_LINEAR, cv::BORDER_CONSTANT); 


    [_sourceImageView setNeedsDisplay]; 
    [_sourceImageView setImage:[self UIImageFromCVMat:rotated]]; 
    [_sourceImageView setContentMode:UIViewContentModeScaleAspectFit]; 

    rotated.release(); 
    src.release(); 

    } 
} 

- (UIImage *)UIImageFromCVMat:(cv::Mat)cvMat 
{ 
    NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()]; 
    CGColorSpaceRef colorSpace; 
    if (cvMat.elemSize() == 1) { 
     colorSpace = CGColorSpaceCreateDeviceGray(); 
    } 
    else { 
     colorSpace = CGColorSpaceCreateDeviceRGB(); 
    } 
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); 
    CGImageRef imageRef = CGImageCreate(cvMat.cols, cvMat.rows, 8, 8 * cvMat.elemSize(), cvMat.step[0], colorSpace, kCGImageAlphaNone|kCGBitmapByteOrderDefault, provider, NULL, false, kCGRenderingIntentDefault); 
    UIImage *finalImage = [UIImage imageWithCGImage:imageRef]; 
    CGImageRelease(imageRef); 
    CGDataProviderRelease(provider); 
    CGColorSpaceRelease(colorSpace); 
    return finalImage; 
} 

- (cv::Mat)cvMatFromUIImage:(UIImage *)image 
{ 
    CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage); 
    CGFloat cols = image.size.width; 
    CGFloat rows = image.size.height; 
    cv::Mat cvMat(rows, cols, CV_8UC4); 
    CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, cols, rows, 8, cvMat.step[0], colorSpace, kCGImageAlphaNoneSkipLast | kCGBitmapByteOrderDefault); 
    CGContextDrawImage(contextRef, CGRectMake(0, 0, rows, cols), image.CGImage); 
    CGContextRelease(contextRef); 
    CGColorSpaceRelease(colorSpace); 
    return cvMat; 
} 

यह मेरी समस्या का सही दृष्टिकोण है:> चटाई रूपांतरण + उलट - पूर्णता के लिए, मैं भी UIImage शामिल किया है? क्या आपके पास कोई नमूना कोड है जो मेरी मदद कर सकता है?

मेरा प्रश्न पढ़ने के लिए धन्यवाद!

UDATE:

मैं वास्तव में मेरी UIImagePickerController प्रतिस्थापन यहाँ Sourced खोलें है: https://github.com/mmackh/MAImagePickerController-of-InstaPDF समायोज्य फसल देखने के लिए, फिल्टर और परिप्रेक्ष्य सुधार भी शामिल है जो।

+2

आपका प्रश्न अच्छी तरह से तैयार दोस्त है! –

+1

धन्यवाद, एक बार पूरा हो जाने पर मैं दूसरों को भी मदद करने के लिए पूरे स्रोत कोड को जारी करने की योजना बना रहा हूं। यह इस समय मुझे कुछ सिरदर्द दे रहा है। – mmackh

+0

आपका प्रश्न परिप्रेक्ष्य परिवर्तन करने के बारे में है, लेकिन आपका कोड getAffineTransform और warpAffine का उपयोग कर रहा है। –

उत्तर

49

तो यह हल करने की कोशिश की कुछ दिनों के बाद, मैं एक समाधान (दूसरी छवि पर नीले बिंदुओं पर ध्यान न दें) के साथ आया था कोड:

- (void)confirmedImage 
{ 
    cv::Mat originalRot = [self cvMatFromUIImage:_sourceImage]; 
    cv::Mat original; 
    cv::transpose(originalRot, original); 

    originalRot.release(); 

    cv::flip(original, original, 1); 


    CGFloat scaleFactor = [_sourceImageView contentScale]; 

    CGPoint ptBottomLeft = [_adjustRect coordinatesForPoint:1 withScaleFactor:scaleFactor]; 
    CGPoint ptBottomRight = [_adjustRect coordinatesForPoint:2 withScaleFactor:scaleFactor]; 
    CGPoint ptTopRight = [_adjustRect coordinatesForPoint:3 withScaleFactor:scaleFactor]; 
    CGPoint ptTopLeft = [_adjustRect coordinatesForPoint:4 withScaleFactor:scaleFactor]; 

    CGFloat w1 = sqrt(pow(ptBottomRight.x - ptBottomLeft.x , 2) + pow(ptBottomRight.x - ptBottomLeft.x, 2)); 
    CGFloat w2 = sqrt(pow(ptTopRight.x - ptTopLeft.x , 2) + pow(ptTopRight.x - ptTopLeft.x, 2)); 

    CGFloat h1 = sqrt(pow(ptTopRight.y - ptBottomRight.y , 2) + pow(ptTopRight.y - ptBottomRight.y, 2)); 
    CGFloat h2 = sqrt(pow(ptTopLeft.y - ptBottomLeft.y , 2) + pow(ptTopLeft.y - ptBottomLeft.y, 2)); 

    CGFloat maxWidth = (w1 < w2) ? w1 : w2; 
    CGFloat maxHeight = (h1 < h2) ? h1 : h2; 

    cv::Point2f src[4], dst[4]; 
    src[0].x = ptTopLeft.x; 
    src[0].y = ptTopLeft.y; 
    src[1].x = ptTopRight.x; 
    src[1].y = ptTopRight.y; 
    src[2].x = ptBottomRight.x; 
    src[2].y = ptBottomRight.y; 
    src[3].x = ptBottomLeft.x; 
    src[3].y = ptBottomLeft.y; 

    dst[0].x = 0; 
    dst[0].y = 0; 
    dst[1].x = maxWidth - 1; 
    dst[1].y = 0; 
    dst[2].x = maxWidth - 1; 
    dst[2].y = maxHeight - 1; 
    dst[3].x = 0; 
    dst[3].y = maxHeight - 1; 

    cv::Mat undistorted = cv::Mat(cvSize(maxWidth,maxHeight), CV_8UC1); 
    cv::warpPerspective(original, undistorted, cv::getPerspectiveTransform(src, dst), cvSize(maxWidth, maxHeight)); 

    UIImage *newImage = [self UIImageFromCVMat:undistorted]; 

    undistorted.release(); 
    original.release(); 

    [_sourceImageView setNeedsDisplay]; 
    [_sourceImageView setImage:newImage]; 
    [_sourceImageView setContentMode:UIViewContentModeScaleAspectFit]; 

} 

- (UIImage *)UIImageFromCVMat:(cv::Mat)cvMat 
{ 
    NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize() * cvMat.total()]; 

    CGColorSpaceRef colorSpace; 

    if (cvMat.elemSize() == 1) { 
     colorSpace = CGColorSpaceCreateDeviceGray(); 
    } else { 
     colorSpace = CGColorSpaceCreateDeviceRGB(); 
    } 

    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); 

    CGImageRef imageRef = CGImageCreate(cvMat.cols,          // Width 
             cvMat.rows,          // Height 
             8,            // Bits per component 
             8 * cvMat.elemSize(),       // Bits per pixel 
             cvMat.step[0],         // Bytes per row 
             colorSpace,          // Colorspace 
             kCGImageAlphaNone | kCGBitmapByteOrderDefault, // Bitmap info flags 
             provider,          // CGDataProviderRef 
             NULL,           // Decode 
             false,           // Should interpolate 
             kCGRenderingIntentDefault);      // Intent 

    UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; 
    CGImageRelease(imageRef); 
    CGDataProviderRelease(provider); 
    CGColorSpaceRelease(colorSpace); 

    return image; 
} 

- (cv::Mat)cvMatFromUIImage:(UIImage *)image 
{ 
    CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage); 
    CGFloat cols = image.size.height; 
    CGFloat rows = image.size.width; 

    cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels 

    CGContextRef contextRef = CGBitmapContextCreate(cvMat.data,     // Pointer to backing data 
                cols,      // Width of bitmap 
                rows,      // Height of bitmap 
                8,       // Bits per component 
                cvMat.step[0],    // Bytes per row 
                colorSpace,     // Colorspace 
                kCGImageAlphaNoneSkipLast | 
                kCGBitmapByteOrderDefault); // Bitmap info flags 

    CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage); 
    CGContextRelease(contextRef); 

    return cvMat; 
} 

आशा है कि यह आपको + खुश कोडिंग में मदद करेगी!

+0

आपके कोड में _adjustRect क्या है? और coordinatesForPoint आपका फ़ंक्शन या इसके अंतर्निहित आईओएस एसडीके फ़ंक्शन है? –

+0

क्या आप कृपया उस समारोह को प्रदान कर सकते हैं? –

+0

आपके निर्देशांकफॉरपॉइंट विधि को देखने की सराहना करेंगे। मैंने आईओएस प्रकार के कॉर्ड (ऊपरी बाईं ओर मूल) में प्रवेश करने का प्रयास किया है लेकिन कुछ अजीब परिणाम प्राप्त करें। – VaporwareWolf

1

मुझे लगता है कि getAffineTransform में बिंदु पत्राचार गलत है। बिंदु

चेक निर्देशांक box.points(pts);

द्वारा उत्पादन क्यों नहीं बस p1 p2 p3 p4 का उपयोग परिवर्तन की गणना करने के?

Original Image, with adjusted frame Cropped Frame

के रूप में वादा किया था, यहाँ एक पूरी की नकल है:

+0

मैंने कार्लफिलिप के समाधान का उपयोग किया है, जहां वह कहता है कि "अंक का क्रम प्राप्त करने के लिए संभव है ट्रांसफरफॉर्म() और निम्नलिखित क्रम में निर्दिष्ट होना चाहिए:" (http://stackoverflow.com/a/7878210/1091044) – mmackh

+0

RotatedRect :: अंक() द्वारा पॉइंट आउटपुट का क्रम जो आप मानते हैं उससे भिन्न हो सकता है। यही है, इनपुट बिंदुओं के छोटे विस्थापन के लिए, minAreaRect() :: अंक() अलग-अलग क्रम में अंक प्रदान कर सकता है। – luhb