Display Qbytearray as Image in QT 5.12.9 version - c++

I am reading the QByteArray using QTcpSocket and converting the array into the cvMat image. to display the image using imshow().but i am getting gray image.
code is as follows.
//array ->QBytearray (received from socket)
cv::Mat img,img1;
img.cols=320;
img.rows=240;
img = cv::Mat(240,320, CV_8UC1,array.data());
cv::cvtColor(img, img, CV_GRAY2RGB); //
cv::imshow("image display",img);
cv::waitKey(5000);
after cvtColour() function also its not converting into colour image.
Thanks in advance.

This is the way to modify channels separately:
img = cv::Mat(240,320, CV_8UC1,array.data());
cv::Mat img1;
cv::divide(img,cv::Scalar(2),img1);
std::vector<cv::Mat> channels;
channels.push_back(img);
channels.push_back(img1);
channels.push_back(img);
cv::merge(channels, img);
cv::imshow("image display",img);
cv::waitKey(5000);

Related

Converting cv::mat to QImage

like the title says I am trying to convert a cv::mat to a QImage. What I am doing is using the equalizeHist() function on the mat and then converting it to a QImage to display in widget window in Qt. I know the mat works and loads the image correctly because the equalized image will show in the new window with imshow(), however when converting this mat to a QImage, I can not get it to display in the window. I believe the problem is with the conversion from the mat to QImage but cant find the issue. Below is a part of my code snippet.
Mat image2= imread(directoryImage1.toStdString(),0);
//cv::cvtColor(image2,image2,COLOR_BGR2GRAY);
Mat histEquImg;
equalizeHist(image2,histEquImg);
imshow("Histogram Equalized Image 2", histEquImg);
//QImage img=QImage((uchar*) histEquImg.data, histEquImg.cols, histEquImg.rows, histEquImg.step, QImage::Format_ARGB32);
imageObject= new QImage((uchar*) histEquImg.data, histEquImg.cols, histEquImg.rows, histEquImg.step, QImage::Format_RGB888);
image = QPixmap::fromImage(*imageObject);
scene=new QGraphicsScene(this); //create a frame for image 2
scene->addPixmap(image); //put image 1 inside of the frame
ui->graphicsView_4->setScene(scene); //put the frame, which contains image 3, to the GUI
ui->graphicsView_4->fitInView(scene->sceneRect(),Qt::KeepAspectRatio); //keep the dimension ratio of image 3
No errors occur and the program doesnt crash.
Thanks in advance.
Your problem is the conversion of the QImage to cv::Mat, when using the flag 0 in cv::imread implies the reading is grayscale, and you are using the conversion with the format QImage::Format_RGB888. I use the following function to make the conversion of cv::Mat to QImage:
static QImage MatToQImage(const cv::Mat& mat)
{
// 8-bits unsigned, NO. OF CHANNELS=1
if(mat.type()==CV_8UC1)
{
// Set the color table (used to translate colour indexes to qRgb values)
QVector<QRgb> colorTable;
for (int i=0; i<256; i++)
colorTable.push_back(qRgb(i,i,i));
// Copy input Mat
const uchar *qImageBuffer = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage img(qImageBuffer, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8);
img.setColorTable(colorTable);
return img;
}
// 8-bits unsigned, NO. OF CHANNELS=3
if(mat.type()==CV_8UC3)
{
// Copy input Mat
const uchar *qImageBuffer = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage img(qImageBuffer, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
return img.rgbSwapped();
}
return QImage();
}
After that I see that you have misconceptions of how QGraphicsView and QGraphicsScene work when commenting: put the frame, which contains image 3, to the GUI, with ui->graphicsView_4->setScene(scene); you are not setting a frame but a scene, and the scene should only be set once and preferably in the constructor.
// constructor
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
So when you want to load the image just use the scene:
cv::Mat image= cv::imread(filename.toStdString(), CV_LOAD_IMAGE_GRAYSCALE);
cv::Mat histEquImg;
equalizeHist(image, histEquImg);
QImage qimage = MatToQImage(histEquImg);
QPixmap pixmap = QPixmap::fromImage(qimage);
scene->addPixmap(pixmap);
ui->graphicsView->fitInView(scene->sceneRect(), Qt::KeepAspectRatio);
The complete example can be found in the following link.

QImage to cv::Mat convert strange behavior in comparison with imread

I have to transform QImage to cv::Mat, if I use technique described in similar topics, I receive different numbers of contours (7--8) and strange result matrix, but if I do
QImage im;
im.save ("tmp.bmp");
cv::Mat rImage;
rImage = cv::imread ("tmp.bmp", CV_LOAD_IMAGE_GRAYSCALE);
function findContours works fine and properly. What is the difference between these techniques and which way I can archive equal results between these approaches ?
Your code works for me.
int main(int argc, char *argv[]){
QImage img(QString("lena.bmp"));
QImage img2 = img.convertToFormat(QImage::Format_RGB32);
cv::Mat imageMat = qimage_to_cvmat_copy(img2, CV_8UC4);
cv::namedWindow("lena");
cv::imshow("lena", imageMat);
cv::waitKey(0);
}
cv::Mat qimage_to_cvmat_copy(const QImage &img, int format)
{
uchar* b = const_cast<uchar*> (img.bits ());
int c = img.bytesPerLine();
return cv::Mat(img.height(), img.width(), format, b, c).clone();
}
Make sure your Mat format is CV_8UC4 if your QImage format is Format_RGB32. You don't have to do a cvtColor or mixChannels.
All !
As mentioned above I used conversion QImage to cv::Mat as described here. My source code became something like this
QImage srcIm (argv[1]);
QImage img2 = srcIm.convertToFormat(QImage::Format_ARGB32);
Mat src_gray = QImageToCvMat (img2);
cvtColor (src_gray, src_gray1, CV_RGB2GRAY);
Mat bwimg = src_gray1.clone();// > 127;
vector<vector<Point> > contours;
findContours( bwimg, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE );
All works fine.

convert Qimage to cvMat 64FC3 format

i have searched a lot on the internet but i have only found how to convert Qimage to RGB format, i want to convert an Qimage to cv mat format CV_64FC3.
i have really bad results when i work with CV_8UC3
here is my code :
QImage myImage;
myImage.load("C://images//PolarImage300915163358.bmp");
QLabel myLabel;
myLabel.setPixmap(QPixmap::fromImage(myImage));
//myLabel.show();
cv::Mat image1 = QImage2Mat(myImage);
Mat img;
image1.convertTo(img, CV_64FC3, 1.0 / 255.0);
and here is the function that i used :
cv::Mat QImage2Mat(QImage const& src)
{
cv::Mat tmp(src.height(),src.width(),CV_8UC3,(uchar*)src.bits(),src.bytesPerLine());
cv::Mat result; // deep copy just in case (my lack of knowledge with open cv)
cvtColor(tmp, result,CV_BGR2RGB);
return result;
}
please help me i m new to both opencv and Qt
Not sure what you mean with bad results, but you are assuming that QImage also loads the image as OpenCV (BGR). In the documentation it tells you that they use ARGB.
So, knowing this you have 2 options:
Convert to QImage::Format_RGB888 the Qimage using the function convertToFormat and then this line cvtColor(tmp, result,CV_BGR2RGB); is not needed, since it will be already in RGB.
Use CV_8UC4 when creating the cv::Mat and then drop the first channel (channel alpha) using either split and join or mixchannels.
i have found what was going wrong, in fact, Qimage has a fourth channel for alpha so when you read the Qimage data you need to put it in CV_8UC4
here is the code :
Mat QImage2Mat(const QImage& src) {
cv::Mat mat = cv::Mat(src.height(), src.width(), CV_8UC4, (uchar*)src.bits(), src.bytesPerLine());
cv::Mat result = cv::Mat(mat.rows, mat.cols, CV_8UC3 );
int from_to[] = { 0,0, 1,1, 2,2 };
cv::mixChannels( &mat, 1, &result, 1, from_to, 3 );
return result;
}

Split frames obtained from video into separate channels

I am trying to read a video (mp4) frame by frame and then convert the frames from BGR to HSV.
I then want to split the HSV Mats into different channels (Hue, Saturation, Value).
this, however, does not work:
void colorize () {
VideoCapture cap("myFile.mp4");
Mat frame;
Mat frame2;
while (true) {
cap>>frame;
cvtColor(frame, frame2, CV_BGR2HSV);
Vector<Mat> channels;
split(frame2, channels);
}
}
The split-function gives the following error:
no matching function for call to ‘split(cv::Mat&, cv::Vector<cv::Mat>&)’
split(frame2, channels);
I have tried the exact same code outside of a loop with another image I had before transformed to hsv and it worked fine, so I assume the problem must be the looping.
Any ideas?
You're using cv::Vector, while instead you should use std::vector (note the lowercase v).
std::vector<Mat> channels; // std::vector, not cv::Vector
split(frame2, channels);

BGR to YCrCb resulting in gray images in OpenCV

I'm converting a BGR image to YCrCb and saving it in the disk; however, the output images are gray, how can I save the images to disk with color?
Here is just an example of how my code looks like:
Mat img = imread("...");
Mat img2;
cvtColor(img, img2, CV_BGR2YCrCb);
vector<Mat> planes;
split(imgColorConverted, planes);
imwrite(".../planes1.jpg", planes[0]);
imwrite(".../planes2.jpg", planes[1]);
imwrite(".../planes3.jpg", planes[2]);
When I open the saved images, it is gray. Is it possible to save the images as the following example that I found on Wikipedia (Wikipedia - YCbCr)?:
Thank you!
In you case, you save 1 channel pictures, so it's gray. In fact, what you should do is:
Mat img = imread("...");
Mat img2;
cvtColor(img, img2, CV_BGR2YCrCb);
vector<Mat> planes;
split(imgColorConverted, planes);
Mat* planes2 = new Mat[3];
Mat emptyMat(planes[0].size(), planes[0].type(), Scalar(0));
Mat Cr, Cb;
imwrite(".../planes1.jpg", planes[0]);
// Set Cr channel on R channel
planes2[0] = emptyMat;
planes2[1] = emptyMat;
planes2[2] = planes[1];
merge(planes2, 3, Cr);
imwrite(".../planes2.jpg", Cr);
// Set Cb channel on B channel
planes2[0] = planes[2];
planes2[1] = emptyMat;
planes2[2] = emptyMat;
merge(planes2, 3, Cb);
imwrite(".../planes3.jpg", Cb);