How to extract Numerical gradient matrix from the image matrix in Opencv - c++

i am searching a way to get Numerical gradient from the matrix. The same
function is implemented in matlab's default documentation.http://www.mathworks.com/help/techdoc/ref/gradient.html but i couldn't find any in opencv.
I want to port this to C++ using opencv.
should i use sobel for horizontal and vertical gradient or any
other function or way to do it???
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
/// Gradient X
Sobel( mat, grad_x, CV_32F, 1, 0, 3);
imshow("xx",grad_x);
convertScaleAbs( grad_x, abs_grad_x );
/// Gradient Y
Sobel( mat, grad_y, CV_32F, 0, 1, 3);
convertScaleAbs( grad_y, abs_grad_y );
/// Total Gradient (approximate)
Mat res;
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, res );
[EDIT]
solution
Mat grad_x,abs_grad_x,grad_y,abs_grad_y;
int type=CV_64F ;
Gradient.setTo(Scalar::all(0));
/// Gradient Y
Sobel( input, grad_x, type, 1, 0, 3);
convertScaleAbs(grad_x,abs_grad_x);
cv::accumulateSquare(abs_grad_x,Gradient);
/// Gradient Y
Sobel(input, grad_y, type, 0, 1, 3);
convertScaleAbs(grad_y,abs_grad_y);
cv::accumulateSquare(abs_grad_y,Gradient);
imshow("gradient Mag",Gradient);

You can find the gradient calculation here Just like you have said to calculate sobel gradients, the example does so.

Related

Using Opencv and Hough Transform circle to detect circles (subscript error)

As right now is my school holiday, I decided to pick up some skills thus I'm attempting to learn how to use OpenCV features with visual studio c++ to detect how many cans is in the carton and had to group it 4 by 4.
I have tried various demo codes such as " opencv find:contour " , Template matching(doesn't work well as it cannot detect the rotation of the top lid)
The best method that I found out is that to combine Canny Edge Detection and Hough Transform Circle such that the output result of Canny Edge Detection can be the input image of the Hough Transform Circle,the result is as below.
Unfortunately, not all circles is detected and if i change the
for (int i = 0; i < circles.size(); i++) into
for (int i = 0; i < 24; i++) // 24 is the no. of cans
I will get a Expression: vector subscript out of range. I am not sure why it is only able to detect 21 circles
Source code as below:-
using namespace cv;
using namespace std;
Mat src, src_gray;
int main()
{
Mat src1;
src1 = imread("cans.jpg", CV_LOAD_IMAGE_COLOR);
namedWindow("Original image", CV_WINDOW_AUTOSIZE);
imshow("Original image", src1);
Mat gray, edge, draw;
cvtColor(src1, gray, CV_BGR2GRAY);
Canny(gray, edge,50, 150, 3);
//50,150,3
edge.convertTo(draw, CV_8U);
namedWindow("Canny Edge", CV_WINDOW_AUTOSIZE);
imshow("Canny Edge", draw);
imwrite("output.jpg", draw);
waitKey(500);
/// Read the image
src = imread("output.jpg", 1);
Size size(932, 558);//the dst image size,e.g.100x100
resize(src, src, size);//resize image
/// Convert it to gray
cvtColor(src, src_gray, CV_BGR2GRAY);
/// Reduce the noise so we avoid false circle detection
GaussianBlur(src_gray, src_gray, Size(9, 9), 2, 2);
vector<Vec3f> circles;
/// Apply the Hough Transform to find the circles
HoughCircles(src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows / 8,200, 100, 0, 0);
/// Draw the circles detected
for (int i = 0; i < circles.size(); i++)
{
printf("are you um?\n");
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// circle center
circle(src, center, 3, Scalar(0, 255, 0), -1, 8, 0);
// circle outline
circle(src, center, radius, Scalar(255, 0, 255), 3, 8, 0);
}
// namedWindow("Hough Circle Transform Demo", CV_WINDOW_NORMAL);
imshow("Hough Circle Transform Demo", src);
line(src, Point(0, 288), Point(1024, 288), Scalar(225, 220, 225), 2, 8);
// middle line
line(src, Point(360, 0), Point(360, 576), Scalar(225, 220, 225), 2, 8);
//break cans into 4 by 4
line(src, Point(600, 0), Point(600, 576), Scalar(225, 220, 225), 2, 8);
// x, y
imshow("Lines", src);
imwrite("lineoutput.jpg", src);
waitKey(0);
return 0;
}
I had also manually typed out the coordinates for the lines to group them into 4 x 4.
What should I change in order for it not to have any subscript out of range error and able to detect all circles?
Okay solved my own question. Changed CV_BGR2GRAY to CV_RGB2GRAY,made the file ratio smaller, changing the circles min Radius and applying another threshold to get the circles.

How to apply discrete Green's theorem to an image using the library Opencv?

I'm trying to implement the core detection algorithm on fingerprint from the paper "Singular Point Detection in Fingerprint Image".
1) I have defined the direction field from part 2 (original and Theta, W=2x2)
2) The next step is to find the gradient of field orientation (over x and y respectively):
Mat Jx, Jy;
Sobel(theta, Jx, CV_32F, 1, 0, 3, 1, 0, BORDER_DEFAULT);
Sobel(theta, Jy, CV_32F, 0, 1, 3, 1, 0, BORDER_DEFAULT);
3) Apply next formula to image (disctete Green's theoreme):
I do so, but I think it's wrong:
Mat Jx_dy, Jy_dx;
Sobel(Jy, Jy_dx, CV_32F, 1, 0, 3, 1, 0, BORDER_DEFAULT);
Sobel(Jx, Jx_dy, CV_32F, 0, 1, 3, 1, 0, BORDER_DEFAULT);
Mat G, _G;
cv::subtract(Jy_dx, Jx_dy, _G);
integral(_G,G);
imshow("Jy_dx - Jx_dy", _G); //totally black image
How to apply this formula on image?
Thanks.

OpenCV filter2D negative values in C++

I'm trying to implement Histogram of Oriented Gradients on some video frames in C++. I used filter2D to convolute the frame image yet it seems that the resulting values are floored at 0. How do I get filter2D to give negative values as well?
Here's a snippet of code:
// Function that gets the histogram of gradients for a single video file
int HOG(string filename)
{
static int frames_read = 0;
VideoCapture cap(filename);
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat image;
namedWindow(filename,1);
// Read through frames of video
for(;;)
{
Mat frame;
float histogram[NUM_BINS * SPACIAL_X * SPACIAL_Y] = {0};
cap >> frame; // Get a new frame from camera
if(frame.empty())
break;
cvtColor(frame, image, CV_BGR2GRAY);
// Set up gradient kernels
float kernelX[9] = {0, 0, 0, -1.0, 0, 1.0, 0, 0, 0};
float kernelY[9] = {0, -1.0, 0, 0, 0, 0, 0, 1.0, 0};
Mat filterX(3, 3, CV_32F, kernelX);
Mat filterY(3, 3, CV_32F, kernelY);
Mat gradientX;
Mat gradientY;
// Apply gradients
filter2D(image, gradientX, CV_32F, filterX, Point (-1, 1), 0, BORDER_DEFAULT);
filter2D(image, gradientY, CV_32F, filterY, Point (-1, 1), 0, BORDER_DEFAULT);
}
}
Your code seems to be OK, and should generate positive results as well as negatives. How are you checking that there no negative results? Maybe you are converting floating point images to gray level (i.e. unsigned char), this indeed will crop all negative results.
It is easier to get same results by using Sobel function, that is dedicated to calculation of gradients in image:
Sobel(image, gradientX, CV_32F, 1, 0, 1);
Sobel(image, gradientY, CV_32F, 0, 1, 1);

Obtain Gradient orientation in OpenCV

I must find the orientation of the gradient in an image. I already obtain Gx,Gy and the total gradient.
//Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
Sobel( img, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x ); //Gradiente en X
/// Gradient Y
//Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
Sobel( img, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y ); //Gradiente en Y
/// Total Gradient (approximate)
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad ); //Magnitud del Gradiente
Now, I must find the orientation of the gradient,but I dont find any code to get it. I know the theory but I dont know to put it in practice.
Anyone knows how can I get de orientation of the gradient?
Thanks for your time
EDIT: I tried to use this:
Mat modulo;
Mat orientacion;
cartToPolar(abs_grad_x,abs_grad_y,modulo,orientacion);
But it give me an error:
OpenCV Error: Assertion failed (X.size == Y.size && type == Y.type() && (depth == CV_32F || depth == CV_64F)) in cartToPolar, file C:\OpenCV246PC\opencv\modules\core\src\mathfuncs.cpp, line 448
I tried to change the depth to CV_32F and the image of gradient its not correct.

