openCV cvSaveImage() increases the size of image - c++

i am loading an image and just saving the same image but with a different name using cvSaveImage(). After saving the size of the newly saved image gets increased. can anyone tell me why and how to avoid it?? here is my code:
int main(){
IplImage* src = cvLoadImage("test.jpg", 0);
cvSaveImage("reTest.jpg", src);
return 0;
}
thanks.

There are different methods of compression and coding combined in JPEG.
Most likely your original image used a different compression/coding than standard openCV parametrization for cvSaveImage.
Try this:
IplImage* src = cvLoadImage("test.jpg", 0);
cvSaveImage("reTest.jpg", src);
IplImage* reSrc = cvLoadImage("reTest.jpg",0);
cvSaveImage("reTest2.jpg", reSrc);
if reTest.jpg and reTest2.jpg have the same size, openCV does not increase the filesize but just uses a different compression level or sth.
You would have to find out the compression level and coding of your original file and save it with these same parameters, maybe with a different library than openCV.

It is because of low JPEG compression factor used by default in OpenCV. Here is how to to pass custom compression factor - OpenCV cvSaveImage Jpeg Compression Factor .

Related

How to store images in c++ with Ximea

I have a superSpeed usb 3.0 Ximea camera and I'm trying to code an application with a Ximea camera that consists on computer vision and machine learning.
I've been able to alocate the frames captured by the camera in it's buffer but I can find the way to save those images or frames as an JPEG or BMP file. I don't know if it's just a command line in my script or I need some kind of libraries to do it.
The images are aquired using these commands:
#define EXPECTED_IMAGES 10
for (int images=0;images < EXPECTED_IMAGES;images++)
{
// getting image from camera
stat = xiGetImage(xiH, 5000, &image);
HandleResult(stat,"xiGetImage");
printf("Image %d (%dx%d) received from camera\n", images, (int)image.width, (int)image.height);
}
As I can extract the data from the images, I suppose that the frame is still in the buffer, but I can't figure out the way to save it as a JPEG or BMP file in the computer.
I would appreciate any help with the code.
Thank you!
Aha, saving the image. I think you might have gotten the answer by now.
But here is mine, and I hope this will be useful for anyone working with machine vision cameras.
I have been working with XIMEA for quite a while now. XIMEA API does not include any functions to save images from the buffer to hard drive. So, you need to write your own function or use some library to save out images. And I think, essentially it all comes down to whether it's RAW or compressed image and what kind of image format you want to save out. ie. BMP, JPEG, PNG, PGM, EXR ......
Let's make couple assumptions first.
Here I assume you want to save out 8bit per pixel RAW image having a resolution of 1024*1024. The size of the image will be 8bit * 1024 * 1024 = 8388608bit = 1048576btye ~= 1MB
By looking at your code, you are using XIMEA API in C++.
Okay...... Here are two ways I used most often to save out images from XIMEA.
Writing all the image pixels to a binary file with a proper header according to the format you want to save out. Here is an example saving a data to a PGM format image.
FILE *file;
char fileName = "example.pgm";
char *image;
int width = 1024;
int height = 1024;
int byte_per_pixel = 1;
int max_pixel_value = 255;
file = fopen (fileName , "w+bx");
if(file == NULL){
fprintf(stderr, "Cannot open %s\n", fileName);
return -1;
}
size_t n = 0;
n += fprintf(file, "P5\n# Comment goes here!\n%d %d\n%d\n", width, height, max_pixel_value);
n += fwrite(image, 1, width * height * byte_per_pixel, file);
fclose (fileToSave);
Saving image to PGM may seem easy but when you need to save an image having pixel depth higher than 8bit, you need to deal with endianness issue, since PGM big-endian format. Here is a link to Netpbm formats if you want to read more about it. https://en.wikipedia.org/wiki/Netpbm_format
And also, other formats may have way more complicated data structure then you cannot just simply put down a header. So, using an image library or OpenCV will be a lot less cumbersome.
The handy OpenCV imwrite. Since you are gonna deal with pixels, OpenCV is a good library to have. OpenCV is a powerful library helps you with manipulating matrixes easier than ever. And it comes with a lot of useful stuff like GPU accelerated OpenCV functions. Back to the topic, imwrite can save images to many formats. Here is an example I wrote to save RAW data to PNG format.
string fileName = "example.png";
char *image;
int width = 1024;
int height = 1024;
int byte_per_pixel = 1;
int max_pixel_value = 255;
cv::Mat img_raw = cv::Mat(height, width, CV_8UC1, image);
vector compression_params;
compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
compression_params.push_back(0);
cv::imwrite(PNGFileName, img_raw, compression_params);
imwirte will determine what kind of format you want to save out based on the filename extension. And just a couple lines of code. OpenCV saves out the image for you effortlessly. Here is a link to OpenCV documentation of imwirte, http://docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html?highlight=imwrite
I hope my answer can help you and others are wondering how to save out images.
to store images from XIMEA cameras I would recommend to use the OpenCV library
as it provides tools for storing both JPEG and BMP image formats. Please download
a short example that demonstrates the storing of several different data formats
from the camera to JPEG and BMP images. Download the archive with MSVC 2013 project and OpenCV3.0 binaries from here and use password SHWJGRAIHFLG for
extraction.
If you should have any other questions concerning XIMEA products, please visit
and register directly on the XIMEA customer support. Thank you.
Best regards,
XIMEA team

