How to open ECW file with GDAL in OpenCV 3.0 - c++

As you know, GDAL is added to OpenCV version 3. I have a satellite ecw image and want to read and show it. I already try to use OpenCV sample named : gdal-image.cpp. it has a line for reading input image:
cv::Mat image = cv::imread(argv[1], cv::IMREAD_LOAD_GDAL | cv::IMREAD_COLOR );
my problem : I set my ecw image as argv[1] but it doesnt work.
should I convert my image before?
any way to read ecw using GDAL?

For read ecw image, i suggest you use GDAL, you can download GDAL binary prebuild and ECW extension from here https://www.gisinternals.com/release.php.
For read the first band of image you can use this code:
GDALDataset* dataset = (GDALDataset*) GDALOpenEx("image.ecw", GDAL_OF_RASTER, NULL, NULL, NULL);
GDALRasterBand* band = dataset->GetRasterBand(1);
cv::Rect roi(x, y, w, h);
cv::Mat mat;
mat.create(roi.size(),CV_32F);
band->RasterIO( GF_Read, roi.x, roi.y, roi.width, roi.height, mat.data,
roi.width, roi.height, GDT_Float32, 0, 0);
You just have to be sure that OpenCV data type match the GDAL datatype and that ROI dimensions are ok for the raster size.
For more info it is good: enter link description here

To read ECW file using GDAL,its driver should be built into the gdal, maybe you should test the supported driver in opencv. If the author didn't add the ecw driver, then do it youself. Here is the page about gdal in OpenCV:http://code.opencv.org/issues/3725
OpenCV's code repository was moved to github, and I can't find this issue, but in github i find something related here.

Related

OpenCv read / write video color difference

I am trying to simply open a video with openCV, process frames and write the processed frames into a new video file.
My problem is that even if I don't process frames at all (just opening a video, reading frames with VideoCapture and writing them with VideoWriter to a new file), the output file appears more "green" than the input.
The code to do that can be found in any openCV tutorial, nothing special.
I use openCV c++ 4.4.0 on Windows 10.
I use openCV with ffmpeg through opencv_videoio_ffmpeg440_64.dll
The input video is mp4.
I write the output as a .avi with huffyuv codec :
m_video_writer.reset(new cv::VideoWriter(m_save_video_path.toStdString(), cv::VideoWriter::fourcc('H', 'F', 'Y', 'U'), // lossless compression
m_model->getFps(), cv::Size(m_frame_size.width(), m_frame_size.height())));
I tried many other codecs and the problem remains.
The difference in pixels is small, not constant in value but always varying in the same way : blue channel is lower, red and green are higher.
Strange fact : when I open both input or output video with opencv, the matrix are actually exactly the same. So I guess the problem is in the reading ??
Here are the properties of each video file, as exported with Windows Media Playre (MPC-HC).
VS
What should I investigate ?
Thx !!
Full code here (copying the first 100 frames of my video):
VideoCapture original("C:/Users/axelle/Videos/original.MP4");
int frame_height = original.get(CAP_PROP_FRAME_HEIGHT);
int frame_width = original.get(CAP_PROP_FRAME_WIDTH);
int fps = original.get(CAP_PROP_FPS);
VideoWriter output("C:/Users/axelle/Videos/output.avi", VideoWriter::fourcc('H', 'F', 'Y', 'U'),
fps, cv::Size(frame_width, frame_height));
int count = 0;
while (count < 100)
{
count++;
Mat frame;
original >> frame;
if (frame.empty())
{
break;
}
//imshow("test", frame);
//waitKey(0);
output.write(frame);
}
original.release();
output.release();
Note: the difference in colors can be seen in the imshow already.
There is a bug in OpenCV VideoCapture when reading video frames using FFmpeg backend.
The bug results a "color shift" when H.264 video stream is marked as BT.709 color standard.
The subject is too important to leave it unanswered...
The important part of the post, is reproducing the problem, and proving the problem is real.
The solution I found is selecting GStreamer backend instead of FFmpeg backend.
The suggested solution has downsides (like the need to build OpenCV with GStreamer support).
Note:
The problem is reproducible using OpenCV 4.53 under Windows 10.
The problem is also reproducible under Ubuntu 18.04 (using OpenCV in Python).
The issue applies both "full range" and "limited range" of BT.709 color standard.
Building synthetic video pattern for reproducing the problem:
We can use FFmpeg command line tool create a synthetic video to be used as input.
The following command generates an MP4 video file with H.264 codec, and BT.709 color standard:
ffmpeg -y -f lavfi -src_range 1 -color_primaries bt709 -color_trc bt709 -colorspace bt709 -i testsrc=size=192x108:rate=1:duration=5 -vcodec libx264 -crf 17 -pix_fmt yuv444p -dst_range 1 -color_primaries bt709 -color_trc bt709 -colorspace bt709 -bsf:v h264_metadata=video_full_range_flag=1:colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 bt709_full_range.mp4
The above command uses yuv444p pixel format (instead of yuv420p) for getting more pure colors.
The arguments -bsf:v h264_metadata=video_full_range_flag=1:colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 use Bitstream Filter for marking the H.264 stream as "full range" BT.709.
Using MediaInfo tool, we can view the following color characteristics:
colour_range: Full
colour_primaries: BT.709
transfer_characteristics: BT.709
matrix_coefficients: BT.709
Capturing the video using OpenCV:
The following C++ code grabs the first frame, and save it to 1.png image file:
#include "opencv2/opencv.hpp"
void main()
{
cv::VideoCapture cap("bt709_full_range.mp4");
cv::Mat frame;
cap >> frame;
cv::imwrite("1.png", frame);
cap.release();
}
We may also use the following Python code:
import cv2
cap = cv2.VideoCapture('bt709_full_range.mp4')
_, frame = cap.read()
cv2.imwrite('1.png', frame)
cap.release()
Converting bt709_full_range.mp4 into images sequence using FFmpeg:
ffmpeg -i bt709_full_range.mp4 -pix_fmt rgb24 %03d.png
The file name of the first "extracted" frame is 001.png.
Comparing the results:
The left side is 1.png (result of OpenCV)
The right side is 001.png (result of FFmpeg command line tool)
As you can see, the colors are different.
The value of the red color pixels of OpenCV are RGB = [232, 0, 3].
The value of the red color pixels of FFmpeg are RGB = [254, 0, 0].
The original RGB value is probably [255, 0, 0] (value is 254 due to colors conversion).
As you can see, the OpenCV colors are wrong!
Solution - selecting GStreamer backend instead of FFmpeg backend:
The default OpenCV release excludes GStreamer support (at least in Windows).
You may use the following instruction for building OpenCV with GStreamer.
Here is a C++ code sample that uses GStreamer backend for grabbing the first frame:
void main()
{
cv::VideoCapture cap("filesrc location=bt709_full_range.mp4 ! decodebin ! videoconvert ! appsink", cv::CAP_GSTREAMER);
cv::Mat frame;
cap >> frame;
cv::imwrite("1g.png", frame);
cap.release();
}
Result:
The left side is 1g.png (result of OpenCV using GStreamer)
The right side is 001.png (result of FFmpeg command line tool)
The value of the red color pixels of OpenCV using GStreamer are RGB = [254, 0, 1]. (blue is 1 and not zero due to colors conversion).
Conclusions:
Using GStreamer backend (instead of FFmpeg) backend seems to solve the "color shifting" problem.
OpenCV users need to be aware of the color shifting problem.
Let's hope that OpenCV developers (or FFmpeg plugin developers) fix the problem.

