How to get the bytes from opencv image matrix? - c++

If I have an opencv image that I read from a png file like this:
cv::Mat img = cv::imread("/to/path/test.png");
how do I get that image in bytes? I know using img.data returns an unsigned char* but that is not what I need. Any suggestions?

If I got your question right, you want, for example, a 250*250 image to return a 250*250 matrix so I would suggest using grey-scale instead of BGR
imgData = cv2.imread(path, 0)
I believe this is written in C++ like this
cv::Mat img = cv::imread(file_name);//It returns a matrix object
cv::Mat graymat;
cvtColor(img, graymat,cv::COLOR_BGR2GRAY);

Related

C++/CLI Convert Bitmap to OpenCV Mat

I'm trying to develop a small C++/CLI wrapper around OpenCV for use in a C# application. I can't use Emgu since it's for a commercial application.
I'm facing a problem when I'm trying to convert from System.Drawing.Bitmap to OpenCV Mat.
I have the following code:
cv::Mat BitmapToMat(System::Drawing::Bitmap^ bitmap)
{
System::Drawing::Rectangle blank = System::Drawing::Rectangle(0, 0, bitmap->Width, bitmap->Height);
System::Drawing::Imaging::BitmapData^ bmpdata = bitmap->LockBits(blank, System::Drawing::Imaging::ImageLockMode::ReadWrite, System::Drawing::Imaging::PixelFormat::Format24bppRgb);
cv::Mat cv_img(cv::Size(bitmap->Width, bitmap->Height), CV_8UC3, bmpdata->Scan0.ToPointer(), cv::Mat::AUTO_STEP);
bitmap->UnlockBits(bmpdata);
return cv_img;
}
I'm using it in cpp file to test out the generated Mat like this:
Mat image = BitmapToMat(templateImage);
cv::imwrite("some2.jpg", image);
But the image produced is completely distorted (see images)
INPUT BITMAP IMAGE
RESULT MAT IMAGE SAVED TO FILE
Windows bitmaps are padded. You want to calculate "width in bytes" of the bitmap row, and supply that instead of cv::Mat::AUTO_STEP:
int wb = ((bitmap->Width * 24 + 31) / 32) * 4;
cv::Mat cv_img(cv::Size(bitmap->Width, bitmap->Height),
CV_8UC3, bmpdata->Scan0.ToPointer(), wb);

Opencv c++ resize function: new Width should be multiplied by 3

I am programming in Qt environment and I have a Mat image with size 2592x2048 and I want to resize it to the size of a "label" that I have. But when I want to show the image, I have to multiply the width by 3, so the image is shown in its correct size. Is there any explanation for that?
This is my code:
//Here I get image from the a buffer and save it into a Mat image.
//img_width is 2592 and img_height is 2048
Mat image = Mat(cv::Size(img_width, img_height), CV_8UC3, (uchar*)img, Mat::AUTO_STEP);
Mat cimg;
double r; int n_width, n_height;
//Get the width of label (lbl) into which I want to show the image
n_width = ui->lbl->width();
r = (double)(n_width)/img_width;
n_height = r*(img_height);
cv::resize(image, cimg, Size(n_width*3, n_height), INTER_AREA);
Thanks.
The resize function works well, because if you save the resized image as a file is displayed correctly. Since you want to display it on QLabel, I assume you have to transform your image to QImage first and then to QPixmap. I believe the problem lies either in the step or the image format.
If we ensure the image data passed in
Mat image = Mat(cv::Size(img_width, img_height), CV_8UC3, (uchar*)img, Mat::AUTO_STEP);
are indeed an RGB image, then below code should work:
ui->lbl->setPixmap(QPixmap::fromImage(QImage(cimg.data, cimg.cols, cimg.rows, *cimg.step.p, QImage::Format_RGB888 )));
Finally, instead of using OpenCV, you could construct a QImage object using the constructor
QImage((uchar*)img, img_width, img_height, QImage::Format_RGB888)
and then use the scaledToWidth method to do the resize. (beware thought that this method returns the scaled image, and does not performs the resize operation to the image per se)

Transform a YUV420p QVideoFrame into grayscale OpenCV mat

