disable JPEG compression in openCV

Hello

I use openCV for steganography analysis (educationol purpose). I load an image (say 300Kb) and edit it's pixels:

BYTE *data = (BYTE*)img->imageData;
//do some changes

then, when going to save the data[] array:
cvSaveImage("c:\\result.jpg", img);

result is compressed (like 20Kb). I dont want JPEG compression, I want data[] array be saved excatly in result.jpg. I googled and found that I can save like this:
int p[3] = {1,100,0};
!cvSaveImage("c:\\result.bmp", img, p);
//code from http://stackoverflow.com/questions/801054/opencv-cvsaveimage-jpeg-compression-factor

but could not use third parameter as I want. I change second parameter but always there is a compression.

so, I want one of these:
1- my question's answer :)
2- recommend a jpeg library that doesn't compress. but please recommend just if you have experience and know that doesn't do compression.
3- any applicable idea that solves my problem

thanks
regards
LVL 17
CSecurityAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

davesgonebananasCommented:
JPEG is a form of lossy" compression. If you want to save an uncompressed, or losslessly compressed, image use a different file format.  BMP, PNG and TIFF are formats that support either uncompressed or losslessly compressed data.

If you want to save the RAW data without any header or file format information then you can simply use standard C/C++ file output functions.


FILE *f = fopen("image.raw", "w");
fwrite(img, 1, sizeof(img), f);
fclose(f);

Open in new window

CSecurityAuthor Commented:
no brother. I should not change the file format. if it's JPG, so the result must be JPG as well. I don't mind jpg compresses or not. I open a jpg (maybe comressed o not), edit its pixels and then when going to save it, save the pixels exactly in my byte array. I dont want compression for my data array. it is what i want.

I found a cpp file in opencv diretory: x:\openCV2.1\src\highgui\grfmt_jpeg.cpp

in this file, there is this function:
bool  JpegEncoder::write( const Mat& img, const vector<int>& params )

and in this function:
jpeg_create_compress(&cinfo);
jpeg_start_compress( &cinfo, TRUE );

I found these lines but if I edit them, I should recompile .lib files too. so, maybe I should compile the .lib files (dunno exactly how).

I appriciate any idea

thanks
davesgonebananasCommented:
>> no brother. I should not change the file format. if it's JPG, so the result must be JPG as well. I don't mind jpg compresses or not. I open a jpg (maybe comressed o not), edit its pixels

A JPEG is a compressed representation of a pixmap image.  When you "open" a JPEG file, the compressed information is converted into an in memory bitmap representation; that is, each pixel is represented by a certain location in the array.  At this point it's no longer in JPEG format.  You are free to modify this array, but to save the image back as a JPEG you must re-compress it.

No matter what JPEG library you use, you cannot "edit the pixels" in JPEG data, because the concept of a pixel doesn't really exist in a JPEG.  It's more a sort of matrix of cosine functions.  Trying to edit that in any meaningful sort of way would require a very good understanding of the mathematics involved indeed!

>> ... and then when going to save it, save the pixels exactly in my byte array.

You can write the array to disk using the code I already gave you.  But it won't be a JPEG image because your array is not in JPEG format.

You can not both "save the pixels exactly in my byte array" and keep the original file format because your byte array is not in the original format.  If your byte array was in the original format, you wouldn't need a JPEG library anyway.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Become a Certified Penetration Testing Engineer

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

CSecurityAuthor Commented:
well brother, you are right. when openCV loads a JPG, converts and decompreses it in readable format in memory. so, I can change it pixels. then, when going to save the file, as it is JPG, compresses it and in compression some pixels vary from original. you are right but I can not accept it because of 3 things:
1- I had a bmp file. opened it in photoshop, converted it to jpg and selected maximum quality. then opened jpg in photoshop and converted it to bmp. md5 of converted bmp and the originall bmp file the same. so, there is a way to save a jpg without altering the pixels.
2- there are so many applications that use jpg for steganography. when you  work on steganography, and change a pixel -say 0xFE- to 0xFF, it must be save exactly in this value. it should not change. there are so many applications that do successfully in jpg format. so, what they do?
3- I found in openCV source code (x:\openCV2.1\src\highgui\grfmt_jpeg.cpp) this function:
bool  JpegEncoder::write( const Mat& img, const vector<int>& params )

