OpenCV 和 ROS:cvMAT 中的空指针错误

Posted

技术标签:

【中文标题】OpenCV 和 ROS:cvMAT 中的空指针错误【英文标题】:OpenCV and ROS: NULL Pointer error in cvMAT 【发布时间】:2012-08-17 09:17:41 【问题描述】:

我正在使用以下方法来检测两个彩色对象的位置、方向。 除非相机无法对这两个物体(黄色和蓝色)中的任何一个进行精细处理,或者当我将手放在相机前时,否则一切正常。它抛出以下错误:

OpenCV 错误:cvGetMat 中的空指针(传递了空数组指针),文件 /tmp/buildd/libopencv-2.3.1+svn6514+branch23/modules/core/src/array.cpp,第 2382 行 在抛出 'cv::Exception' 的实例后调用终止 what(): /tmp/buildd/libopencv-2.3.1+svn6514+branch23/modules/core/src/array.cpp:2382: 错误: (-27) 函数 cvGetMat 传递了 NULL 数组指针

如果有人能帮我解决这个错误,我将不胜感激。

谢谢

#include <ros/ros.h>
#include <opencv/cv.h>
#include <opencv/highgui.h>



#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>

#include <math.h>

#include <geometry_msgs/Twist.h>

#define MAX_CONTOUR_LEVELS 5 //This will be used when displaying contours
#define PI 3.14159265
using namespace cv;
using namespace std;
// Class Definition
class color_control 
public:
    void mainLoop1();
    void mainLoop2();
    double R_X, R_Y; /* red center of gravity x,y in the frame normalized from -1.0 to 1.0 */
    int C_C;
    double setSpeed( double, double );
    void do_some_magic( IplImage* , int , int , int , int );

    color_control()
    
      // node creation in root-namespace 
      ros::NodeHandle m_nodeHandle("/");

      m_commandPublisher = m_nodeHandle.advertise<geometry_msgs::Twist> ("cmd_vel", 20);
    

    ~color_control()
    
      cvDestroyWindow("result");
    



protected:

    ros::NodeHandle m_nodeHandle;

    // Publisher und Membervariable für die Fahrbefehle
    ros::Publisher m_commandPublisher;
    geometry_msgs::Twist m_roombaCommand;

;

int abort_error_handler(int status, char const* func_name, char const* err_msg, char const* file_name, int line, void*) 
cout << "ERROR: in " << func_name << "(" << file_name << ":" << line << ") Message: " << err_msg << endl;
abort();


IplImage* GetThresholdedImage1(IplImage* img)

    IplImage* imgHSV = cvCreateImage(cvGetSize(img), 8, 3);
    cvCvtColor(img, imgHSV, CV_BGR2HSV);
    IplImage* imgThreshed1=cvCreateImage(cvGetSize(img),8,1);
    //cvInRangeS(imgHSV, cvScalar(20, 100, 100), cvScalar(30, 255, 255), imgYellow);
    cvInRangeS(imgHSV, cvScalar(22, 100, 100), cvScalar(32, 255, 255), imgThreshed1);
    cvReleaseImage(&imgHSV);
    //cvAdd(imgYellow,imgGreen,imgThreshed);
    //if (imgThreshed1 != NULL)
            return imgThreshed1;
    //cvShowImage( "result", imgThreshed1 );


IplImage* GetThresholdedImage2(IplImage* img)

    IplImage* imgHSV = cvCreateImage(cvGetSize(img), 8, 3);
    cvCvtColor(img, imgHSV, CV_BGR2HSV);
    IplImage* imgThreshed2=cvCreateImage(cvGetSize(img),8,1);
    //cvInRangeS(imgHSV, cvScalar(20, 100, 100), cvScalar(30, 255, 255), imgYellow);
    cvInRangeS(imgHSV, cvScalar(100,100,100^3),cvScalar(120,255,255^3), imgThreshed2);
    cvReleaseImage(&imgHSV);
    //cvAdd(imgYellow,imgGreen,imgThreshed);
    //if (imgThreshed2 == NULL)
            return imgThreshed2;




// find the largest contour (by area) from a sequence of contours and return a
// pointer to that item in the sequence

CvSeq* findLargestContour(CvSeq* contours)

  CvSeq* current_contour = contours;
  double largestArea = 0;
  CvSeq* largest_contour = NULL;

  // check we at least have some contours

  if (contours == NULL)return NULL;

  // for each contour compare it to current largest area on
  // record and remember the contour with the largest area
  // (note the use of fabs() for the cvContourArea() function)

  while (current_contour != NULL)

      double area = fabs(cvContourArea(current_contour));

      if(area > largestArea)
          largestArea = area;
          largest_contour = current_contour;
      

      current_contour = current_contour->h_next;
  

  // return pointer to largest

  return largest_contour;