How to convert a labview image type to opencv image type (or Mat)?

I'm using LabView to acquire an image from a usb camera and then I want to process this image using openCV functions through a dll file (which is used in call function VI). Now I want to convert the image format that Labview produce to process it with opencv. How can I do so?
You can use the "IMAQ GetImagePixelPtr" to get the pointer on the image in LabView.
In the dll, you should be able to get it like this :
int function(unsigned __int8 *LVImagePointer, int lineWidth, int height, int width)
{
Mat image(height, width, CV_8UC1, LVImagePointer, lineWidth);
...
}
Using any of the available toolkits. Say, this one: https://www.ehe-lab.com/OpenCV_Wrapper.html
I found it is easy to use IMAQ ImageToArray for IMAGEand IMAQ GetImageSize for IMAGE_HEIGHT and IMAGE_WIDTH and pass these to the DLL. They are called this way:
cv::Mat src = cv::Mat(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC1, IMAGE);
It has the advantage that all operations on srccan be seen in Labview by converting the array you get out of the DLL back to an image.
I found out that it is complicated to keep the memory from leaking. I suggest you use a toolkit: http://ms-consultants.de/index.php/software/msc-image-processing/37-msc-image-processing-eng
They also offer to implement new functions if you need more.

How to reduce image data size without changing its resolution?

I have tried couple of ways to reduce image size, but all failed. All similar to this:
//Mat frame...
vector<uchar> buff;
vector<int> params;
params.push_back(cv::IMWRITE_JPEG_QUALITY);
params.push_back(50); //Tried any value here, didn't change much
cv::imencode(".jpg", frame, buff, params);
Mat a = cv::imdecode(buff,1);
// a size is bigger than frame's
How can one reduce an image (Mat object) size without changing its resolution?
Edit:
I'm taking frames from camera and making video of them. Saving the frames as is makes a 1 minute video to weight about 100mb, which is totally unacceptable. How can I reduce the size (number of bytes) of each frame?
You need video compression like mpeg instead of image compression.
Another way might be to first blur the image and them encode to jpeg. Blurring will reduce entropy and so the image might compress better. Considering that you are not satisfied with the JPEG compression, to reduce image size I guess you can't escape reducing quality, blurring might not be the worst solution, it depends on your problem.

Does OpenCV 2 provide any api for fast fragment decoding of encoded image?

So I have 200k x 200k jpeg and png encoded images. I need to get a segment (say a Rectangle {( 1k, 1k); (2k, 1k)} ) of such encoded image not loading given image info ram entirely. Is such thing possible via OpenCV or there is some other crossplatfom library for such operations?
OpenCV doesn't have an API where you provide a Rect to imread(). I am not aware of any other library that has this feature.
Looking at the source in modules/highgui/src/grfmt_jpeg.cpp, it seems possible to add this feature by subclassing JpegDecoder and providing a bool readData( Mat& img, Point location ) as well as custom version of imread() to call it.

opencv read jpeg image from buffer

I have an unsigned char* buffer containing data of a jpeg image. I would like to display that image using c++ and opencv. If i do:
Mat img(Size(640, 480), CV_8UC3, data);
namedWindow("image", 1);
imShow("image", img);
I get a noisy mess of pixels.
I suppose it's because the data is jpeg (with a header). Because this works:
Mat imgbuf(Size(640, 480), CV_8UC3, data);
Mat img = imdecode(imgbuf, CV_LOAD_IMAGE_COLOR);
BUT I cannot use the imdecode function as it is from highgui.h which is based upon GTK 2, and in my project I use GTK 3.
So, how can I display the buffer data? Is there a way to decode the jpeg image other than imdecode in opencv, if that's the problem. I don't really want to have to rebuild opencv with Qt...
Any other suggestions?
(Using Linux)
I have seen many responses to this question around on the net saying that you should call libjpeg directly and bypass OpenCV's imread() routine.
This is NOT necessary! You can use imdecode() to decode a raw image buffer from memory. The way to do it is NOT intuitive, and isn't documented enough to help people trying to do this for the first time.
If you have a pointer/size for your raw file data (fread() directly from the .jpg, .png, .tif, files, etc...
int nSize = ... // Size of buffer
uchar* pcBuffer = ... // Raw buffer data
// Create a Size(1, nSize) Mat object of 8-bit, single-byte elements
Mat rawData( 1, nSize, CV_8UC1, (void*)pcBuffer );
Mat decodedImage = imdecode( rawData /*, flags */ );
if ( decodedImage.data == NULL )
{
// Error reading raw image data
}
That's IT!
Hope this helps someone in the future.
I have decompressed the JPEG image using libjpeg using the standard procedure described in the libjpeg API documentation under 'Decompression details'.
After having decompressed the data you can use it to construct the cv::Mat. Mind you, the decompressed image is in RGB format, whereas openCV uses a BGR format so a cvtColor() operation with format CV_RGB2BGR is needed.