如何修改cv :: Mat类(16UC1)中某个位置的值

时间:2015-12-10 20:43:36

标签: c++ opencv

为了更好地理解计算机视觉,我试图从头开始编写一个精确的边缘检测算法" (不只是使用cv lib中的canny函数)。为此,我需要对图像应用滞后阈值。但是,当我尝试修改矩阵中的元素时,出现错误。这是我的功能:

cv::Mat hysteresisThresh(cv::Mat originalImage, int lowThresh, int highThresh){
    //initialize a 2d vector to keep track of whethr or not the pixel is "in" the image
    std::vector<std::vector<bool>>isIn(
                    originalImage.rows,
                    std::vector<bool>(originalImage.cols, true));
    //loop through every row and col in the original image
    //create a varaible to hold the element being checked
    unsigned short curElementValue;
    for(int curRow = 0; curRow<originalImage.rows; curRow++){
            for(int curCol = 0; curCol<originalImage.cols; curCol++){
                    curElementValue = originalImage.at<unsigned short>(curRow, curCol);
                    if(curElementValue > highThresh){
                            isIn.at(curRow).at(curCol) = true;
                            //do nothing to the returnImage since the correct value is already stored       
                    }
                    else if(curElementValue < highThresh && curElementValue > lowThresh){
                            /* i need to check that this pixel is adjacent to another edge pixel
                            thus, I have 8  possabilities. Think of them as:
                            123
                            4*5
                            678
                            with the * being the current pixel. However, I can cut the possabilities
                            in half since pixels 5-8 (inclusive) have not been checked yet and will be
                            checked in the future. So, I will only check pixels 1-4
                            */
                            //TODO there may be a more efficient way to check these values. Find out        
                            //The first stage of this if is the be sure that you are checking values in the array that actually exist

                            if((curRow!=0 && curCol!=0 && curRow!=originalImage.rows-1 && curCol!=originalImage.cols-1)&&
                            (isIn[curRow][curCol-1] || isIn[curRow-1][curCol-1]|| isIn[curRow-1][curCol] || isIn[curRow-1][curCol+1])){
                            isIn.at(curRow).at(curCol) = true;
                            //do nothing to the returnImage since the correct value is already stored
                            }
                            else{
                            //none of the adjacent pixels are in, so it is not an edge
                            isIn.at(curRow).at(curCol) = false;
                            originalImage.at<unsigned short>(curRow, curCol) = 0; //same as above
                            }

                    }
                    else{

                            isIn.at(curRow).at(curCol) = false;
                            originalImage.at<unsigned short>(curRow, curCol) = 0; //same as above

                    }
            }
    }
    return originalImage;

}

运行程序时的输出是经典的seg错误:

Segmentation fault (core dumped)

我在gdb中进行了一些探索,发现故障发生在该行:

originalImage.at<unsigned short>(curRow, curCol) = 0;

我做错了什么?谢谢!

编辑:评论中我被要求提供该功能的上下文。这是函数调用的代码。我在深度图上调用所有操作(是的,我知道canny设计用于彩色地图但是在研究之后我认为相同的一般原则将适用于在深度图中找到边缘)。无论如何,这是代码:

    void displayDepthEdges(cv::VideoCapture* capture){

    //initialize the matricies for holding images
    cv::Mat depthImage;
    cv::Mat edgeImage;
    cv::Mat bgrImage;
    //initialize variables for sobel operations
    cv::Mat yGradient;
    cv::Mat xGradient;
    //double theta;
    //initialize variable for hysteresis thresh operation
    cv::Mat threshedImage;
    int cannyLowThresh = 0;
    int cannyHighThresh = 500;
    //initialize variables for erosion and dilation based noise cancelation.
    //CURRENTLY NOT IN USE
    //int erosionFactor = 0;
    //int dilationFactor = 0;
    //initialize the windows and trackbars used to control everything
    //cv::namedWindow("EroDilMenu", CV_WINDOW_NORMAL);
    cv::namedWindow("CannyMenu", CV_WINDOW_NORMAL);
    cvCreateTrackbar("Low Thresh", "CannyMenu",&cannyLowThresh, 500);
    cvCreateTrackbar("High Thresh", "CannyMenu",&cannyHighThresh, 500);
    //cvCreateTrackbar("Dil Fac", "EroDilMenu",&dilationFactor, 25);
    //cvCreateTrackbar("Ero Fac", "EroDilMenu", &erosionFactor, 25); 
    cv::namedWindow("Edges", CV_WINDOW_NORMAL);
    for(;;){
            if(!capture->grab()){
                    std::cerr << "Error: Could not grab an image\n";
            }
            else{
                    //initialization here will stop totalGradient from carrying values over (hopefully)
                    cv::Mat totalGradient;
                    capture->retrieve(depthImage, CV_CAP_OPENNI_DEPTH_MAP);

                    //blur the image so that only major edges are detected
                    GaussianBlur(depthImage, depthImage, cv::Size(3,3), 1, 0, cv::BORDER_DEFAULT);
                    //apply the sobel operator in the x and y directions, then average to approximate gradient
                    //arguments are(input, output, dataType, x order derivative, y order derivative
                    //matrix size, scale, delta)
                    Sobel(depthImage, xGradient, CV_16U, 1, 0, 3, 1, 0, cv::BORDER_DEFAULT);
                    convertScaleAbs(xGradient, xGradient);
                    Sobel(depthImage, yGradient, CV_16U, 1, 0, 3, 1, 0, cv::BORDER_DEFAULT);
                    convertScaleAbs(yGradient, yGradient);
                    addWeighted(yGradient, 0.5, xGradient, 0.5, 0.0, totalGradient);
                    //it is not clear that noise canceling does anything here... 
                    //it seemed to only blur or sharpen edges in testing
                    //totalGradient = noiseCancel(totalGradient ,erosionFactor, dilationFactor);



                    //TODO impliment direction based edge priority
                    //theta = atan2(xGradient, yGradient);//this is returned in radians
                    //times 10 since the threshes are in mm and trackbars are in cm
                    totalGradient = hysteresisThresh(totalGradient,cannyLowThresh*10, cannyHighThresh*10);
                    imshow("Edges", totalGradient);
                    if(cv::waitKey(30) == 27){break;}
            }
    }

}

1 个答案:

答案 0 :(得分:0)

你的错误在于周围的代码,而不是算法本身。根据{{​​3}}(对于 3.0.0 版本也是正确的),cv::convertScaleAbs会将结果转换为 8位图像,i。即CV_8UC1类型。因此,您的totalGradiend 8位图像,并且无法通过unsigned short指针访问其元素。