BGR to YCrCb resulting in gray images in OpenCV - c++

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);

Related

Display Qbytearray as Image in QT 5.12.9 version

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);

Opencv error: assertion failed in wrapPerspective

i'm trying to make an AR app, using aruco and Opencv (i'm a newbie). It detects aruco marker, and puts an image on it. I have tried to use wrapPerstective() function, however somethig is wrong, it returns Opencv error assertion failed ((m0.type() == cv_32f m0.type() == cv_64f) in wrapPerspective. Please give me a way to solve it
int main() {
cv::VideoCapture inputVideo;
inputVideo.open("gal.mp4");
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_50);
cv::Mat sq = imread("zhuz.jpg", CV_LOAD_IMAGE_UNCHANGED);
while (inputVideo.grab()) {
vector<Point2f> sqPoints;
vector<Point2f> p;
sqPoints.push_back(Point2f(0, 0));
sqPoints.push_back(Point2f(sq.cols, 0));
sqPoints.push_back(Point2f(sq.cols, sq.rows));
sqPoints.push_back(Point2f(0, sq.rows));
cv::Mat image, warp_matrix;
inputVideo.retrieve(image);
Mat cpy_img(image.rows, image.cols, image.type());
Mat neg_img(image.rows, image.cols, image.type());
Mat gray;
Mat blank(sq.rows, sq.cols, sq.type());
std::vector<int> ids;
std::vector<std::vector<cv::Point2f>> corners;
cv::aruco::detectMarkers(image, dictionary, corners, ids);
if (ids.size() > 0) {
p.push_back(corners[0][0]);
p.push_back(corners[0][1]);
p.push_back(corners[0][2]);
p.push_back(corners[0][3]);
Mat wrap_matrix = getPerspectiveTransform(sqPoints, p);
blank = Scalar(0);
neg_img = Scalar(0); // Image is white when pixel values are zero
cpy_img = Scalar(0); // Image is white when pixel values are zero
bitwise_not(blank, blank);
warpPerspective(sq, neg_img, warp_matrix, Size(neg_img.cols, neg_img.rows)); // Transform overlay Image to the position - [ITEM1]
warpPerspective(blank, cpy_img, warp_matrix, Size(cpy_img.cols, neg_img.rows)); // Transform a blank overlay image to position
bitwise_not(cpy_img, cpy_img); // Invert the copy paper image from white to black
bitwise_and(cpy_img, image, cpy_img); // Create a "hole" in the Image to create a "clipping" mask - [ITEM2]
bitwise_or(cpy_img, neg_img, image); // Finally merge both items [ITEM1 & ITEM2]
}
cv::imshow("out", image);
}
}

Add alpha channel to opencv Mat

Using the cv::imread I was able to reading the RGB image to cv::Mat (as below)
Mat picture = imread(fileName, -1);
Instead of reading, I tried to create an RGB image using the following code :
Mat arr1 = Mat(9, 9, CV_8UC1, &data1);
Mat arr2 = Mat(9, 9, CV_8UC1, &data2);
Mat arr3 = Mat(9, 9, CV_8UC1, &data3);
Mat pic;
vector<Mat> mk(3);
mk.at(0)=(arr1);
mk.at(1)=(arr2);
mk.at(2)=(arr3);
merge(mk,pic);
Will the Mat picture and Mat pic be equal?
As cv::imread has a flag of '-1' which indicates that 'Return the loaded image as is (with alpha channel)'. Which I am not able to understand and how do I match 'pic' to 'picture'?(Not picture to pic)
-1 Flag in cv::imread indicates that image will be loaded as it is including the alpha channel if present. So, if your image file has alpha channel, your picture(Mat) will be a CV_8UC4 type of image while your pic(Mat) is a 3 channel image. Hence, they won't be same in some cases. But if your picture(Mat) has only 3 channels and its B, G, R channels have same data as data1, data2, data3 respectively then your 'picture' and 'pic' will be same.

converting only a region of image to grayscale

