Reputation: 31
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
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