I've created a filter extending QAbstractVideoFilter and
QVideoFilterRunnable and I've overrided the
QVideoFrame run(QVideoFrame* input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags)`
method
The problem is that QVideoFrame format is Format_YUV420P and has no handle. I need to convert it into a CV_8UC1 in order to use OpenCV algorithms.
Which is the best way to accomplish this?
First you need to create a cv::Mat which has an API for initializing using data pointer as:
cv::Mat img = cv::Mat(rows, cols, CV_8UC3, input.data/*Change this to point the first element of array containing the YUV color info*/)
Now since the img is initialized with YUV color data, you may use various cvtColor modes to convert the YUV mat to other formats, for converting it to gray-scale you may try:
cv::Mat gray;
cv::cvtColor(img, gray, cv::COLOR_YUV2GRAY_I420);

Viewing 8 bit RAW image file in openCV

I have a raw file which contains a header of 5 bytes containing the number of rows and columns in first two bits each . The 5th byte contains the number of bits for each pixel in the image which is 8 bits in all cases. The image data follows after that.
Since I am new to openCV, i want to ask how to view this RAW image file as an greyscale image using C++?
I know how to read binary data in C++ and have stored the image as a 2-D unsigned char array (since each pixel is 8 bit).
Can anyone please tell me how to view this data as image using openCV ?
I am using the below code , but getting a completely weird image :
void openRaw() {
cv::Mat img(numRows, numCols,CV_8U,&(image[0][0]));
//img.t();
cv::imshow("img",img);
cv::waitKey();
}
Any help will be greatly appreciated.
Thanks,
Rohit
You have to convert it to an IplImage.
If you want to see it as a pure grey-scale image, its actually rather easy.
Example code I use in one application:
CvSize mSize;
mSize.height = 960;
mSize.width = 1280;
IplImage* image1 = cvCreateImage(mSize, 8, 1);
memcpy( image1->imageData, rawDataPointer, sizeOfImage);
cvNamedWindow( "corners1", 1 );
cvShowImage( "corners1", image1 );
At that point you have a valid IplImage, which you can then display. (last 2 lines of code display it)
If the image is bayer-tiled, you will have to convert to RGB.
c++ notation:
cv::Mat img(rows,cols,CV_8U,ptrToDat);
cv::imwhow("img",img);
cv::waitkey();
*data should be saved columwise, otherewise use:
cv::Mat img(cols,rows,CV_8U,ptrToDat);
img=img.t();
cv::imwhow("img",img);
cv::waitkey();

Convert RGB to Black & White in OpenCV

I would like to know how to convert an RGB image into a black & white (binary) image.
After conversion, how can I save the modified image to disk?
AFAIK, you have to convert it to grayscale and then threshold it to binary.
1. Read the image as a grayscale image
If you're reading the RGB image from disk, then you can directly read it as a grayscale image, like this:
// C
IplImage* im_gray = cvLoadImage("image.jpg",CV_LOAD_IMAGE_GRAYSCALE);
// C++ (OpenCV 2.0)
Mat im_gray = imread("image.jpg",CV_LOAD_IMAGE_GRAYSCALE);
2. Convert an RGB image im_rgb into a grayscale image: Otherwise, you'll have to convert the previously obtained RGB image into a grayscale image
// C
IplImage *im_rgb = cvLoadImage("image.jpg");
IplImage *im_gray = cvCreateImage(cvGetSize(im_rgb),IPL_DEPTH_8U,1);
cvCvtColor(im_rgb,im_gray,CV_RGB2GRAY);
// C++
Mat im_rgb = imread("image.jpg");
Mat im_gray;
cvtColor(im_rgb,im_gray,CV_RGB2GRAY);
3. Convert to binary
You can use adaptive thresholding or fixed-level thresholding to convert your grayscale image to a binary image.
E.g. in C you can do the following (you can also do the same in C++ with Mat and the corresponding functions):
// C
IplImage* im_bw = cvCreateImage(cvGetSize(im_gray),IPL_DEPTH_8U,1);
cvThreshold(im_gray, im_bw, 128, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
// C++
Mat img_bw = im_gray > 128;
In the above example, 128 is the threshold.
4. Save to disk
// C
cvSaveImage("image_bw.jpg",img_bw);
// C++
imwrite("image_bw.jpg", img_bw);
This seemed to have worked for me!
Mat a_image = imread(argv[1]);
cvtColor(a_image, a_image, CV_BGR2GRAY);
GaussianBlur(a_image, a_image, Size(7,7), 1.5, 1.5);
threshold(a_image, a_image, 100, 255, CV_THRESH_BINARY);
I do something similar in one of my blog postings. A simple C++ example is shown.
The aim was to use the open source cvBlobsLib library for the detection
of spot samples printed to microarray slides, but the images have to be
converted from colour -> grayscale -> black + white as you mentioned, in order to achieve this.
A simple way of "binarize" an image is to compare to a threshold:
For example you can compare all elements in a matrix against a value with opencv in c++
cv::Mat img = cv::imread("image.jpg", CV_LOAD_IMAGE_GRAYSCALE);
cv::Mat bw = img > 128;
In this way, all pixels in the matrix greater than 128 now are white, and these less than 128 or equals will be black
Optionally, and for me gave good results is to apply blur
cv::blur( bw, bw, cv::Size(3,3) );
Later you can save it as said before with:
cv::imwrite("image_bw.jpg", bw);
Simple binary threshold method is sufficient.
include
#include <string>
#include "opencv/highgui.h"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;
int main()
{
Mat img = imread("./img.jpg",0);//loading gray scale image
threshold(img, img, 128, 255, CV_THRESH_BINARY);//threshold binary, you can change threshold 128 to your convenient threshold
imwrite("./black-white.jpg",img);
return 0;
}
You can use GaussianBlur to get a smooth black and white image.