c++ opencv sobel

c++ - Derivado de Sobel en OpenCV



(3)

Se me ha encomendado la tarea de crear mi propio método Sobel y no usar el cv :: Sobel que se encuentra en OpenCV. Traté de implementar uno que encontré en Técnicas de programación

Sin embargo, cuando ejecuto el programa, cv :: Mat arroja un error. Alguien tiene alguna idea de por qué?

Método Sobel:

int sobelCorrelation(Mat InputArray, int x, int y, String xory) { if (xory == "x") { return InputArray.at<uchar>(y - 1, x - 1) + 2 * InputArray.at<uchar>(y, x - 1) + InputArray.at<uchar>(y + 1, x - 1) - InputArray.at<uchar>(y - 1, x + 1) - 2 * InputArray.at<uchar>(y, x + 1) - InputArray.at<uchar>(y + 1, x + 1); } else if (xory == "y") { return InputArray.at<uchar>(y - 1, x - 1) + 2 * InputArray.at<uchar>(y - 1, x) + InputArray.at<uchar>(y - 1, x + 1) - InputArray.at<uchar>(y + 1, x - 1) - 2 * InputArray.at<uchar>(y + 1, x) - InputArray.at<uchar>(y + 1, x + 1); } else { return 0; } }

Llamarlo y procesarlo en otra función:

void imageOutput(Mat image, String path) { image = imread(path, 0); Mat dst; dst = image.clone(); int sum, gx, gy; if (image.data && !image.empty()){ for (int y = 0; y < image.rows; y++) for (int x = 0; x < image.cols; x++) dst.at<uchar>(y, x) = 0.0; for (int y = 1; y < image.rows - 1; ++y) { for (int x = 1; x < image.cols - 1; ++x){ gx = sobelCorrelation(image, x, y, "x"); gy = sobelCorrelation(image, x, y, "y"); sum = absVal(gx) + absVal(gy); if (sum > 255) sum = 255; else if (sum < 0) sum = 0; dst.at<uchar>(x, y) = sum; } } namedWindow("Original"); imshow("Original", image); namedWindow("Diagonal Edges"); imshow("Diagonal Edges", dst); } waitKey(0); }

Principal:

int main(int argc, char* argv[]) { Mat image; imageOutput(image, "C:/Dropbox/2-falling-toast-ted-kinsman.jpg"); return 0; }

El método absVal:

int absVal(int v) { return v*((v < 0)*(-1) + (v > 0)); }

Cuando se ejecuta, arroja este error: "Excepción no controlada en 0x00007FFC9365A1C8 en Miniproject01.exe: Excepción de Microsoft C ++: cv :: Excepción en la ubicación de memoria 0x000000A780A4F110". y señala aquí:

template<typename _Tp> inline _Tp& Mat::at(int i0, int i1) { CV_DbgAssert( dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] && (unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()) && CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1()); return ((_Tp*)(data + step.p[0] * i0))[i1]; }

¡Si alguien tiene algún consejo o idea de lo que estoy haciendo mal, sería muy apreciado!


Este fragmento de código es para demostrar cómo calcular los derivados de Sobel 3x3 que involucran la imagen con los núcleos de Sobel. Se puede extender fácilmente a diferentes tamaños de kernel dando el radio del kernel como entrada a my_sobel y creando el kernel apropiado.