and in this function, there is these lines:
struct jpeg_compress_struct cinfo;
jpeg_create_compress(&cinfo);
jpeg_start_compress( &cinfo, TRUE );

I think, if I comment these lines, I'll do what I want. but I need to compile .lib files again usgin CMake. maybe work, maybe not. what do you think?

I want to know, what you think

thank you very much, for your comments
Regards
clockwatcherCommented:
See the following:  http://stackoverflow.com/questions/801054/opencv-cvsaveimage-jpeg-compression-factor

If you use the C++ library (rather than the C one), cv::imwrite allows you to pass a vector of params that let you set the compression level:  http://opencv.willowgarage.com/documentation/cpp/reading_and_writing_images_and_video.html#cv-imwrite
CSecurityAuthor Commented:
i'm so sorry, dont want to be rude but you gave me links that I found them before ask in here. actually, the first link compresses anyway, even you set quality to 100. I tested when found this link.

second link is the same. you pass vector or filename, doesn't matter, it compresses unfortunately.

thank you very much clockwatcher. if you have any idea, please share with me.

I think the only way is recompile openCV libraries by removing these lines:
struct jpeg_compress_struct cinfo;
jpeg_create_compress(&cinfo);
jpeg_start_compress( &cinfo, TRUE );

I recompiled them successfully but my application gives error when going to link with it. any idea?

sincerely yours
davesgonebananasCommented:
1)  Your test was invalid for one of several reasons.  Ensure you are using a BMP that has enough complexity for the JPEG algorithm to actually affect the image, and that it did not originate from a JPEG source image.  Otherwise your entire test is invalid.

2)  Yes, there is steganography software available that works with JPEG files. They work by modulating the quantization indices in the DCT.

"The JPEG encoding procedure divides an image into 8x8 blocks of pixels
in the YCbCr colorspace.  Then they are run through a discrete cosine
transform (DCT) and the resulting frequency coefficients are scaled to
remove the ones which a human viewer would not detect under normal
conditions.  If steganographic data is being loaded into the JPEG
image, the loading occurs after this step.  The lowest-order bits of
all non-zero frequency coefficients are replaced with successive bits
from the steganographic source file, and these modified coefficients
are sent to the Huffmann coder. "  - JSteg Documentation


marcie.bmp     9,337 kb     md5: 787444cd7a776da32a8038c1a5e588eb
marcie2.bmp    9,337 kb     md5: debb7ae6a64a4f3b2e9df2a39627b8ac

Open in new window

CSecurityAuthor Commented:
well, about test, maybe I was wrong. ok

so, what's your idea? do you think I should code jpeg compression myself and do my changes in compression?
davesgonebananasCommented:
Well, your existing method would work with a non-lossy compression codec, such as used by PNG, BMP or TIFF.
But in a lossy compression scheme, such as JPG or MP3, you would have to have a detailed understanding of the underlying mathematics.  

The example I gave from the JSteg documentation explains exactly how they go about inserting the source file into the image data stream.  In order to do this yourself you will need to modify the underlying algorithm at the source level.

I would suggest you start by taking a look at a good JPEG library, such as libjpeg (http://en.wikipedia.org/wiki/Libjpeg).

CSecurityAuthor Commented:
OMG! I totally forget to accept this thread. although my problem did not solved but I want to close thid thread. so, evilrix, please remove this thread from abandoned questions so I can accept your suggested answer.

good luck
regards
evilrixSenior Software Engineer (Avast)Commented:
This question has been classified as abandoned and is being closed as part of the Cleanup Program.  See my comment at the end of the question for more details.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.