c++opencvmat

segmentation fault while reading value of cornerharris destination Mat object


I am trying to find corner features in an image using cornerharris function. When I try to check which coordinates have a value greater than 1% of maximum value of cornerharris output Mat object, I change the pixel value to red. My logic seems to work fine in python, but in CPP, I am getting segmentation fault at a specific coordinate

I tried following code and am getting segmentation fault in line if(dst.at(i,j) > corners_perc/100*maxVal)

#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <stdio.h>
#include <iostream>
using namespace cv;
using namespace std;
string type2str(int type) {
  string r;

  uchar depth = type & CV_MAT_DEPTH_MASK;
  uchar chans = 1 + (type >> CV_CN_SHIFT);

  switch ( depth ) {
    case CV_8U:  r = "8U"; break;
    case CV_8S:  r = "8S"; break;
    case CV_16U: r = "16U"; break;
    case CV_16S: r = "16S"; break;
    case CV_32S: r = "32S"; break;
    case CV_32F: r = "32F"; break;
    case CV_64F: r = "64F"; break;
    default:     r = "User"; break;
  }

  r += "C";
  r += (chans+'0');

  return r;
}

Mat getcorners(Mat image){
    Mat dst, image_gray;
    Mat imcopy = image.clone();     
    cvtColor(image, image_gray, COLOR_BGR2GRAY);
    cornerHarris(image_gray, dst, 3, 3, 0.01);
    //Create image copy of same size of image
    Point minLoc, maxLoc;
    double minVal, maxVal;
    minMaxLoc(dst, &minVal, &maxVal, &minLoc, &maxLoc);
    std::cout<<"Max value in dst mat ="<<maxVal<<std::endl;
    int corners_perc = 1;
    
    
    for(int i = 0; i<image.rows; i++){
        for(int j = 0; j<image.cols; j++){
            
            if(dst.at<double>(i,j) > corners_perc/100*maxVal){
            //if(i % 15 == 13){
                imcopy.at<Vec3b>(i,j)[0] = 0;
                imcopy.at<Vec3b>(i,j)[1] = 0;
                imcopy.at<Vec3b>(i,j)[2] = 255;
                //std::cout<<"DST value = "<<dst.at<double>(i,j)<<std::endl;
                if(i>290){
                    std::cout<<"values = "<<dst.at<double>(i,j)<<", i = "<<i<<", j = "<<j<<"\n";
                }
            }
        }
    }
    
    
    
    std::cout<<dst.at<double>(1,10)<<std::endl;
    if(dst.at<double>(1,10) > corners_perc/100*maxVal){
        std::cout<<"values = "<<imcopy.at<double>(1,10)<<"\n";
    }
    std::cout<<"Image values = "<<imcopy.at<Vec3b>(200,450)<<"\n";
    std::cout<<"Image cols = "<<imcopy.cols<<"x"<<imcopy.rows<<"\n"<<"Color: "<<imcopy.at<Vec3b>(imcopy.rows-1, imcopy.cols-1)<<"\n";
    std::cout<<"Dst vals = "<<type2str(dst.type())<<"\n"<<type2str(imcopy.type())<<"\n"<<dst.at<int>(449,460)<<"\n";
    return imcopy;
}

int main(int argc, char** argv)
{
    if (argc != 2) {
        printf("usage: DisplayImage.out <Image_Path>\n");
        return -1;
    }
    Mat image, image_gray, image_corners;
    image = imread(argv[1], 1);
    
    if (!image.data) {printf("No image data \n"); return -1;}
    std::cout<<"Image size = "<<image.size()<<", test = "<<image.size[0]<<"X"<<image.size[1]<<std::endl;

    image_corners = getcorners(image);

    namedWindow("Display Image", WINDOW_AUTOSIZE);
    imshow("Display Image", image_corners);
    waitKey(0);

    return 0;
}