// normalize center of color to propulsion command
double color_control::setSpeed( double center, double width )


  double normedCenter = (12.0*center/width) - 6.0;
    //ROS_INFO("normed center: %f", normedCenter);
  double retval = 0.0;

  if ( fabs( normedCenter ) > 1.0 )
      retval = (trunc( normedCenter )/10.0 );
  
  return retval;



//
// comments R 4 mollycoddles, guess what i'm doing!
// 
// Please help me ! I need someone writing comments. Thanx
//
void color_control::do_some_magic( IplImage* img, int red, int green, int blue, int tolerance) 

    int radius = 20 ;

    int width = img->width;
    int height = img->height;
    int channels = img->nChannels;
    int step = img->widthStep;

    unsigned char redP = 0, greenP = 0, blueP = 0;
    double S_x = 0.0 ;
    double S_y = 0.0 ;
    int red_difference, green_difference, blue_difference = 255;

    C_C = 0 ;

    for(int y=0;y<height;y++) 
        for(int x=0;x<width;x++) 
          blueP = img->imageData[y*step+x*channels+0] ;
          greenP = img->imageData[y*step+x*channels+1] ;
          redP = img->imageData[y*step+x*channels+2] ;

      red_difference = fabs(red - (int)redP);
      green_difference = fabs(green - (int)greenP);
      blue_difference = fabs(blue - (int)blueP);

      if ( (red_difference + green_difference + blue_difference) < tolerance ) 
         C_C++ ;
         S_x += x;
         S_y += y;

         //ROS_INFO( "Difference to target color: %i", (red_difference + green_difference + blue_difference) );
        

        
     

    S_x = S_x / (C_C) ;
    S_y = S_y / (C_C) ;

    R_X = setSpeed( S_x, img->width );
    R_Y = setSpeed( S_y, img->height );

    // for monitoring, draw a circle and display the respective picture
    CvPoint center;
    center.x = S_x;
    center.y = S_y;
    cvCircle( img, center, radius, CV_RGB( 255 - red, 255 - green, 255 - blue ) , 3, 8, 0 );
    cvShowImage( "result", img );


// Main Loop
void color_control::mainLoop1() 
    // determines the number of frames per second
    ros::Rate loop_rate(20);
     int radius ;
    CvCapture* capture = 0;
    //IplImage *frame, *frame_copy = 0;
    IplImage* imgScribble=NULL;
    // open the camera
    capture = cvCaptureFromCAM( 0 );
    cvSetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT, 640);
    cvSetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH, 480);
    //capture = cvCaptureFromCAM( 1 );
    //cvRedirectError(abort_error_handler);



    // loop stops, e.g. if the node recieves a kill signal
    while (m_nodeHandle.ok())
    
        IplImage* frame=0;
                    frame=cvQueryFrame(capture);

                    if(!frame)
                                break;
//                  if(imgScribble == NULL)
//                  
//                      imgScribble=cvCreateImage(cvGetSize(frame),8,1);
//                  


                    IplImage* imgYellowThresh = GetThresholdedImage1(frame);
                    IplImage* imgGreenThresh = GetThresholdedImage2(frame);



            //CvMemStorage and CvSeq are structures used for dynamic data collection. CvMemStorage contains pointers to the actual
            //allocated memory, but CvSeq is used to access this data. Here, it will hold the list of image contours.
            CvMemStorage *storage = cvCreateMemStorage(0);
            CvSeq *contours = 0;

            //Once we have a binary image, we can look for contours in it. cvFindContours will scan through the image and store connected contours in "sorage".
            //"contours" will point to the first contour detected. CV_RETR_TREE means that the function will create a contour hierarchy. Each contour will contain
            //a pointer to contours that are contained inside it (holes). CV_CHAIN_APPROX_NONE means that all the contours points will be stored. Finally, an offset
            //value can be specified, but we set it to (0,0).
            cvFindContours(imgYellowThresh, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));

            //This function will display contours on top of an image. We can specify different colours depending on whether the contour in a hole or not.
            CvSeq* largest_contour = NULL;
            largest_contour = findLargestContour(contours);

                //cvDrawContours(imgYellowThresh, largest_contour, CV_RGB(255,255,255), CV_RGB(0,255,0), MAX_CONTOUR_LEVELS, 3, CV_AA, cvPoint(0,0));
