Loading Multiband tiff image into OpenCV C++ - c++

I tried loading a 8 band tiff image into OpenCV C++ but when I checked the dimensions of the image it gives me 3 bands of 1500 by 0 pixels. The image is 1500 by 1500 pixles with 8 bands. Is there a place I am going wrong? My code is as below:
int main(int argc, char** argv)
{
Mat Image, Normalized, ImageCopy;
if (argc != 2){
cout << "Define Image location" << endl;
}
else{
Image = imread(argv[1], CV_LOAD_IMAGE_UNCHANGED|CV_LOAD_IMAGE_ANYDEPTH);
}
cout <<" Number of bands \t: " << Image.channels() << "\t Image size\t"<< Image.size() << endl;
//Checking image validity
if(!Image.data){
cout << "Invalid image" <<endl;
return -1;
}
waitKey(0);
return 0;
}

I think you are out of luck, in TiffDecoder::readHeader() there is this:
m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? 3 : 1);
That is, it is using the PHOTOMETRIC tag to set the number of channels to 1 or 3.
For your code to work, you would need it to set the number of channels based on the SAMPLESPERPIXEL tag, but is doesn't. The whole decoder seems to be peppered with the assumption that an image is either grayscale or RGB. Even an RGBA image has its alpha channel discarded.
You could use libtiff directly, using the OpenCV source in grfmt_tiff.cpp as a guide.

Related

Image height is halved after transformation from VideoCapture to Mat object

The operations I did were quite simple:
I read an .avi file with a dimension of 1280x720, stored one frame of the video to a Mat object and displayed it.
Here is part of the code:
VideoCapture capL;
capL.open("F:/renderoutput/cube/left.avi");
Mat frameL;
cout << capL.get(CAP_PROP_FRAME_WIDTH) << ", " << capL.get(CAP_PROP_FRAME_HEIGHT) << endl;
for (;;)
{
capL.read(frameL);
cout << frameL.size() << endl;
if (frameL.empty())
break;
imshow("Output", frameL);
waitKey(200);
}
......
But the dimensions of the capL and frameL are not he same, with the former being 1280x720 and latter 1280x360. Why is this happening? I have been using OpenCV 3.3.1 in Visual Studio for quite a long time and some day this happened.
Most likely the video is interlaced. So you have only half height of it in every frame.

OpenCv 3.3 Cuda Medianfilter generates 2/3 of image black

I'm trying to use the cv::cuda::createMedianfilter function in OpenCV library.
This simple code produces an image which is 2/3 black, and only 1/3 is filtered.
using namespace cv;
int main(int argc, char** argv)
{
Mat src; Mat dst;
src = imread("test.bmp", 1);
cuda::GpuMat imageGpu(src),imageGpuOut;
cuda::Stream stream;
try
{
Ptr<cuda::Filter> filterX = cuda::createMedianFilter(CV_8UC1, 31);
filterX->apply(imageGpu, imageGpuOut,stream);
imageGpuOut.download(dst,stream);
stream.waitForCompletion();
imwrite("test_cuda31.bmp", dst);
}
catch (cv::Exception& e)
{
const char* err_msg = e.what();
std::cout << "exception caught: " << err_msg << std::endl;
}
}
Input image looks like this :Input image
Output image looks like this :Output image
I have tried several other images with different sizes and also different kernal sizes on the medianfilter. All with the same result.
Any ideas on what I'm doing wrong ?
You are loading an image of 3 channels (BGR)
src = imread("test.bmp", 1);
then, you are using as if the source was only 1 channel
Ptr<cuda::Filter> filterX = cuda::createMedianFilter(CV_8UC1, 31);
then it will process only 1/3 of the pixels, and probably the image is initialized in all 0, thus the black pixels in the rest of the image.
Sadly, cuda::createMedianFilter only supports CV_8UC1, so it is not possible to change that, but you can load the image as an CV_8UC1
src = imread("test.bmp", 0);
or convert it to greyscale after the load.
I hope this solves your problem

Is it normal that Opencv's imread is giving me a 2-D Mat when I ask for a color image?

So I have an .bmp image file in my folder.
I load it using imread:
cv::Mat image = cv::imread( imageName, CV_LOAD_IMAGE_COLOR );
After that I look at the dimensions of it with:
std::cout<<"Rows: "<<image.rows <<" Cols:"<<image.cols<<" Dims:"<<image.dims<<std::endl;
This gives me :
Rows: 480 Cols:640 Dims:2
But given that I had RGB image, shouldn't it also be 3D Mat?
Yes, it's normal.
dims is defined as (from the doc):
int dims; //! the array dimensionality, >= 2
You should look at the number of channels instead:
std:cout << "Channels: " << image.channels() << std::endl;

When does imwrite() fails

Does imwrite fails when the pixel values are of type CV_32FC1. I am trying to write an image in a jpg file but this is not working-:
make_response_mat(hr_lrt,response);
if (!response.data) // Checks input
{
cout << "Could not open or find the image" << std::endl;
return -1;
}
while (!imwrite("response.jpg", response))
{
cout << "Hari" << response.size() << "\n" << response.at<float>(456954, 4);
}
Here response has the pixel value of type float.
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). You can use Mat::convertTo to convert the image data type.
e.g.
Mat res;
response.convertTo(res, CV_8UC*)
* refer to image channel(1, 2, 3)

OpenCV - FPS from phone camera not correct

I have multiple recorded video samples, when I run these through my program it returns the FPS among other things. It is accurate enough for all of my video samples (see table below) but when I run a video sample taken through my smartphone it is returning the FPS at 90000, this happens with every video that captured through my smartphone so it is not just a problem with a single video file.
File Actual FPS OpenCV FPS ffmpeg FPS
action-60fps 60 59 60
action-24fps 24 24 24
phone_panning 29 90000 29
What is causing this problem?
EDIT: Managed to forget to add my code...
VideoCapture capture(argv[1]);
Mat frame;
if(capture.isOpened()) {
int fps = capture.get(CV_CAP_PROP_FPS);
int width = capture.get(CV_CAP_PROP_FRAME_WIDTH);
int height = capture.get(CV_CAP_PROP_FRAME_HEIGHT);
cout << "FPS: " << fps << ", width: " << width << ", height: " << height << endl;
VideoWriter writer("output.mpg",
CV_FOURCC('P','I','M','1'), fps, cvSize(width, height), 0); // 0 means gray, 1 means color
if(writer.isOpened()) {
while(true) {
capture >> frame;
if(!frame.empty()) {
imshow("Video", frame);
}
Mat frame_gray = frame.clone();
cvtColor(frame, frame_gray, CV_RGB2GRAY);
writer << frame_gray;
int key = waitKey(25);
if((char)key == 'q') {
break;
}
}
}
}
I had the same problem with opencv in calculating the FPS and number of frames in a video. (It was returning 90,000 for FPS and 5,758,245 for frame count for a 64-second video!!)
According to this answer:
OpenCV captures only a fraction of the frames from a video file
it's an opencv issue and they are working on it.
Another reason could be a problem with file header, mine was caused by converting video format. I solved it by using original video format mp4, instead of avi.