Unable to imwrite to PNG even though imshow works

Does anyone know why even though I could imshow the image stored in grad, I am unable to write it using imwrite? I searched the web and it seems like it might be a floating point issue, but I do not know of any way to make the floating points in the matrix of an image disappear.
int main( int argc, char** argv ) {
cv::Mat src, src_gray;
cv::Mat grad;
char* window_name = "Sobel Demo - Simple Edge Detector";
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
int c;
/// Load an image
src = imread("C:/Users/Qi Han/Dropbox/44.jpg" );
if( !src.data ) return -1;
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
/// Convert it to gray
cvtColor( src, src_gray, CV_RGB2GRAY );
/// Create window
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
/// Generate grad_x and grad_y
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
/// Gradient X
//Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x );
/// Gradient Y
//Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y );
/// Total Gradient (approximate)
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
imshow( window_name, grad );
imwrite("C:/Users/Qi Han/Dropbox/aftsobel.png", grad);
return 0;
}
Try to imwrite a BMP image instead or use Mat::convertTo and cvtColor to convert it before saving.
From imwrite documentation:
[...] Only 8-bit (or 16-bit unsigned (CV_16U) in case of PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with ‘BGR’ channel order) images can be saved using this function. If the format, depth or channel order is different, use Mat::convertTo() , and cvtColor() to convert it before saving. [...]
read the docs of imwrite:
Only 8-bit (or 16-bit unsigned (CV_16U) in case of PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with ‘BGR’ channel order) images can be saved using this function. If the format, depth or channel order is different, use Mat::convertTo() , and cvtColor() to convert it before saving.