Solution

  • According to the documentation of cornerHarris:

    dst - Image to store the Harris detector responses. It has the type CV_32FC1 and the same size as src .

    The type of matrix dst is CV_32FC1.
    We have to use dst.at<float>(i,j) instead of dst.at<double>(i,j).

    Trying to read (i, j) as double may result segmentation fault because double is 8 bytes per element and float is 4 (we are trying to read data from memory address outside the bounds of dst).
    When interpreting float elements as double, we are also reading invalid values.


    There is also place were dst.at<int>(449,460) should be replaced with dst.at<float>(449,460).
    We may also replace imcopy.at<double>(1,10) with imcopy.at<Vec3b>(1,10).


    Updated code sample:

    #include <opencv2/opencv.hpp>
    #include <opencv2/highgui.hpp>
    #include <opencv2/imgproc.hpp>
    #include <stdio.h>
    #include <iostream>
    #include <string>
    
    using namespace cv;
    using namespace std;
    string type2str(int type) {
      string r;
    
      uchar depth = type & CV_MAT_DEPTH_MASK;
      uchar chans = (uchar)(1 + (type >> CV_CN_SHIFT));
    
      switch ( depth ) {
        case CV_8U:  r = "8U"; break;
        case CV_8S:  r = "8S"; break;
        case CV_16U: r = "16U"; break;
        case CV_16S: r = "16S"; break;
        case CV_32S: r = "32S"; break;
        case CV_32F: r = "32F"; break;
        case CV_64F: r = "64F"; break;
        default:     r = "User"; break;
      }
    
      r += "C";
      r += (chans+'0');
    
      return r;
    }
    
    Mat getcorners(Mat image){
        Mat dst, image_gray;
        Mat imcopy = image.clone();     
        cvtColor(image, image_gray, COLOR_BGR2GRAY);
        cornerHarris(image_gray, dst, 3, 3, 0.01);
        //Create image copy of same size of image
        Point minLoc, maxLoc;
        double minVal, maxVal;
        minMaxLoc(dst, &minVal, &maxVal, &minLoc, &maxLoc);
        std::cout<<"Max value in dst mat ="<<maxVal<<std::endl;
        int corners_perc = 1;
        
        
        for(int i = 0; i<image.rows; i++){
            for(int j = 0; j<image.cols; j++){
                
                //if(dst.at<double>(i,j) > corners_perc/100*maxVal){
                if(dst.at<float>(i,j) > corners_perc/100*maxVal){
                //if(i % 15 == 13){
                    imcopy.at<Vec3b>(i,j)[0] = 0;
                    imcopy.at<Vec3b>(i,j)[1] = 0;
                    imcopy.at<Vec3b>(i,j)[2] = 255;
                    //std::cout<<"DST value = "<<dst.at<double>(i,j)<<std::endl;
                    if(i>290){
                        //std::cout<<"values = "<<dst.at<double>(i,j)<<", i = "<<i<<", j = "<<j<<"\n";
                        std::cout<<"values = "<<dst.at<float>(i,j)<<", i = "<<i<<", j = "<<j<<"\n";
                    }
                }
            }
        }
        
        
        
        //std::cout<<dst.at<double>(1,10)<<std::endl;
        std::cout<<dst.at<float>(1,10)<<std::endl;
        //if(dst.at<double>(1,10) > corners_perc/100*maxVal){
        if(dst.at<float>(1,10) > corners_perc/100*maxVal){
            //std::cout<<"values = "<<imcopy.at<double>(1,10)<<"\n";
            std::cout<<"values = "<<imcopy.at<Vec3b>(1,10)<<"\n";
        }
        std::cout<<"Image values = "<<imcopy.at<Vec3b>(200,450)<<"\n";
        std::cout<<"Image cols = "<<imcopy.cols<<"x"<<imcopy.rows<<"\n"<<"Color: "<<imcopy.at<Vec3b>(imcopy.rows-1, imcopy.cols-1)<<"\n";
        //std::cout<<"Dst vals = "<<type2str(dst.type())<<"\n"<<type2str(imcopy.type())<<"\n"<<dst.at<int>(449,460)<<"\n";
        std::cout<<"Dst vals = "<<type2str(dst.type())<<"\n"<<type2str(imcopy.type())<<"\n"<<dst.at<float>(449,460)<<"\n";
        return imcopy;
    }
    
    int main(int argc, char** argv)
    {
        if (argc != 2) {
            printf("usage: DisplayImage.out <Image_Path>\n");
            return -1;
        }
        Mat image, image_gray, image_corners;
        image = imread(argv[1], 1);
        
        if (!image.data) {printf("No image data \n"); return -1;}
        std::cout<<"Image size = "<<image.size()<<", test = "<<image.size[0]<<"X"<<image.size[1]<<std::endl;
    
        image_corners = getcorners(image);
    
        namedWindow("Display Image", WINDOW_AUTOSIZE);
        imshow("Display Image", image_corners);
        waitKey(0);
    
        return 0;
    }