So I'm trying to access jpg image data that's stored in the computer's memory, but I'm only able to access the starting address of the data and the size of the data. The pointer to the beginning of the data is an uint8_t * and the size of the data is an uint32_t.
Using fwrite, I can write the data to a jpg file and display it properly, so I know the data is correct and exists. How can I directly store the jpg image data in a variable? Ultimately, I want to store it in an opencv Mat too.
I'm not sure what code to show, so if you want to see a specific part of it, just ask.
you know the resolution of the image? if so
to store it in an opencv Mat you can do
cv::Mat buf = cv::Mat(height, width, CV_8U, buff_ptr);
cv::Mat img = cv::imdecode(buf, CV_LOAD_IMAGE_COLOR);
How about this:
uint8_t *JPEG;
JPEG = malloc(sizeof(uint8_t) * size_var);
if(JPEG) {
memcpy(JPEG, your_pointer, size_var);
}
However, you do already have the data in a variable since you already have a pointer to it. :)
If you wanted to be really fancy you could build a struct that correctly formatted the header of a JPEG and then typecast the raw memory into the struct to better manipulate it.
If you have a variable of type uint8_t * that contains a pointer to it, you can access it just like an array.
uint8_t* my_pointer;
int my_len;
for (int i = 0; i < my_len; ++i)
cout << "The value of byte " << i
<< " of the data is " << my_pointer[i] << endl;
Related
I've c++ and OpenCV 3.1 and i separated the RGB three channels with these code :
Mat src = imread("original_image.jpg",CV_LOAD_IMAGE_COLOR);
Mat bgr[3] , bluemat ;
split(src,bgr);
bluemat = bgr[0];
std::cout << "bluemat.at<int>(0,1); : " << bluemat.at<int>(0,1) << '\n';
The strange thing is it print out a big number : 1415208581 , why is that ?
Isn't it suppose to be in 0-255 range ? why it is not ?
(expanding comment for search)
A feature of openCV is that the cv::Mat image type is a very simple object based on the original C version of the library.
The cv::Mat contains a field giving the pixel type but the data is stored simply as a block of memory bytes. You can use this block of memory to store and access pixels however you want. It makes it very flexible and easy to link with other libraries, but means you need to manually keep track of what the data is.
So data.at<int>(0,0) will extract the first pixel as if the data was ints (whatever int is on your platform), data.at<uchar> (0,0) will get the first pixel as a byte (which is generally what you want).
The main difference here is casting the memory byte to uchar vs int. What form the data you have depends on how you read it in. CV_LOAD_IMAGE_COLOR read the image as 16-bit/32-bit values. I cannot compile the code you gave me becuase of the memory issues that are created by converting that data to an int.
Now, if you use uchar, that will be solved. The problem however with the cout printing a character, has to do with the overload functions of <<
Mat src = imread("1.jpg", CV_LOAD_IMAGE_COLOR);
Mat bgr[3], bluemat;
split(src, bgr);
bluemat = bgr[0];
std::cout << "bluemat.at<uchar>(0,1); : " << (int)bluemat.at<uchar>(0, 1) << '\n';
What I changed was just to insert the typecast int. This issue is expanded here, but tells the output stream that this is a number, not a character.
I want to load an image in c++ opencv that comes from a postgresql database.
The image, jpg extension, is stored as a binary data (bytea type) in the base, that I can access thanks to libpqxx.
The problem is that I do not know how to convert the data into a cv::Mat instance. With a regular image I could use imread('myImage.jpg', ...), but in this case I cannot even load the database image in the data attribute of Mat because it is jpeg and not bmp.
Any idea ? Is there some opencv method I could use that could understand directly the binary data and convert it to the appropriate structure ? the imdecode() functions seems to be used for bitmap datas.
edit : Berak, using a vector the imdecode function returns null Matrice What happens "If the buffer is too short or contains invalid data, the empty matrix/image is returned." Here is the code :
pqxx::result r=bdd::requete("SELECT image FROM lrad.img WHERE id=3",1);//returns the bytea image in r[0]["image"]
const char* buffer=r[0]["image"].c_str();
vector<uchar>::size_type size = strlen((const char*)buffer);
vector<uchar> jpgbytes(buffer, buffer+size);
Mat img = imdecode(jpgbytes, CV_LOAD_IMAGE_COLOR);
//jpgbytes.size()=1416562 img.size()=[0 x 0]
What am I missing ?
still, use imdecode . it can handle png,jpg,bmp,ppm,webp,jp2,exr, but no gif.
vector<uchar> jpgbytes; // from your db
Mat img = imdecode(jpgbytes);
(you should do the same for bmp or any other supported formats, don't mess with Mat's raw data pointers!)
Ok I have the process to convert a bytea data to a cv::Mat, here is the code.
inline int dec(uchar x){ //convert uchar to int
if (x>='0'&&x<='9') return (x-'0');
else if (x>='a'&&x<='f') return (x-'a'+10);
else if (x>='A'&&x<='F') return (x-'A'+10);
return 0;
}
cv::Mat bytea2Mat(const pqxx::result::field& f){
const char* buffer=f.c_str();
vector<uchar>::size_type size = strlen((const char*)buffer);
vector<uchar> jpgbytes(size/2-1);
for (size_t i=0; i!=size/2-1;i++) {
jpgbytes[i]=(dec(buffer[2*(i+1)])<<4)+dec(buffer[2*(i+1)+1]);
}
cout <<size/2<<";"<<jpgbytes.size()<<endl;
return imdecode(jpgbytes, CV_LOAD_IMAGE_COLOR);
}
The bytea output is encrypted as a char* looking like "\x41204230", for an original input string of "a b0" in hexa form. (the \x may not be present according to the data input)
to get the original data you have to calculate the original input from the two char, ('4','1'= 0x41=65). The vector is half the size of the char*.
edit: In trying to give a straight forward example of the problem it appears I left out what was causing the real issue. I have modified the example to illustrate the problem.
I am trying to use opencv to perform operations on a cv::Mat that is composed of external data.
Consider this example:
unsigned char *extern_data = new unsigned char[1280*720*3];
cv::Mat mat = cv::Mat(1280, 720, CV_8UC3, extern_data); //Create cv::Mat external
//Edit - Added cv::imdecode
mat = cv::imdecode(mat,1);
//In real implementation it would be mat = cv::imdecode(image,'1')
// where image is a cv::Mat of an image stored in a mmap buffer
mat.data[100] = 99;
std::cout << "External array: " << static_cast<int>(extern_data[100]) << std::endl;
std::cout << "cv::Mat array: " << static_cast<int>(mat.data[100]) << std::endl;
The result of this is:
> External array: 0
> cv::Mat array: 100
It is clear this external array is not being modified, therefore new memory is being allocated for the cv::Mat array. From my understanding this was not suppose to happen! This should have caused no copy operation, and mat.data should be a pointer to extern_data[0].
What am I misunderstanding?
So far the way I have got my program to work is to use std::copy. I am still wondering if there is a way to assign the result of cv::imdecode() directly to the external data.
Currently I am using
unsigned char *extern_data = new unsigned char[1280*720*3];
cv::Mat mat = cv::Mat(1280, 720, CV_8UC3, extern_data); //Create cv::Mat external
mat = cv::imdecode(mat,1);
std::copy(mat.data, mat.data + 1280*720*3, extern_data);
I just wish i could figure out how to assign the result of cv::imdecode() directly to extern_data without the additional std::copy line!
I have a image buffer stored as a linear array[640*480] of unsigned integer type, and I want to save this array as a bitmap image which can be viewed. I have captured an image from my camera and retrieved its image buffer from a GigE cable using in c++ code. So please tell me how to write an integer array of RGB values to Bitmap in C++ along with the header files required. I have stream buffer as
if (Result.Succeeded())
{
// Grabbing was successful, process image
cout << "Image #" << n << " acquired!" << endl;
cout << "Size: " << Result.GetSizeX() << " x "
<< Result.GetSizeY() << endl;
// Get the pointer to the image buffer
const unsigned int *pImageBuffer = (int *) Result.Buffer();
the pImagebuffer is the image Buffer and please ignore the Functions as they belong to a custom compiler. I just want to convert the RGB values to bitmap image and then save it
also the pImageBuffer is giving me the R=G=B as photo is mono chrome.
Save the pixel data together with a simple BMP-file header, appropriately initialized. See the format description here.
CompVision once again, I'm working with jpeg images in my application. Just because I'm a bit familiar with MFC and ATL, I used CImage to access pixel values.
For my needs I calculate brightness matrix for the image during initialization. Function goes like this (Image is the name of my own class, unimportant, bright is float[][]):
void Image::fillBrightnessMatrix(){
COLORREF val;
for(int i=0;i<width;i++){
for(int j=0; j<height;j++){
val=src.GetPixel(i,j);
bright[i][j]=rgb_to_L(val);
}
}
}
Where src is an instance of CImage class, rgb_to_L - some function that calculates brightness of the color.
Examining the performance of my app, I discovered that GetPixel is the most expensive operation, and it significantly (really, ~700 times slower than any other operation) slows down the whole initializing of image. The question is, which library can you suggest for fast access to single pixel values? I don't need any other operations but loading jpeg image and accessing single pixels. Performance is important, because my application works with set of ~3000 images and I can't wait for hours to get results.
Use CBitmap::GetBits() to get a raw pointer to the pixel data. You can now directly party on the pixels without going through the expensive GetPixel() method. There are a number of things you need to be careful with when you do this:
You have to use CBitmap::GetPitch() to calculate the offset to the start of a line. The pitch is not the same as the width.
Lines in the bitmap are stored upside-down
You have to deal with the pixel format yourself. A 24bpp image stores 3 bytes per pixel. An indexed format like 8bpp requires looking up the color in the color table. 32bpp is the easy one, 4 bytes per pixel and the pitch is always the same as the width.
I always recommend OpenCV.
This is a humble code snippet to get you started:
IplImage* pRGBImg = cvLoadImage("c:\\test.jpg", CV_LOAD_IMAGE_UNCHANGED);
if (!pRGBImg)
{
std::cout << "!!! cvLoadImage failed !!!" << std::endl;
exit(1);
}
int width = pRGBImg->width;
int height = pRGBImg->height;
int bpp = pRGBImg->nChannels;
for (int i=0; i < width*height*bpp; i+=bpp)
{
if (!(i % (width*bpp))) // print empty line for better readability
std::cout << std::endl;
std::cout << std::dec << "R:" << (int) pRGBImg->imageData[i] <<
" G:" << (int) pRGBImg->imageData[i+1] <<
" B:" << (int) pRGBImg->imageData[i+2] << " ";
}
You should probably extract the jpeg to raw data, then access the raw data instead of GetPixel.