Unable to write Grayscale image with imwrite in OpenCV - c++

I tried to convert RGB image into grayscale, conversion is successfull and i can display it with imshow. Yet, i cannot write it with imwrite, imwrite function returns NULL. My original image is 1920*1080 JPEG file with UINT8. Here is the code
#include <opencv\cv.h>
#include <opencv\highgui.h>
using namespace cv;
int main(int argc, char** argv)
{
char* imageName = argv[1];
Mat image;
image = imread(imageName, 1);
if (argc != 2 || !image.data)
{
printf(" No image data \n ");
return -1;
}
Mat gray_image;
cvtColor(image, gray_image, CV_BGR2GRAY);
if (imwrite("../../images/Gray_Image.jpg", gray_image) ==NULL) {
printf( "Writing image is not successfull!");
}
namedWindow(imageName, CV_WINDOW_AUTOSIZE);
namedWindow("Gray image", CV_WINDOW_AUTOSIZE);
imshow(imageName, image);
imshow("Gray image", gray_image);
waitKey(0);
return 0;
}
Why imwrite returns NULL?

The #include directive supports forward slashes. Use forward slashes there, for portability. And for sanity.
File handling functions generally don't support forward slashes in Windows. Use backward slashes there. Or, better, use some path handling class (such classes often support forward slashes, since they need to be portable, and automatically convert to backward slash in Windows).
In short,
/ → \ to fix the immediate problem.
That said, the OpenCV imwrite probably does not support automatic folder creation, so you'd better make sure that …
the specified folder exists, and
for a relative path (as you have), that the program execution's current folder is where you imagined the relative path starting.

Related

How to read a .tif floating point gray scale image in openCV

I am trying to read a .tif or .tiff floating point gray scale image in OpenCV.
I can read and write routine file format such as png, jpg etc but I am not able to read from my Desktop a format I never used before which is .tif or .tiff format.
The image: the image I am trying to read has the following parameters:
Size:
And width and height:
After some documentation and various sources I was able to understand that it is possible to use a convertTo function to convert between available data types, the source can be found here. However this didn't work well and I actually had a compilation error saying:
OpenCV(3.4.1) Error: Assertion failed (size.width>0 && size.height>0) in imshow, file /home/to/opencv/modules/highgui/src/window.cpp, line 356
terminate called after throwing an instance of cv::Exception
what(): OpenCV(3.4.1) /home/to/opencv/modules/highgui/src/window.cpp:356: error: (-215) size.width>0 && size.height>0 in function imshow
The code I am using is the following:
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
Mat img = imread("/home/to/Desktop/example.tif");
cv::imshow("source",img);
Mat dst; // destination image
// check if we have RGB or grayscale image
if (img.channels() == 3) {
// convert 3-channel (RGB) 8-bit uchar image to 32 bit float
img.convertTo(dst, CV_32FC3);
}
else if (img.channels() == 1) {
// convert 1-chanel (grayscale) 8-bit uchar image to 32 bit float
img.convertTo(dst, CV_32FC1);
}
// display output, note that to display dst image correctly
// we have to divide each element of dst by 255 to keep
// the pixel values in the range [0,1].
cv::imshow("output",dst/255);
waitKey();
}
Additional example I tried to make it work is directly from the OpenCV documentation which can be found here, with a small modification though. I read from official documentation that the options IMREAD_ANYCOLOR | IMREAD_ANYDEPTH should also be activated and in fact is what I did in the second additional trial below:
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
String imageName( "/home/to/Desktop/example.tif" ); // by default
if( argc > 1)
{
imageName = argv[1];
}
Mat image;
Mat outImage;
image = imread( imageName, IMREAD_ANYCOLOR | IMREAD_ANYDEPTH ); // Read the file
if( image.empty() ) // Check for invalid input
{
cout << "Could not open or find the image" << std::endl ;
return -1;
}
namedWindow( "Display window", WINDOW_AUTOSIZE ); // Create a window for display.
resize(image, outImage, cv::Size(500,500));
imshow("orig", image);
imshow("resized", outImage);
// Show our image inside it.
waitKey(0); // Wait for a keystroke in the window
return 0;
This time the compiler runs without any error but no image is shown as it is possible to see from the print screen below:
UPDATE
This is the result after the cv::resize
UPDATE 2
This the result after applying imshow("Display window", image*10);
Is there something that I am missing from the official documentation or something else I am forgetting to do?
Thanks for shedding light on this issue.
Your image is composed of a single channel of 64-bit floats which range from -219.774 to -22.907. I can tell that using tiffutil which is shipped with libtiff:
tiffutil -verboseinfo image.tif
TIFFReadDirectory: Warning, Unknown field with tag 33550 (0x830e) encountered.
TIFFReadDirectory: Warning, Unknown field with tag 33922 (0x8482) encountered.
TIFFReadDirectory: Warning, Unknown field with tag 42113 (0xa481) encountered.
Directory at 0x256b3a2
Image Width: 2277 Image Length: 2153
Bits/Sample: 64
Sample Format: IEEE floating point
Compression Scheme: none
Photometric Interpretation: "min-is-black"
Samples/Pixel: 1
Rows/Strip: 1
Number of Strips: 2153
Strips (Offset, ByteCount):
17466, 18216
35682, 18216
53898, 18216
...
...
I am not certain exactly what you plan to do, but as a first stab, you can just add 220 to every pixel and convert to unsigned char and your range will be 0 to 197 which is perfectly displayable:
I actually did it using Python because I am quicker with that, but the C++ will follow exactly the same format:
import cv2
# Load image
img = cv2.imread('image.tif',cv2.IMREAD_UNCHANGED)
# Add 220 to all values, round to unsigned 8-bit and display
Image.fromarray((img+220).astype(np.uint8)).show()

