Steven Yen
Steven Yen

Reputation: 31

Segmentation Fault in OpenCV

I recently start to use C++ to do some image processing stuff, and face the segmentation fault issue. Hope someone can help me make clear of what's going on? Thanks!! The issue is that the code attached below works fine, but if the declaration of my "vector roi_corners(4);" is changed into "vector roi_corners;" then use "push_back()" and "clear()" to renew the vector, it will get the segmentation fault. Could anyone help me clarify the cause of this issue? Thank you!!

OpenCV version:4.4.0

MacOS version:10.14.5

Workable Code

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
#include <vector>  

#define PI 3.14159265
#define WINDOW "Image Correction"

using namespace std;
using namespace cv;

vector< Point2f> roi_corners(4); 
vector< Point2f> dst_corners(4); 
Mat img1;
Mat cache;
int roi_id;

void On_mouse(int event, int x, int y, int flags, void*);


int main(int argc, char const *argv[])
{
    
    //import image
    roi_id = 0;
    img1 = imread("Board.jpg");
    if ( img1.empty() )
    {
        cerr << "Please Import an Image!!" << endl;
    }
    int factor = 60;//for pixel adjustment
    cache = img1.clone();//copy for retake points
    imshow(WINDOW, img1);
    
    
    /*Run the point taking procedure*/
    while(true){
     setMouseCallback(WINDOW, On_mouse, 0);
     char c = (char)waitKey( 10 );
     if(c=='n') break;//press 'n' when determine the four point you want 
     if(c=='e') {roi_id=0; img1 = cache.clone();} //press 'e' to retake the foru point

    }
    

    /*For adjustment point estimation*/
    dst_corners[0].x = roi_corners[0].x;
    dst_corners[0].y = roi_corners[0].y;
    dst_corners[1].x = roi_corners[0].x+factor*1;
    dst_corners[1].y = roi_corners[0].y;
    dst_corners[2].x = roi_corners[0].x+factor*1;
    dst_corners[2].y = roi_corners[0].y+factor*1;
    dst_corners[3].x = roi_corners[0].x;
    dst_corners[3].y = roi_corners[0].y+factor*1;

    Mat M = getPerspectiveTransform(roi_corners, dst_corners);
    Mat warped_image;
    

    /*Print the corrected picture*/
    Size sz = cache.size();
    warpPerspective(cache, warped_image, M, Size(sz.width, sz.height)); // do perspective transformation
    imshow("Corrected Image", warped_image);
    waitKey(0);
    cout<<"complete"<<endl;
    return 0;
}


void On_mouse(int event, int x, int y, int flags, void*)
{   imshow(WINDOW, img1);
    if(roi_id<4){
        if (event == EVENT_LBUTTONDOWN){
            roi_corners[roi_id].x=x; 
            roi_corners[roi_id].y=y;
            cout<<"The Point You Take is: "<<x<<' '<<y<<endl;
            roi_id++;
            circle(img1, Point(x,y), 2, Scalar(0, 0, 255), LINE_8 ,0);
            imshow(WINDOW, img1);
        }

    }

}

If I modify the code like this, it will show seg fault

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
#include <vector>  

#define PI 3.14159265
#define WINDOW "Image Correction"

using namespace std;
using namespace cv;

vector< Point2f> roi_corners; 
vector< Point2f> dst_corners; 
Mat img1;
Mat cache;


void On_mouse(int event, int x, int y, int flags, void*);


int main(int argc, char const *argv[])
{
    
    //import image
    roi_id = 0;
    img1 = imread("Board.jpg");
    if ( img1.empty() )
    {
        cerr << "Please Import an Image!!" << endl;
    }
    int factor = 60;//for pixel adjustment
    cache = img1.clone();//copy for retake points
    imshow(WINDOW, img1);
    
    
    /*Run the point taking procedure*/
    while(true){
     setMouseCallback(WINDOW, On_mouse, 0);
     char c = (char)waitKey( 10 );
     if(c=='n') break;//press 'n' when determine the four point you want 
     if(c=='e') {roi_corner.clear(); img1 = cache.clone();} //press 'e' to retake the foru point

    }
    

    /*For adjustment point estimation*/
    dst_corners[0].x = roi_corners[0].x;
    dst_corners[0].y = roi_corners[0].y;
    dst_corners[1].x = roi_corners[0].x+factor*1;
    dst_corners[1].y = roi_corners[0].y;
    dst_corners[2].x = roi_corners[0].x+factor*1;
    dst_corners[2].y = roi_corners[0].y+factor*1;
    dst_corners[3].x = roi_corners[0].x;
    dst_corners[3].y = roi_corners[0].y+factor*1;

    Mat M = getPerspectiveTransform(roi_corners, dst_corners);
    Mat warped_image;
    

    /*Print the corrected picture*/
    Size sz = cache.size();
    warpPerspective(cache, warped_image, M, Size(sz.width, sz.height)); // do perspective transformation
    imshow("Corrected Image", warped_image);
    waitKey(0);
    cout<<"complete"<<endl;
    return 0;
}


void On_mouse(int event, int x, int y, int flags, void*)
{   imshow(WINDOW, img1);
    if(roi_corners.size()<4){
        if (event == EVENT_LBUTTONDOWN){
            roi_corners.push_back(Point2f(x,y)); 
            cout<<"The Point You Take is: "<<x<<' '<<y<<endl;
            circle(img1, Point(x,y), 2, Scalar(0, 0, 255), LINE_8 ,0);
            imshow(WINDOW, img1);
        }

    }

}

Upvotes: 0

Views: 2455

Answers (1)

stateMachine
stateMachine

Reputation: 5805

A couple of things with your code. You declare a vector of 4 elements but do not initialize it. Depending on your platform and data type, you could see undesired behavior. Try to declare and initialize your vector on the same line:

std::vector<cv::Point2f> roi_corners( 4, cv::Point2f(0.0, 0.0) );

Of course, if you declare the vector with an initial capacity (size) and initial values, you can index each element using std::vector<>::operator[]:

roi_corners[0] = cv::Point2f( 1.0, 2.0 );
roi_corners[1] = cv::Point2f( 3.0, 4.0 );
roi_corners[2] = cv::Point2f( 5.0, 6.0 );
roi_corners[3] = cv::Point2f( 7.0, 8.0 );

By declaring the vector with an initial size you have allocated memory that will be used to store and load the individual elements of your vector. Now, suppose you do not declare the vector with an initial size and use push_back to add elements as you go:

//vector declaration with no initial size:
std::vector<cv::Point2f> roi_corners;

//store a new element into the vector:
roi_corners.push_back( cv::Point2f(1.0, 2.0) );

All cool, your vector has stored a new element and shows capacity for one item only. However, you still do this:

roi_corners[0] = cv::Point2f( 1.0, 2.0 ); // data overwrite in position 0
roi_corners[1] = cv::Point2f( 3.0, 4.0 ); // you haven't allocated memory for this yet!

Result: seg fault

Corollary: If you have a pre-defined vector of size N, you can index elements from 0 to N via std::vector<>::operator[], because memory has been allocated to hold all N elements. If you try to address elements outside of this range you will be greeted with a seg fault.

Upvotes: 2

Related Questions