I want to get an image in which only a region has color given a color image.
Mat img = imread("lena.jpg");
Rect roi = Rect(100, 100, 300, 300);// only this should be in color in output
Mat img_yuv;
cvtColor(img, img_yuv, CV_RGB2YUV);
vector<Mat> channels(3);
split(img_yuv, channels);
Mat Y = channels[0];
Mat U = channels[1];
Mat V = channels[2];
// create mask
Mat mask = Mat::zeros(Y.size(), Y.type());
rectangle(mask, roi, Scalar(1), CV_FILLED);
// merging channels
channels[0] = Y;
channels[1] = U.mul(mask)+(Scalar::all(1)-mask).mul(Y);
channels[2] = V.mul(mask)+(Scalar::all(1)-mask).mul(Y);
Mat img_yuv_out, img_out;
merge(channels, img_yuv_out);
cvtColor(img_yuv_out, img_out, CV_YUV2RGB);
imshow("masked_color", img_out);
imshow("lena", img);
with the above opencv code here are my imput and output images respectively.
In the roi it works fine but rest of image doesn't look like a grayscale image(not exactly as we still have 3 channels.
You could try this:
get a copy of the image, and convert it to 3-channel grayscale (I don't know if you need to convert the grayscale explicitly back to (colored) RGB...)
get a Mat for the ROI you want to have the colors in, once for the grayscale copy and once for the original color image
assign/copy the color image ROI to the grayscale image ROI
Indeed, it's exactly as #AndreyKamaev suggests:
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
int main() {
char const * const fname_in = "lena.jpg";
char const * const fname_out = "lena_out.jpg";
cv::Mat img = cv::imread(fname_in, CV_LOAD_IMAGE_COLOR);
cv::Mat tmp;
cv::cvtColor(img, tmp, CV_BGR2GRAY);
cv::cvtColor(tmp, tmp, CV_GRAY2BGR);
cv::Rect roi(100, 100, 300, 300);
img(roi).copyTo(tmp(roi));
img = tmp;
cv::imwrite(fname_out, img);
}
Output image:
Basically the same as #moooeeeep suggests:
Mat tmp;
cvtColor(img, tmp, COLOR_BGR2GRAY);
cvtColor(tmp, tmp, COLOR_GRAY2BGR);
img(roi).copyTo(tmp(roi));
img = tmp;
To convert roi into grayscale in python you can
Convert the roi to gray
Replace roi by merging the gray, such that [gray, gray, gray] inplace of BGR
Now the roi is gray.
image = cv2.imread(image.jpg')
h, w, _ = image.shape
r, c, s = h//4, w//4, min(h,w)//2
gray_portion = cv2.bitwise_not(cv2.cvtColor(image[r:r+s, c:c+s], cv2.COLOR_BGR2GRAY))
merged = cv2.merge([gray_portion, gray_portion, gray_portion]) #IMPORTANT
image[r:r+s, c:c+s] = merged
cv2.imshow(image)
For those who want to the other way round :-)
Mat tmp;
cvtColor(img, tmp, COLOR_BGR2GRAY);
cvtColor(tmp, tmp, COLOR_GRAY2BGR);
tmp(roi).copyTo(img(roi));
tmp = img;

cvBlob/Opencv: Why is my output variable empty?

When doing:
IplImage blobimg = image;
IplImage *labelImg=cvCreateImage(cvGetSize(&blobimg), IPL_DEPTH_LABEL, 1);
IplImage *test=cvCreateImage(cvGetSize(&blobimg), IPL_DEPTH_8U, 3);
unsigned int result=cvLabel(&blobimg, labelImg, blobs);
cvRenderBlobs(labelImg, blobs, &blobimg,test,CV_BLOB_RENDER_BOUNDING_BOX);
Mat imgMat(test);
imshow("Depth", imgMat);
I notice that my test variable is empty :
I think I have to do this instead:
cvRenderBlobs(labelImg, blobs, &blobimg,&blobimg,CV_BLOB_RENDER_BOUNDING_BOX);
But cvRenderBlobs destImg has to have 3 channels and IPL_DEPTH_8U and my image has only 1 channel since it's a gray image.
Can someone tell me why this is and how I can fix this ?
Edit
Where image comes from:
Mat *depthImage = new Mat(480, 640, CV_8UC1, Scalar::all(0));
Mat image = *depthImage;
Will guess here but not too many times I've seen instances of IplImages that are not actually pointers. Are you sure that image, wherever it's coming from, isn't also a pointer to an IplImage struct?
IplImage *blobimg = image;
I use this portion of code in my project and it works, see if it can help:
//BYTE* blobMap = ... blobMap holds an image
CvMat mat = cvMat( HEIGHT, WIDTH, CV_8UC1, blobMap);
IplImage *img = cvCreateImage(cvSize(HEIGHT,WIDTH), IPL_DEPTH_8U, 1);
cvGetImage(&mat, img);
cvThreshold(img, img, 10, 255, CV_THRESH_BINARY);
IplImage *labelImg = cvCreateImage(cvGetSize(img),IPL_DEPTH_LABEL,1);
CvBlobs blobs;
unsigned int result = cvLabel(img, labelImg, blobs);
cvFilterByArea(blobs, 1000, 1680*HEIGHT);
IplImage *imgOut = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3);
cvRenderBlobs(labelImg, blobs, img, imgOut);
cvNamedWindow("test", 1);
cvShowImage("test", imgOut);
cvWaitKey(0);
cvDestroyWindow("test");
I also don't like the way you pass the Mat to an IplImage, are you sure that your input image (blobimg) is ok?