How can I resolve showing empty image in opencv?

I use opencv2.4.9 whith visual studio 2010
when I have to show an image program display the empty window and not show image
and its my code:
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\core\core.hpp>
#include<opencv\cv.h>
int main(int argc,char**argv[]) {
IplImage* img1=cvLoadImage("C:\opencv\sources\samples\cpp\board.jpg");
cvNamedWindow("img1",CV_WINDOW_AUTOSIZE);
cvShowImage("img1",img1);
cvWaitKey(0);
cvReleaseImage(&img1);
}
The problem is in the way you wrote the path of the image. you should not use the escape character alone. You can solve it by one of these:
IplImage* img1=cvLoadImage("C:\\opencv\\sources\\samples\\cpp\\board.jpg");
Or:
IplImage* img1=cvLoadImage("C:/opencv/sources/samples/cpp/board.jpg");
Or:
IplImage* img1=cvLoadImage(R"(C:\opencv\sources\samples\cpp\board.jpg)");
BTW, you are using C interface which is really too out of data. If you do not have a REAL reason to use it, please do not. The equivalent code that use C++ is:
int main(int argc,char**argv[]) {
cv::Mat img1=cv::imread("C:\\opencv\\sources\\samples\\cpp\\board.jpg");
cv::namedWindow("img1",CV_WINDOW_AUTOSIZE);
cv::imshow("img1",img1);
cv::waitKey(0);
//No need to release manually
}
if you use Mat then you can use:
if (frame1.empty())
{
std::cout << "no image";
break;
}
then if the image not empty you should use more delay to display the images.
for example you can use:
waitKey(100);

imwrite does not create image

#include <opencv/cv.h>
#include <opencv/highgui.h>
using namespace cv;
int main( int argc, char** argv )
{
const char* imageName = "samp.png";
Mat image;
image = imread( imageName, 1 );
Mat gray_image;
cvtColor( image, gray_image, CV_BGR2GRAY );
imwrite( "/home/Downloads/Pictures/Gray_Image.jpg",gray_image );
namedWindow( imageName, CV_WINDOW_AUTOSIZE );
namedWindow( "Gray image", CV_WINDOW_AUTOSIZE );
imshow( imageName, image );
imshow( "Gray image", gray_image );
waitKey(0);
return 0;
}
'imwrite" in the above code does not create image.Everything else works fine,and I can see the image using imshow.But I dont know why it is not creating a image.I tried 'convertTo' and replacing '/' to '\' in the path, but it does not work.I will be pleased if I get any lead.Thanks!
This is not documented clearly, but imwrite returns a boolean which is true if and only if it thinks that it could write the file successfully. You should check that value!
You'll probably find out that imwrite returns false. Most likely you do not have sufficient permissions or -- as berak pointed out -- your file path is invalid.
By the way, for proper error handling, you should also catch exceptions, in particular, if the user provides the output file URL. If OpenCV, for some reason, can't find a suitable encoder (i.e. it can't recognize which type of file you are going to write), it will throw an exception.
Markus Mayr's response helped me find out that I was getting a false when I printed the result of imwrite. The reason turned out to be, the directory in which I was trying to write, didnt exist. I was assuming it will create the directory but imwrite silently failed.After I manually created the directory it worked

