iOS:Retrieve rectangle shaped image from the background image

前端 未结 2 1926
失恋的感觉
失恋的感觉 2020-12-01 15:37

I am working on an implementation where I have a rectangle shaped image in an big background image. I am trying to programmatically retrieve the rectangle shaped image from

2条回答
  •  庸人自扰
    2020-12-01 16:07

    Here is a full answer using a small wrapper class to separate the c++ from objective-c code.

    I had to raise another question on stackoverflow to deal with my poor c++ knowledge - but I have worked out everything we need to interface c++ cleanly with objective-c code, using the squares.cpp sample code as an example. The aim is to keep the original c++ code as pristine as possible, and to keep the bulk of the work with openCV in pure c++ files for (im)portability.

    I have left my original answer in place as this seems to go beyond an edit. The complete demo project is on github

    CVViewController.h / CVViewController.m

    • pure Objective-C

    • communicates with openCV c++ code via a WRAPPER... it neither knows nor cares that c++ is processing these method calls behind the wrapper.

    CVWrapper.h / CVWrapper.mm

    • objective-C++

    does as little as possible, really only two things...

    • calls to UIImage objC++ categories to convert to and from UIImage <> cv::Mat
    • mediates between CVViewController's obj-C methods and CVSquares c++ (class) function calls

    CVSquares.h / CVSquares.cpp

    • pure C++
    • CVSquares.cpp declares public functions inside a class definition (in this case, one static function).
      This replaces the work of main{} in the original file.
    • We try to keep CVSquares.cpp as close as possible to the C++ original for portability.

    CVViewController.m

    //remove 'magic numbers' from original C++ source so we can manipulate them from obj-C
    #define TOLERANCE 0.01
    #define THRESHOLD 50
    #define LEVELS 9
    
    UIImage* image =
            [CVSquaresWrapper detectedSquaresInImage:self.image
                                           tolerance:TOLERANCE
                                           threshold:THRESHOLD
                                              levels:LEVELS];
    

    CVSquaresWrapper.h

    //  CVSquaresWrapper.h
    
    #import 
    
    @interface CVSquaresWrapper : NSObject
    
    + (UIImage*) detectedSquaresInImage:(UIImage*)image
                              tolerance:(CGFloat)tolerance
                              threshold:(NSInteger)threshold
                                 levels:(NSInteger)levels;
    
    @end
    

    CVSquaresWrapper.mm

    //  CVSquaresWrapper.mm
    //  wrapper that talks to c++ and to obj-c classes
    
    #import "CVSquaresWrapper.h"
    #import "CVSquares.h"
    #import "UIImage+OpenCV.h"
    
    @implementation CVSquaresWrapper
    
    + (UIImage*) detectedSquaresInImage:(UIImage*) image
                              tolerance:(CGFloat)tolerance
                              threshold:(NSInteger)threshold
                                 levels:(NSInteger)levels
    {
        UIImage* result = nil;
    
            //convert from UIImage to cv::Mat openCV image format
            //this is a category on UIImage
        cv::Mat matImage = [image CVMat]; 
    
    
            //call the c++ class static member function
            //we want this function signature to exactly 
            //mirror the form of the calling method 
        matImage = CVSquares::detectedSquaresInImage (matImage, tolerance, threshold, levels);
    
    
            //convert back from cv::Mat openCV image format
            //to UIImage image format (category on UIImage)
        result = [UIImage imageFromCVMat:matImage]; 
    
        return result;
    }
    
    @end
    

    CVSquares.h

    //  CVSquares.h
    
    #ifndef __OpenCVClient__CVSquares__
    #define __OpenCVClient__CVSquares__
    
        //class definition
        //in this example we do not need a class 
        //as we have no instance variables and just one static function. 
        //We could instead just declare the function but this form seems clearer
    
    class CVSquares
    {
    public:
        static cv::Mat detectedSquaresInImage (cv::Mat image, float tol, int threshold, int levels);
    };
    
    #endif /* defined(__OpenCVClient__CVSquares__) */
    

    CVSquares.cpp

    //  CVSquares.cpp
    
    #include "CVSquares.h"
    
    using namespace std;
    using namespace cv;
    
    static int thresh = 50, N = 11;
    static float tolerance = 0.01;
    
        //declarations added so that we can move our 
        //public function to the top of the file
    static void findSquares(  const Mat& image,   vector >& squares );
    static void drawSquares( Mat& image, vector >& squares );
    
        //this public function performs the role of 
        //main{} in the original file (main{} is deleted)
    cv::Mat CVSquares::detectedSquaresInImage (cv::Mat image, float tol, int threshold, int levels)
    {
        vector > squares;
    
        if( image.empty() )
            {
            cout << "Couldn't load " << endl;
            }
    
        tolerance = tol;
        thresh = threshold;
        N = levels;
        findSquares(image, squares);
        drawSquares(image, squares);
    
        return image;
    }
    
    
    // the rest of this file is identical to the original squares.cpp except:
    // main{} is removed
    // this line is removed from drawSquares: 
    // imshow(wndname, image); 
    // (obj-c will do the drawing)
    

    UIImage+OpenCV.h

    The UIImage category is an objC++ file containing the code to convert between UIImage and cv::Mat image formats. This is where you move your two methods -(UIImage *)UIImageFromCVMat:(cv::Mat)cvMat and - (cv::Mat)cvMatWithImage:(UIImage *)image

    //UIImage+OpenCV.h
    
    #import 
    
    @interface UIImage (UIImage_OpenCV)
    
        //cv::Mat to UIImage
    + (UIImage *)imageFromCVMat:(cv::Mat&)cvMat;
    
        //UIImage to cv::Mat
    - (cv::Mat)CVMat;
    
    
    @end        
    

    The method implementations here are unchanged from your code (although we don't pass a UIImage in to convert, instead we refer to self)

提交回复
热议问题