if(largest_contour!=NULL) 
                cvDrawContours(imgYellowThresh, largest_contour, CV_RGB(255,255,255), CV_RGB(0,255,0), 0, 2, 8, cvPoint(0,0));



            static int posX_Yellow=0;
            static int posY_Yellow=0;


            //int lastX=posX;
            //int lastY=posY;

           CvMoments moments1,cenmoments1;
           double M00, M01, M10;

           cvMoments(largest_contour,&moments1);
           M00 = cvGetSpatialMoment(&moments1,0,0);
           M10 = cvGetSpatialMoment(&moments1,1,0);
           M01 = cvGetSpatialMoment(&moments1,0,1);
           posX_Yellow = (int)(M10/M00);
           posY_Yellow = (int)(M01/M00);

          double theta = 0.5 * atan(
                    (2 * cvGetCentralMoment(&moments1, 1, 1)) /
                    (cvGetCentralMoment(&moments1, 2, 0) -  cvGetCentralMoment(&moments1, 0, 2)));
                theta = (theta / PI) * 180;

                // fit an ellipse (and draw it)

                if (largest_contour->total >= 6) // can only do an ellipse fit
                                                 // if we have > 6 points
                
                    CvBox2D box = cvFitEllipse2(largest_contour);
                    if ((box.size.width < imgYellowThresh->width) &&  (box.size.height < imgYellowThresh->height))
                    
                        // get the angle of the ellipse correct (taking into account MS Windows
                        // seems to draw ellipses differently

                        box.angle =  270 - box.angle;
                        #ifndef WIN32
                            if( imgYellowThresh->origin ) 
                                box.angle = - box.angle;
                            
                        #endif
                        cvEllipseBox(imgYellowThresh, box, CV_RGB(255, 255 ,255), 3, 8, 0 );
                    
                
              CvFont font;
              cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, 1, 1 , 0, 2, 8 );

            #ifdef WIN32
                int height_offset = 20;
            #else
                int height_offset = 5;
            #endif
                char outputString[255];

                sprintf(outputString, "angle: %.10f", theta);
                cvPutText(imgYellowThresh, outputString,
                    cvPoint(10,imgYellowThresh->height - height_offset), &font, CV_RGB(255, 255,255));






                              CvMemStorage *storageG = cvCreateMemStorage(0);

    CvSeq *contoursG = 0;

        //Once we have a binary image, we can look for contours in it. cvFindContours will scan through the image and store connected contours in "sorage".
        //"contours" will point to the first contour detected. CV_RETR_TREE means that the function will create a contour hierarchy. Each contour will contain
        //a pointer to contours that are contained inside it (holes). CV_CHAIN_APPROX_NONE means that all the contours points will be stored. Finally, an offset
        //value can be specified, but we set it to (0,0).
        cvFindContours(imgGreenThresh, storageG, &contoursG, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));

        //This function will display contours on top of an image. We can specify different colours depending on whether the contour in a hole or not.
        CvSeq* largest_contourG = NULL;
        largest_contourG = findLargestContour(contoursG);

if(largest_contourG!=NULL) 
            //cvDrawContours(imgYellowThresh, largest_contour, CV_RGB(255,255,255), CV_RGB(0,255,0), MAX_CONTOUR_LEVELS, 3, CV_AA, cvPoint(0,0));

            cvDrawContours(imgGreenThresh, largest_contourG, CV_RGB(255,255,255), CV_RGB(0,255,0), 0, 2, 8, cvPoint(0,0));

        //cvShowImage( "result2", imgGreenThresh );
    CvMoments moments2;
                               double M00g, M01g, M10g;

                               cvMoments(largest_contourG,&moments2);
                               M00g = cvGetSpatialMoment(&moments2,0,0);
                               M10g = cvGetSpatialMoment(&moments2,1,0);
                               M01g = cvGetSpatialMoment(&moments2,0,1);
                               static int posX_Green=0;
                                        static int posY_Green=0;
                                posX_Green = (int)(M10g/M00g);
                               posY_Green = (int)(M01g/M00g);

                               //printf("%d\n",M00g);
   //ROS_INFO("position (%d,%d)\n",posX_Yellow,posY_Yellow);
   //ROS_INFO("position (%d,%d)\n",posX_Green,posY_Green);

            //do_some_magic( frame , 0, 0, 0, 100);