Thresholding Images from a Webcam

I am teaching myself OpenCV for a work project that will eventually involve object tracking and such, and I'm just trying to familiarize myself with the basics right now. I have a chunk of code that's meant to simply grab images from my webcam, convert them to grayscale and threshold them, and print them out to a window. I keep getting this error:
"cannot convert parameter 1 from 'cv::Mat' to 'const CvArr *'"
with this code:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int main()
{
Mat img;
VideoCapture cap(0);
while (true)
{
cap >> img;
Mat tHold;
cvtColor(img, tHold, CV_BGR2GRAY);
cvThreshold(tHold, tHold, 50, 255, CV_THRESH_BINARY);
imshow("Thresholded Image", tHold);
waitKey(1);
}
return 0;
}
The thing is that other functions seem to work, like Canny(), etc...I just can't get thresholding to work. Thoughts? Thanks!
You are using the function cvThreshold from the C interface of OpenCV. Whereas the input images are of type cv::Mat which are from the C++ interface.
The corresponding C++ function of cvThreshold is cv::threshold. Just replace cvThreshold with cv::threshold.

C/C++ OpenCV video processing

Good day everyone! So currently I'm working on a project with video processing, so I decided to give a try to OpenCV. As I'm new to it, I decided to find few sample codes and test them out. First one, is C OpenCV and looks like this:
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <stdio.h>
int main( void ) {
CvCapture* capture = 0;
IplImage *frame = 0;
if (!(capture = cvCaptureFromCAM(0)))
printf("Cannot initialize camera\n");
cvNamedWindow("Capture", CV_WINDOW_AUTOSIZE);
while (1) {
frame = cvQueryFrame(capture);
if (!frame)
break;
IplImage *temp = cvCreateImage(cvSize(frame->width/2, frame->height/2), frame->depth, frame->nChannels); // A new Image half size
cvResize(frame, temp, CV_INTER_CUBIC); // Resize
cvSaveImage("test.jpg", temp, 0); // Save this image
cvShowImage("Capture", frame); // Display the frame
cvReleaseImage(&temp);
if (cvWaitKey(5000) == 27) // Escape key and wait, 5 sec per capture
break;
}
cvReleaseImage(&frame);
cvReleaseCapture(&capture);
return 0;
}
So, this one works perfectly well and stores image to hard drive nicely. But problems begin with next sample, which uses C++ OpenCV:
#include "opencv2/opencv.hpp"
#include <string>
using namespace cv;
int main(int, char**)
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat edges;
//namedWindow("edges",1);
for(;;)
{
Mat frame;
cap >> frame; // get a new frame from camera
cvtColor(frame, edges, CV_RGB2XYZ);
imshow("edges", edges);
//imshow("edges2", frame);
//imwrite("test1.jpg", frame);
if(waitKey(1000) >= 0) break;
}
// the camera will be deinitialized automatically in VideoCapture destructor
return 0;
}
So, yeah, generally, in terms of showing video (image frames) there is practically no changes, but when it comes to using im** functions, some problems arise.
Using cvSaveImage() works out nicely, but the moment I try to use imwrite(), unhandled exception arises in regards of 'access violation reading location'. Same goes for imread(), when I'm trying to load image.
So, the thing I wanted to ask, is it possible to use most of the functionality with C OpenCV? Or is it necessary to use C++ OpenCV. If yes, is there any solution for the problem I described earlier.
Also as stated here, images initially are in BGR-format, so conversion needed. But doing BGR2XYZ conversion seems to invert colors, while RGB2XYZ preserve them. Examples:
images
Or is it necessary to use C++ OpenCV?
No, there is no necessity whatsoever. You can use any interface you like and you think you are good with it (OpenCV offers C, C++, Python interfaces).
For your problem about imwrite() and imread() :
For color images the order channel is normally Blue, Green, Red , this
is what imshow() , imread() and imwrite() expect
Quoted from there