OpenCV imread 8BPP PNG image error

I am trying to read an 8BPP PNG image using imread() in OpenCV and copy it into a larger matrix. This is the code:
Mat subimage = imread((directory + file).toStdString(), IMREAD_COLOR);
subimage.copyTo(whole(Rect(rect.left(), rect.top(),
rect.width(), rect.height())));
I have tried other flags like IMREAD_ANYCOLOR, IMREAD_ANYDEPTH, IMREAD_GRAYSCALE and IMREAD_UNCHANGED. None of them seem to work (subimage remains empty).
I am getting the folowing error:
OpenCV Error: Assertion failed (!fixedSize()) in cv::_OutputArray::release, file ..\..\..\sources\modules\core\src\matrix.cpp, line 1619
I finally figured out the error. However, it has nothing to do with imread. I am downloading the images and was trying to read them before the download is complete.

In Dlib how do I save image with overlay?

I'm trying to modify Dlib's face detection example to save an image with detections to a file since I'm using a server without GUI. So far I have only figured how to save the image but not the overlay. How do I save both to the same file?
//win.add_overlay(dets, rgb_pixel(255,0,0));
save_png(img, "detected.png");
You can call draw_rectangle on the image before saving it.
Try this: dlib::draw_rectangle()
Example:
dlib::draw_rectangle(rect_image, rect, dlib::rgb_pixel(255, 0, 0), 1);

how to convert a jpg image to pgm format in cpp

I want to covert a .jpg image to a .pgm image.The image is being obtained from a tcp socket which has live streaming by a OPENCV program.
In matlab I used the imread function to do it. How do I do it in cpp?
I am working in linux platform. Is there any function to do it in OPENCV?
can anyone help?
regards,
shiksha
Yes.
In OpenCV, you can use imread() to load the JPG image, and then use imwrite() it to the PGM image (by using the CV_IMWRITE_PXM_BINARY format flag).
please look at OpenCV documentation for HighGui library functions cv::imread and cv::imwrite.
Read the jpg using cv::imread and resave it with cv::imsave using filename with proper extension.
http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#imread
http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#imwrite

converting a UYVY FFmpeg

I want to read and show a video using opencv. I've recorded with Direct-show, the Video has UYVY (4:2:2) codec, since opencv can't read that format, I want to convert the codec to an RGB color model, I readed about ffmpeg and I want to know if it's possible to get this done with it ? if not if you a suggestion I'll be thankful.
As I explained to you before, OpenCV can read some formats of YUV, including UYVY (thanks to FFmpeg/GStreamer). So I believe the cv::Mat you get from the camera is already converted to the BGR color space which is what OpenCV uses by default.
I modified my previous program to store the first frame of the video as PNG:
cv::Mat frame;
if (!cap.read(frame))
{
return -1;
}
cv::imwrite("mat.png", frame);
for(;;)
{
// ...
And the image is perfect. Executing the command file on mat.png reveals:
mat.png: PNG image data, 1920 x 1080, 8-bit/color RGB, non-interlaced
A more accurate test would be to dump the entire frame.data() to the disk and open it with an image editor. If you do that keep in mind that the R and B channels will be switched.