#include <opencv2/opencv.hpp> #include <iostream> using namespace std; using namespace cv; void my_sobel(const Mat1b& src, Mat1s& dst, int direction) { Mat1s kernel; int radius = 0; // Create the kernel if (direction == 0) { // Sobel 3x3 X kernel kernel = (Mat1s(3,3) << -1, 0, +1, -2, 0, +2, -1, 0, +1); radius = 1; } else { // Sobel 3x3 Y kernel kernel = (Mat1s(3, 3) << -1, -2, -1, 0, 0, 0, +1, +2, +1); radius = 1; } // Handle border issues Mat1b _src; copyMakeBorder(src, _src, radius, radius, radius, radius, BORDER_REFLECT101); // Create output matrix dst.create(src.rows, src.cols); // Convolution loop // Iterate on image for (int r = radius; r < _src.rows - radius; ++r) { for (int c = radius; c < _src.cols - radius; ++c) { short s = 0; // Iterate on kernel for (int i = -radius; i <= radius; ++i) { for (int j = -radius; j <= radius; ++j) { s += _src(r + i, c + j) * kernel(i + radius, j + radius); } } dst(r - radius, c - radius) = s; } } } int main(void) { Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE); // Compute custom Sobel 3x3 derivatives Mat1s sx, sy; my_sobel(img, sx, 0); my_sobel(img, sy, 1); // Edges L1 norm Mat1b edges_L1; absdiff(sx, sy, edges_L1); // Check results against OpenCV Mat1s cvsx,cvsy; Sobel(img, cvsx, CV_16S, 1, 0); Sobel(img, cvsy, CV_16S, 0, 1); Mat1b cvedges_L1; absdiff(cvsx, cvsy, cvedges_L1); Mat diff_L1; absdiff(edges_L1, cvedges_L1, diff_L1); cout << "Number of different pixels: " << countNonZero(diff_L1) << endl; return 0; }


Si fuera usted, casi siempre evitaría usar bucles for (si es posible). Innecesario para los bucles, tienden a ralentizar la ejecución. En cambio, reutilícelo siempre que sea posible. Por ejemplo, el siguiente código usa filter2D para dar un resultado de correlación 2d:

Mat kern = (Mat_<float>(3,3)<<-1,0,1,-2,0,2,-1,0,1); Mat dest; cv::filter2D(src,dest,src.type(),kern);

Si desea obtener resultados de convolución, deberá voltear el kernel ''kern'' antes de filtrar.

cv::flip(kern,kern, -1);

Si desea obtener más rendimiento, puede usar filtros separables ''sepFilter2D''.


gracias por la publicación, pude generar un mapa gradiente usando el kernel anterior, y usando el código de código openCV filter2D obteniendo el uso del kernel personalizado en opencv 2DFilter, causando un bloqueo ... convolución ¿cómo?

para convolucionar la imagen con el núcleo. el código que usé es

#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <stdlib.h> #include <stdio.h> #include <iostream> using namespace cv; using namespace std; int main(int argc, char** argv) { //Loading the source image Mat src; //src = imread("1.png"); src = cv::imread("E://Gray_Image.bmp", 0); //Output image of the same size and the same number of channels as src. Mat dst1,dst2,grad; //Mat dst = src.clone(); //didn''t help... //desired depth of the destination image //negative so dst will be the same as src.depth() int ddepth = -1; //the convolution kernel, a single-channel floating point matrix: //Mat kernel = imread("kernel.png"); Mat kernel_x = (Mat_<float>(3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1); Mat kernel_y = (Mat_<float>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1); kernel_x.convertTo(kernel_x, CV_32F); kernel_y.convertTo(kernel_y, CV_32F); //<<not working //normalize(kernel, kernel, 1.0, 0.0, 4, -1, noArray()); //doesn''t help //cout << kernel.size() << endl; // ... gives 11, 11 //however, the example from tutorial that does work: //kernel = Mat::ones( 11, 11, CV_32F )/ (float)(11*11); //default value (-1,-1) here means that the anchor is at the kernel center. Point anchor = Point(-1, -1); //value added to the filtered pixels before storing them in dst. double delta = 0; //alright, let''s do this... filter2D(src, dst1, ddepth, kernel_x, anchor, delta, BORDER_DEFAULT); filter2D(src, dst2, ddepth, kernel_y, anchor, delta, BORDER_DEFAULT); imshow("Source", src); //<< unhandled exception here //imshow("Kernel1", kernel_x); imshow("Kernel2", kernel_y); imshow("Destination1", dst1); imshow("Destination2", dst2); addWeighted(dst1, 0.5, dst2, 0.5, 0, grad); imshow("Destination3", grad); waitKey(1000000); return 0; }