I am getting a float point image in the range of 0 to 1. I tried to display this float image in Qt using label but it didn't work.
I checked the QImage formats and found that Qt don't support float image. now i am trying it in this way..
QVector<QRgb> colorTable;
for (int i = 0; i < 256; i++)
colorTable.push_back(qRgb(i, i, i));
Mat img2;
DepthImg.convertTo(img2, CV_8UC1);
assert(img2.isContinuous());
QImage image = QImage((unsigned char*)(img2.data), DepthImg.cols, DepthImg.rows, QImage::Format_Indexed8);
image.setColorTable(colorTable);
ui.ThreeD->setPixmap(QPixmap::fromImage(image, Qt::AutoColor));
ui.ThreeD->setScaledContents(true);
qApp->processEvents();
this->ui.ThreeD->show();
Here "DepthImage" is a float point image.
Mat img2;
DepthImg.convertTo(img2, CV_8UC1);
assert(img2.isContinuous());
QImage image = QImage((unsigned char*)img2.data, img2.cols, img2.rows, img2.cols*3, QImage::Format_RGB888);
ui.ThreeD->setPixmap(QPixmap::fromImage(image, Qt::AutoColor));
ui.ThreeD->setScaledContents(true);
qApp->processEvents();
this->ui.ThreeD->show();
After executing it in both ways i am getting only a black image.
Can any body help me to solve this issue ?
You need scale image by factor 255.
You can do it by changing
DepthImg.convertTo(img2, CV_8UC1);
with
DepthImg.convertTo(img2, CV_8UC1, 255.0);
Related
I'm trying to change the brightness of an image by coverting it from BGR to LAB and changing the L parameter to L+brightness. It works to change the brightness but the output image is blue , why?
void MainWindow::BrightnessSlider(cv::Mat image)
{
cv::Mat image2;
cv::cvtColor(image,image2,cv::COLOR_BGR2Lab);
for (int i=0; i < image2.rows; i++)
{
for (int j=0; j < image2.cols; j++)
{
image2.at<cv::Vec3b>(i,j)[0] = cv::saturate_cast<uchar>(image2.at<cv::Vec3b>(i,j)[0] + brightness);
}
}
cv::cvtColor(image2,image2,cv::COLOR_Lab2BGR);
QImage imageupdate= QImage((const unsigned char*)(image2.data), image2.cols,image2.rows,QImage::Format_RGB888);
int w = ui->label->width();
int h =ui-> label->height();
ui->label->setPixmap(QPixmap::fromImage(imageupdate.scaled(w,h,Qt::KeepAspectRatio)));
}
The main problem here is that 3-channel color images in OpenCV use BGR memory layout, while in Qt they use RGB memory layout. That's why your image shown in QLabel looks "blue".
To fix the memory layout problem, you should change cv::COLOR_Lab2BGR to cv::COLOR_Lab2RGB in the second cv::cvtColor():
cv::cvtColor(image2, image2, cv::COLOR_Lab2RGB);
Or append .rgbSwapped() to imageupdate (note that imageupdate will not share memory block with image2):
QImage imageupdate = QImage((const unsigned char*)(image2.data),
image2.cols, image2.rows, QImage::Format_RGB888).rgbSwapped();
BTW, you can just use Mat::operator+(const Scalar&) to change the value for all pixels, the color conversion and for-loops are unnecessary:
cv::Mat image2 = image + cv::Scalar::all(brightness);
// convert BGR to RGB if you don't want to allocate additional memory
// for imageupdate with QImage::rgbSwapped():
cv::cvtColor(image2, image2, cv::COLOR_BGR2RGB);
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.
I have a question which i am unable to resolve. I am taking difference of two images using OpenCV. I am getting output in a seperate Mat. Difference method used is the AbsDiff method. Here is the code.
char imgName[15];
Mat img1 = imread(image_path1, COLOR_BGR2GRAY);
Mat img2 = imread(image_path2, COLOR_BGR2GRAY);
/*cvtColor(img1, img1, CV_BGR2GRAY);
cvtColor(img2, img2, CV_BGR2GRAY);*/
cv::Mat diffImage;
cv::absdiff(img2, img1, diffImage);
cv::Mat foregroundMask = cv::Mat::zeros(diffImage.rows, diffImage.cols, CV_8UC3);
float threshold = 30.0f;
float dist;
for(int j=0; j<diffImage.rows; ++j)
{
for(int i=0; i<diffImage.cols; ++i)
{
cv::Vec3b pix = diffImage.at<cv::Vec3b>(j,i);
dist = (pix[0]*pix[0] + pix[1]*pix[1] + pix[2]*pix[2]);
dist = sqrt(dist);
if(dist>threshold)
{
foregroundMask.at<unsigned char>(j,i) = 255;
}
}
}
sprintf(imgName,"D:/outputer/d.jpg");
imwrite(imgName, diffImage);
I want to bound the difference part in a rectangle. findContours is drawing too many contours. but i only need a particular portion. My diff image is
I want to draw a single rectangle around all the five dials.
Please point me to right direction.
Regards,
I would search for the highest value for i index giving a non black pixel; that's the right border.
The lowest non black i is the left border. Similar for j.
You can:
binarize the image with a threshold. Background will be 0.
Use findNonZero to retrieve all points that are not 0, i.e. all foreground points.
use boundingRect on the retrieved points.
Result:
Code:
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
// Load image (grayscale)
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
// Binarize image
Mat1b bin = img > 70;
// Find non-black points
vector<Point> points;
findNonZero(bin, points);
// Get bounding rect
Rect box = boundingRect(points);
// Draw (in color)
Mat3b out;
cvtColor(img, out, COLOR_GRAY2BGR);
rectangle(out, box, Scalar(0,255,0), 3);
// Show
imshow("Result", out);
waitKey();
return 0;
}
Find contours, it will output a set of contours as std::vector<std::vector<cv::Point> let us call it contours:
std::vector<cv::Point> all_points;
size_t points_count{0};
for(const auto& contour:contours){
points_count+=contour.size();
all_points.reserve(all_points);
std::copy(contour.begin(), contour.end(),
std::back_inserter(all_points));
}
auto bounding_rectnagle=cv::boundingRect(all_points);
I have image as follows:
I want to detect 5 dials for processing. Hough circles is detecting all other irrelevant circles. to solve this i created a plain image and generated absolute difference with this one. It gave this image:
I drew box around it and final image is:
My code is as follows:
Mat img1 = imread(image_path1, COLOR_BGR2GRAY);
Mat img2 = imread(image_path2, COLOR_BGR2GRAY);
cv::Mat diffImage;
cv::absdiff(img2, img1, diffImage);
cv::Mat foregroundMask = cv::Mat::zeros(diffImage.rows, diffImage.cols, CV_8UC3);
float threshold = 30.0f;
float dist;
for(int j=0; j<diffImage.rows; ++j)
{
for(int i=0; i<diffImage.cols; ++i)
{
cv::Vec3b pix = diffImage.at<cv::Vec3b>(j,i);
dist = (pix[0]*pix[0] + pix[1]*pix[1] + pix[2]*pix[2]);
dist = sqrt(dist);
if(dist>threshold)
{
foregroundMask.at<unsigned char>(j,i) = 255;
}
}
}
cvtColor(diffImage,diffImage,COLOR_BGR2GRAY);
Mat1b img = diffImage.clone();
// Binarize image
Mat1b bin = img > 70;
// Find non-black points
vector<Point> points;
findNonZero(bin, points);
// Get bounding rect
Rect box = boundingRect(points);
// Draw (in color)
rectangle(img1, box, Scalar(0,255,0), 3);
// Show
imshow("Result", img1);
Now the issue is i cant compare plain image with anyother iamge of different sizes. Any pointer to right direction will be very helpful.
Regards,
Saghir A. Khatr
Edit
My plain image is as follows
I want to create a standard sample plain image which can be used with any image to detect that portion...
Hi
I have read the openCV reference from this site and using the following code:
VideoCapture mCap;
Mat mcolImage, mbwImage;
mCap >> mcolImage; // New frames from the camera
cvtColor( mcolImage, mcolImage, CV_BGR2RGB);
cvtColor( mcolImage, mbwImage, CV_RGB2GRAY);
QImage colImagetmp( (uchar*)mcolImage.data, mcolImage.cols, mcolImage.rows, mcolImage.step,
QImage::Format_RGB888 ); //Colour
QImage bwImagetmp ( (uchar*)mbwImage.data, mbwImage.cols, mbwImage.rows, mbwImage.step,
QImage::Format_Indexed8); //Greyscale. I hope
ui.bwDisplay->setPixmap(QPixmap::fromImage(bwImagetmp));
ui.colDisplay->setPixmap( QPixmap::fromImage(colImagetmp ));
I'm trying to convert one of the output into greyscale. Unfortunately they're still both in colour and I can't see that I've missed a step somewhere.
Thanks for the help.
You need to explicitly set a gray color table for bwImagetmp:
QVector<QRgb> colorTable;
for (int i = 0; i < 256; i++) colorTable.push_back(qRgb(i, i, i));
bwImagetmp.setColorTable(colorTable);