//          if(lastX>0 && lastY>0 && posX>0 && posY>0)
//                  
//                      cvLine(imgScribble,cvPoint(posX,posY),cvPoint(lastX,lastY),cvScalar(0,255,255), 5);
//                  
//          cvAdd(frame,imgScribble,frame);
            cv::Point centerY(posX_Yellow,posY_Yellow);
            //centerY.x = posX_Yellow;
            //centerY.y = posY_Yellow;
            //radius = sqrt(areaY/3.14);
            cvCircle( frame, centerY, 10, CV_RGB( 255, 255, 255) , 3, 8, 0 );

            cv::Point centerG(posX_Green,posY_Green);
            //centerG.x = posX_Green;
            //centerG.y = posY_Green;
            cv::Point diff = centerY - centerG;
            //radius = sqrt(areaG/3.14);
            cvCircle( frame, centerG, 10, CV_RGB( 255, 255, 255) , 3, 8, 0 );
            //float angle = atan2(centerY,centerX);
            int slope = ((diff.y)/(diff.x));
            int len = cv::sqrt(diff.x*diff.x + diff.y*diff.y);
            double newdist = (len / 2000000);
            cvLine(frame, centerY, centerG, CV_RGB( 255, 255, 255), 5,8,0);
            //cvCircle( frame, diff, 10, CV_RGB( 255, 255, 255) , 3, 8, 0 );
            //ROS_INFO("angle :  %d\n",theta);
            //ROS_INFO("len: %d    slope: %d\n",len,slope);
            //printf("len: %f\n", slope);
            cvShowImage( "result", frame );
            cvShowImage( "result1", imgYellowThresh );
            cvShowImage( "result2", imgGreenThresh );

            if( cvWaitKey( 10 ) >= 0 )
                                    break;

         //ROS_INFO( "C_C: %d", C_C );



         // set driving direction and velocity
//       if (len > 50 || slope > 0)
//        
//          m_roombaCommand.linear.x = 0.1;
//          m_roombaCommand.angular.z = 0.0;
//         else 
//          m_roombaCommand.linear.x = 0.0;
//          m_roombaCommand.angular.z = 0.1;
//        


         //
//      ROS_INFO("Forward: %f - Turning: %f", m_roombaCommand.linear.x, m_roombaCommand.angular.z);
//
//      // send the driving command to the roomba
        //m_commandPublisher.publish(m_roombaCommand);

    // spinOnce is doing the loop exactly once
    ros::spinOnce();
            //cvReleaseCapture( &capture );

    // sleep stops the process for approx ~50ms, to keep the timing for the looprate
    loop_rate.sleep();


    

    //cvReleaseImage( &frame_copy );





int main(int argc, char** argv) 
    //sleep(10);
    // Initialize
    ros::init(argc, argv, "color_control");

    ros::NodeHandle n;
    color_control f_g;
    f_g.mainLoop1();
    //color_control g_g;
    //g_g.mainLoop2();
    ros::spin();
    //cvRedirectError(abort_error_handler);
    return 0;




        //cvNamedWindow("Video");
        //cvNamedWindow("thresh");
    

【问题讨论】:

代码太多,无法阅读和理解。你能试着做一个有这个错误的更短的例子吗?另请阅读sscce.org 当周围没有彩色对象时,findlargestContour 函数返回空值。因此错误。我怎样才能避免这种情况,以便程序仍然运行而不会出现此错误? 为了让 OP 明白:这个问题看起来不错,但这里发布的 looooong 代码反映了对社区的低评价。好问题很容易阅读。对于这个,必须有人阅读 10 分钟,这太多了 附注:您似乎从某个地方获取了此代码,并且没有足够的编程知识来使用它。我建议开始学习 C++,然后转向更复杂的东西,例如计算机视觉 【参考方案1】:

当您调用findlargestContour 时,您会在调用cvDrawContours 时检查NULL 的返回值。但是,您也可以在此之后使用返回的值,而不检查 NULL

简单的解决方案是在使用返回值之前为NULL 添加更多检查。

【讨论】:

以上是关于OpenCV 和 ROS:cvMAT 中的空指针错误的主要内容,如果未能解决你的问题,请参考以下文章

opencv编程中错误提示:不存在从mat到cvmat适当的转换函数。

OpenCV 中 IplImage,CvMat,Mat中的type是怎么回事

懂opencv中的cvmat的请进啊

OpenCV:Mat,IplImage,CvMat类型转换

opencv中Mat与IplImage,CVMat类型之间转换

人脸检测 OpenCV + Qt + cvMat