为了更好地理解计算机视觉,我试图从头开始编写一个精确的边缘检测算法" (不只是使用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;}
}
}
}
答案 0 :(得分:0)
你的错误在于周围的代码,而不是算法本身。根据{{3}}(对于 3.0.0 版本也是正确的),cv::convertScaleAbs
会将结果转换为 8位图像,i。即CV_8UC1
类型。因此,您的totalGradiend
是 8位图像,并且无法通过unsigned short
指针访问其元素。