Unable to imwrite to PNG even though imshow works - c++

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.

Related

How can I get the color histogram inside the circle in the image or the gradient distribution in the circle?

I have detected circular objects in the image with OpenCV and C++ and using houghcircle function. But I would like to filter out only those circle that have dark color (it should be the airplane door window). So I thought to use the color histogram inside the detected circle in the image or the gradient distribution in those circle to filter out .It works on some images like in the image provided. But when there are more circles in the image does not find the dark circle. Also I played with canny threshold but I would like it do happened automatically. So basically how to make the program more robust?
Firstly here is the code in C++ using OpenCV and C++
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
#include <vector>
int thresh = 200;
int max_thresh = 400;
Mat src;
void thresh_callback(int, void* );
int main()
{
cv::Mat src = cv::imread("d4.png");
resize(src, src, Size(640,480), 0, 0, INTER_CUBIC);
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, src );
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
waitKey(0);
return(0);
}
void thresh_callback(int, void* ) {
Mat src_gray;
cv::Mat bgr_image = cv::imread( "d4.png");
cv::Mat orig_image = bgr_image.clone();
cvtColor( bgr_image, src_gray, COLOR_BGR2HSV );
medianBlur(src_gray, src_gray, 3);
Mat canny_output;
Canny( src_gray, canny_output, thresh, thresh*3.5, 3 );
// Threshold the HSV image, keep only the black pixels
cv::Mat lower_black_hue_range;
cv::Mat upper_black_hue_range;
cv::inRange(canny_output, cv::Scalar(0, 0, 0), cv::Scalar(10, 10, 40), lower_black_hue_range);
cv::inRange(canny_output, cv::Scalar(0,0, 41), cv::Scalar(10, 15, 50), upper_black_hue_range);
// Combine the above two images
cv::Mat black_hue_image;
cv::addWeighted(lower_black_hue_range, 1.0, upper_black_hue_range, 1.0, 0.0, black_hue_image);
cv::GaussianBlur(black_hue_image, black_hue_image, cv::Size(9, 9), 2, 2);
// Use the Hough transform to detect circles in the combined threshold image
std::vector<cv::Vec3f> circles;
cv::HoughCircles(black_hue_image, circles, CV_HOUGH_GRADIENT, 1, black_hue_image.rows/1, 10, 100, 10, 0);
// Loop over all detected circles and outline them on the original image
if(circles.size() == 0) std::exit(-1);
for(size_t current_circle = 0; current_circle < circles.size(); ++current_circle) {
Point center(cvRound(circles[current_circle][0]), cvRound(circles[current_circle][1]));
int radius = cvRound(circles[current_circle][2]);
cv::circle(orig_image, center, radius, cv::Scalar(0, 255, 0), 5);
}
// Show images
resize(lower_black_hue_range, lower_black_hue_range, Size(640,480), 0, 0, INTER_CUBIC);
char* source_window1 = "Threshold lower image";
namedWindow( source_window1, CV_WINDOW_AUTOSIZE );
imshow( source_window1, lower_black_hue_range );
//cv::namedWindow("Threshold lower image", cv::INTER_CUBIC);
//cv::imshow("Threshold lower image", lower_black_hue_range);
resize(upper_black_hue_range, upper_black_hue_range, Size(640,480), 0, 0, INTER_CUBIC);
char* source_window2 = "Threshold upper image";
namedWindow( source_window2, CV_WINDOW_AUTOSIZE );
imshow( source_window2, lower_black_hue_range );
//cv::namedWindow("Threshold upper image", cv::INTER_CUBIC);
//cv::imshow("Threshold upper image", upper_black_hue_range);
resize(black_hue_image, black_hue_image, Size(640,480), 0, 0, INTER_CUBIC);
char* source_window3 = "Combined threshold images";
namedWindow( source_window3, CV_WINDOW_AUTOSIZE );
imshow( source_window3, black_hue_image );
//cv::namedWindow("Combined threshold images", cv::INTER_CUBIC);
//cv::imshow("Combined threshold images", black_hue_image);
resize(orig_image, orig_image, Size(640,480), 0, 0, INTER_CUBIC);
char* source_window4 = "Detected black circles on the input image";
namedWindow( source_window4, CV_WINDOW_AUTOSIZE );
imshow( source_window4, orig_image );
//cv::namedWindow("Detected black circles on the input image", cv::INTER_CUBIC);
//cv::imshow("Detected black circles on the input image", orig_image);
}
Input image of good detected circle
The output is correct
Second image with more circles
The output is wrong, wrong detected circle
Any help?

converting the convolution code matlab to opencv in cpp

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.

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.

OpenCV: Use GaussianBlur or Sobel Derivatives on QImage

I hope you could help me.
I' m using QT and try to do a simple detection of edges on a image. But my program crash when i launch
cv::GaussianBlur( src, src, cv::Size(3,3), 0, 0, cv::BORDER_DEFAULT );
or
cv::Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, cv::BORDER_DEFAULT );
here is my code:
QImage *image1;
IplImage *cv_image1;
image1 = new QImage("./image.png"); // Format is ARGB32
cv_image1 = QImage2IplImage(image1);
cv::Mat src(cv_image1);
cv::imshow(window_name, src); // Work Well
cv::Mat src_gray;
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
cv::GaussianBlur(src, src, cv::Size(3,3), 0, 0, cv::BORDER_DEFAULT); //Crash Here
cv::imshow( window_name, src);
I think that was a problem of format.
But in another program with QIMAGES in ARGB32 this code work well.
Thank you.
Try going with proper QImage to cv::Mat conversion using this functions and you should be fine (I also included a conversion from cv::Mat to QImage):
cv::Mat cvmat_from_qimage(const QImage& qimage)
{
cv::Mat mat = cv::Mat(qimage.height(), qimage.width(), CV_8UC4, (uchar*)qimage.bits(), qimage.bytesPerLine());
cv::Mat mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC3 );
int from_to[] = { 0,0, 1,1, 2,2 };
cv::mixChannels( &mat, 1, &mat2, 1, from_to, 3 );
return mat2;
}
QImage qimage_from_cvmat(const cv::Mat& mat)
{
cv::Mat rgb;
cvtColor(mat, rgb, CV_BGR2RGB);
return QImage((const unsigned char*)(rgb.data), rgb.cols, rgb.rows, QImage::Format_RGB888);
}
I Found a solution.
That' s weird but when I do:
cvtColor(src, src_gray, CV_RGB2GRAY );
cv::Sobel(src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, cv::BORDER_CONSTANT);
without the cv::GaussianBlur it works well. I just change the last parameter to cv::BORDER_CONSTANT

How to extract Numerical gradient matrix from the image matrix in Opencv

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.