Here is my horizontal gradient results.The left one is opencv result and the other one is matlab result
I am trying to do horizontal and vertical gradient which H =[1,-1] and V=[1;-1]
Mat H_gradient,G_Filter1,kernel,V_gradient;
Mat kernelH(1, 2, CV_32F);
kernelH.at<float>(0,0) = 1.0f;
kernelH.at<float>(0,1) = -1.0f;
Mat kernelV(2, 1, CV_32F);
kernelV.at<float>(0,0) = 1.0f;
kernelV.at<float>(1,0) = -1.0f;
cvtColor( image, image, CV_RGB2GRAY );
filter2D( image, H_gradient, -1 ,kernelH , Point( -1, -1 ), 0, BORDER_DEFAULT );
filter2D( image, V_gradient, -1 ,kernelV , Point( -1, -1 ), 0, BORDER_DEFAULT );
But still not match with my matlab code results. I dont know why?
My matlab code for gradients
image=double(image);
% horizontal and vertical gradient
H=[1 -1];
V=[1;-1];
H_Gradient=conv2(image,H,'same');
V_Gradient=conv2(image,V,'same');
try do
cvtColor( image, image, **CV_BGR2GRAY** );
instead of
cvtColor( image, image, **CV_RGB2GRAY** );
If you are using the default imread parameters, OpenCv use BGR color format instead of RGB as default!
Do the same that you did in Matlab, first convert your image to double.
image.convertTo(image, CV_32F);
Now I got the same result in OpenCv and Matlab.
Related
I need some help in detecting the dominant intensity area of an image. Suppose I have the following images and I like to automatically detect the dominant intensity area and find the mean/average intensity value of that dominant area.
Here, in Image-1, the dominant intensity area is the area with light gray color and in Image-2, the dominant area is with the dark gray color. How can I detect the dominant areas in those images and find the mean intensity value of the dominant area.
Image-1:
Image-2:
Any suggestion will be helpful!
Update: I used the following codes to get the histogram for Image-2. Figure-3 shows the histogram. Now, I need to find out which bin holds the most of the values i.e. the mode of the histogram. But, couldn't figure out how to calculate the bin with most of the values.
Figure-3:
int main(int, char**)
{
Mat gray=imread("Depth_frames_27/Image23.png",0);
namedWindow( "Gray", 1 ); imshow( "Gray", gray );
// Initialize parameters
int histSize = 256; // bin size
float range[] = { 0, 255 };
const float *ranges[] = { range };
// Calculate histogram
MatND hist;
calcHist( &gray, 1, 0, Mat(), hist, 1, &histSize, ranges, true, false );
double minVal=0, maxVal=0;
minMaxLoc(hist, &minVal, &maxVal, 0, 0);
// cout<<"Max:"<<maxVal<<endl;
// cout<<"Min:"<<minVal<<endl;
// Show the calculated histogram in command window
double total;
total = gray.rows * gray.cols;
for( int h = 0; h < histSize; h++ )
{
float binVal = hist.at<float>(h);
cout<<" "<<binVal;
}
// Plot the histogram
int hist_w = 512; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC1, Scalar( 0,0,0) );
normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(hist.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
}
namedWindow( "Result", 1 ); imshow( "Result", histImage );
waitKey();
return 0;
}
Update-2: Worked out finally! I did the following to get the location and value of the maximum bin of the histogram.
double minVal=0, maxVal=0; int minIdx, maxIdx;
minMaxIdx(hist,&minVal,&maxVal, &minIdx, &maxIdx);
cout<<"Max:"<<maxVal<<endl;
cout<<"MaxIdx:"<<maxIdx<<endl;
The MaxIdx gives the location of the highest bin of the histogram and that's the dominant intensity value for the image!
What you are after is the mode of the histogram of intensities (the bin with the highest frequency). It directly tells you the average intensity.
For the given images, the histogram is made of two perfectly sharp peaks.
In some bad cases, the main peak can be spread over several secondary peaks. In such cases, you need to apply smoothing to the histogram before taking the mode.
It can be interesting to look at the relative heights of the first and second maxima, to check how dominant the color is.
I want to make matrix multiplication between image and mask. I want multiply in HSV value with 0.3. I think, the problem is between CV_32FC3 and CV_8UC3, but when I convert, still not work correct.
How can I do? Here is my current code:
Mat mask = Mat(frame.size(), CV_32FC3, cv::Scalar(1, 1, 1));
cv::fillConvexPoly(mask, pts, 3, cv::Scalar(1,1,0.3));
cvtColor(frame, frame, CV_BGR2HSV);
frame.convertTo(frame, CV_32FC3);
cv::multiply(frame,mask,frame);
frame.convertTo(frame, CV_8UC3);
cvtColor(frame, frame, CV_HSV2BGR);
If I do only this, see the mask is ok - white and black changes:
Mat mask = Mat(frame.size(), CV_32FC3, cv::Scalar(1, 1, 1));
cv::fillConvexPoly(mask, pts, 3, cv::Scalar(0,0,0));
imshow("mask", mask);
I am using a Scalar to define the color of a rectangle I am drawing with OpenCV:
rectangle(imgOriginal, Point(0, 0), Point(25, 50), Scalar(H, S, V), CV_FILLED);
However, the color is defined in HSV color space rather than RGB (imgOriginal is RGB).
How do I convert Scalar (or its input, the integer variables H, S, and V) to RGB?
(So far I only found answers telling me how to convert a whole image with cvtColor which is not what I want.)
Although not optimal, You can use the following:
Scalar ScalarHSV2BGR(uchar H, uchar S, uchar V) {
Mat rgb;
Mat hsv(1,1, CV_8UC3, Scalar(H,S,V));
cvtColor(hsv, rgb, CV_HSV2BGR);
return Scalar(rgb.data[0], rgb.data[1], rgb.data[2]);
}
This worked for me,
Mat rgb;
Mat hsv(1, 1, CV_8UC3, Scalar(224, 224, 160));
cvtColor(hsv, rgb, CV_HSV2BGR);
Scalar rgb = Scalar((int)rgb.at<cv::Vec3b>(0, 0)[0],(int)rgb.at<cv::Vec3b>(0, 0)[0],(int)rgb.at<cv::Vec3b>(0, 0)[0])
OpenCV 3.2.0. Note: h is in range [0,360] and l and s is in [0,1]
Mat hls(1, 1, CV_32FC3, Scalar(h, l, s));
Mat rgb;
cvtColor(hls, rgb, COLOR_HLS2RGB);
Scalar c = Scalar(255*rgb.at<float>(0,0), 255*rgb.at<float>(0,1), 255*rgb.at<float>(0,2));
Use this to convert a single value:
cv::Vec3f rgb;
cv::Vec3f hsv;
hsv[0] = H;
hsv[1] = S;
hsv[2] = V;
cvtColor(hsv, rgb, CV_HSV2BGR);
Then you can use it:
rectangle(imgOriginal, Point(0, 0), Point(25, 50),
Scalar(rgb[0], rgb[1], rgb[2]), CV_FILLED);
I'm trying to follow the discreet fourier transform (dft) example here:
http://docs.opencv.org/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.html
I'm running 2.4.8 on Visual Studio 2013 Express in Windows 8.
I've modified the example so that instead of loading a greyscale image I'm using a colour image captured from my webcam (loaded into a Mat variable).
When I run the example above, I get the following error:
"Assertion Failed Tp>::channels == m.channels()) in
cv::Mat::operator"
and a break at the following line:
Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
Looking around, I saw that this is the old way of converting between types, so I added these lines to convert everything to CV_32F:
padded.convertTo(padded32, CV_32F);
Mat planes[] = { padded32, Mat::zeros(padded32.size(), CV_32F) };
Now the problem is that I get another assertion fail a few lines down at:
split(complexI, planes);
The Error is:
"Assertion Failed (Type == CV_32FC1 || Type == CV_32FC2 || ... || Type
== CV_64FC2) in cv::dft"
So now it seems like it doesn't like the CV_32F data type. I tried making the data type CV_32FC1, but it had the same error. I suspect it's related to the output data type of complexI from the dft() function but I'm not sure what to do. It may also be related to the number of channels in my input (3 channel colour vs 1 channel greyscale image).
Thanks for the help.
Complete code from the linked example:
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
int main(int argc, char ** argv)
{
const char* filename = argc >=2 ? argv[1] : "lena.jpg";
Mat I = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
if( I.empty())
return -1;
Mat padded; //expand input image to optimal size
int m = getOptimalDFTSize( I.rows );
int n = getOptimalDFTSize( I.cols ); // on the border add zero values
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
Mat complexI;
merge(planes, 2, complexI); // Add to the expanded another plane with zeros
dft(complexI, complexI); // this way the result may fit in the source matrix
// compute the magnitude and switch to logarithmic scale
// => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude
Mat magI = planes[0];
magI += Scalar::all(1); // switch to logarithmic scale
log(magI, magI);
// crop the spectrum, if it has an odd number of rows or columns
magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));
// rearrange the quadrants of Fourier image so that the origin is at the image center
int cx = magI.cols/2;
int cy = magI.rows/2;
Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right
Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left
Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right
Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
q2.copyTo(q1);
tmp.copyTo(q2);
normalize(magI, magI, 0, 1, CV_MINMAX); // Transform the matrix with float values into a
// viewable image form (float between values 0 and 1).
imshow("Input Image" , I ); // Show the result
imshow("spectrum magnitude", magI);
waitKey();
return 0;
}
You cannot use dft on an imagine that has more than 2 channels.
Even if the image has 2 channels the second one is interpreted as the imaginary part of a complex number so this probably not what you want anyway.
So you have 2 options: either convert the colour image that you get from your webcam to a single channel image, like a grayscale image, or apply the dft for each channel independently.
You can take a look over mix channels or split, both of them can extract the individual channels from your image and then apply dft on each of them,
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.