Extract one colour channel from 4-dimensional cv::Mat - c++

I'm working with OpenCV for a while and experiment with the DNN extension. My model has the input shape [1, 3, 224, 244] with pixel-depth uint8. So I put my m_inputImg which has 3-channels and 8 bit pixel depth in the function:
cv::dnn::blobFromImage(m_inputImg, m_inputImgTensor, 1.0, cv::Size(), cv::Scalar(), false, false, CV_8U);
Now I'm interested in having a Idea how my input image "lay" inside the cv::Mat tensor. Theoretically I know how the tensor looks like, but I don't understand how OpenCV do it. So to understand this I want to extract one colour channel. I've tried this:
cv::Mat blueImg = cv::Mat(cp->getModelConfigs().model[0].input.height,
cp->getModelConfigs().model[0].input.width,
CV_8UC3,
blob.ptr<uint8_t>(0, 0);
But what I get is something like that (see picture). I'm realy confused about that, can anybody help or has a good advice?
Thanks

cv::Size() will use the original image size. You are interpreting the data wrong. Here are 4 ways to interpret a 512x512 (cv::Size()) loaded blob-start from the lenna image:
input (512x512):
blob-start as a 512x512 single channel image:
blob-start as a 512x512 BGR image:
blob-start as a 224x224 BGR image:
blob-start as a 224x224 single channel:
here's the code:
int main()
{
cv::Mat img = cv::imread("C:/data/Lenna.png"); // 8UC3
cv::imshow("img", img);
cv::Mat blob;
cv::dnn::blobFromImage(img, blob, 1.0, cv::Size(), cv::Scalar(), false, false, CV_8U);
cv::Mat redImg = cv::Mat(img.rows,
img.cols,
CV_8UC1,
blob.ptr<uint8_t>(0, 0));
cv::imshow("blob 1", redImg);
cv::imwrite("red1.jpg", redImg);
cv::Mat redImg3C = cv::Mat(img.rows,
img.cols,
CV_8UC3,
blob.ptr<uint8_t>(0, 0));
cv::imshow("redImg3C", redImg3C);
cv::imwrite("red3C.jpg", redImg3C);
cv::Mat redImg224_3C = cv::Mat(224,
224,
CV_8UC3,
blob.ptr<uint8_t>(0, 0));
cv::imshow("redImg224_3C", redImg224_3C);
cv::imwrite("redImg224_3C.jpg", redImg224_3C);
cv::Mat redImg224_1C = cv::Mat(224,
224,
CV_8UC1,
blob.ptr<uint8_t>(0, 0));
cv::imshow("redImg224_1C", redImg224_1C);
cv::imwrite("redImg224_1C.jpg", redImg224_1C);
cv::waitKey(0);
}
Imho you have to do in your code:
cv::dnn::blobFromImage(m_inputImg, blob, 1.0, cv::Size(), cv::Scalar(), false, false, CV_8U);
cv::Mat blueImg = cv::Mat(m_inputImg.rows,
m_inputImg.cols,
CV_8UC3,
blob.ptr<uint8_t>(0, 0);
OR
cv::dnn::blobFromImage(m_inputImg, blob, 1.0, cv::Size(cp->getModelConfigs().model[0].input.width , cp->getModelConfigs().model[0].input.height), cv::Scalar(), false, false, CV_8U);
cv::Mat blueImg = cv::Mat(cp->getModelConfigs().model[0].input.height,
cp->getModelConfigs().model[0].input.width,
CV_8UC3,
blob.ptr<uint8_t>(0, 0);
In addition, here's the version of setting the spatial blob image size to a fixed size (e.g. the desired DNN input size):
cv::Mat blob2;
cv::dnn::blobFromImage(img, blob2, 1.0, cv::Size(224,224), cv::Scalar(), false, false, CV_8U);
cv::Mat blueImg224_1C = cv::Mat(224,
224,
CV_8UC1,
blob2.ptr<uint8_t>(0, 0));
cv::imshow("blueImg224_1C", blueImg224_1C);
cv::imwrite("blueImg224_1C.jpg", blueImg224_1C);
Giving this image:

Related

opencv how to create hsv format mat

For example, I create
Mat mat1 = Mat::zeros(Size(100, 100), CV_8UC3);
and fill each pixel with (0, 255, 255), which is supposed to be red in hsv.
However, if I imshow this mat, this will be printed as a BGR image and is not red.
How do I make this mat hsv format and setting (0, 255, 255) result in red?
imshow assumes that the image you pass to it is in BGR color space. However, you can create a small function that does your imshow of HSV images.
void imshowHSV(std::string& name, cv::Mat& image)
{
cv::Mat hsv;
cv:cvtColor(image, hsv, CV_HSV2BGR);
cv::imshow(name, hsv);
}
But beware! this will convert and create a copy of the image, if you over use it it may have quite some overhead :)

Matrix multiplication between CV_8UC3 and CV_32FC3

I want to make matrix multiplication between image and mask. I want multiply in HSV value with 0.3. I think, the problem is between CV_32FC3 and CV_8UC3, but when I convert, still not work correct.
How can I do? Here is my current code:
Mat mask = Mat(frame.size(), CV_32FC3, cv::Scalar(1, 1, 1));
cv::fillConvexPoly(mask, pts, 3, cv::Scalar(1,1,0.3));
cvtColor(frame, frame, CV_BGR2HSV);
frame.convertTo(frame, CV_32FC3);
cv::multiply(frame,mask,frame);
frame.convertTo(frame, CV_8UC3);
cvtColor(frame, frame, CV_HSV2BGR);
If I do only this, see the mask is ok - white and black changes:
Mat mask = Mat(frame.size(), CV_32FC3, cv::Scalar(1, 1, 1));
cv::fillConvexPoly(mask, pts, 3, cv::Scalar(0,0,0));
imshow("mask", mask);

Can't save image in JPG with white background OpenCV

I write a simple app in OpenCV that delete black background of an image and save it with white background in JPG. However, it's always saved with black background.
This is my code:
Mat Imgsrc = imread("../temp/temp1.jpg",1) ;
mat dest;
Mat temp, thr;
cvtColor(Imgsrc, temp, COLOR_BGR2GRAY);
threshold(temp,thr, 0, 255, THRESH_BINARY);
Mat rgb[3];
split(Imgsrc,rgb);
Mat rgba[4] = { rgb[0],rgb[1],rgb[2],thr };
merge(rgba,4,dest);
imwrite("../temp/r5.jpg", dest);
You can simply use setTo with a mask to set some pixels to a specific value according to a mask:
Mat src = imread("../temp/temp1.jpg",1) ;
Mat dst;
Mat gray, thr;
cvtColor(src, gray, COLOR_BGR2GRAY);
// Are you sure to use 0 as threshold value?
threshold(gray, thr, 0, 255, THRESH_BINARY);
// Clone src into dst
dst = src.clone();
// Set to white all pixels that are not zero in the mask
dst.setTo(Scalar(255,255,255) /*white*/, thr);
imwrite("../temp/r5.jpg", dst);
Also a few notes:
You can directly load an image as grayscale using: imread(..., IMREAD_GRAYSCALE);
You can avoid to use all those temporary Mats.
Are you sure you want to use 0 as threshold value? Because in this case you can avoid entirely to apply theshold, and set to white all pixels that are 0 in the grayscale image: dst.setTo(Scalar(255,255,255), gray == 0);
This is how I'd do:
// Load the image
Mat src = imread("path/to/img", IMREAD_COLOR);
// Convert to grayscale
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
// Set to white all pixels that are 0 in the grayscale image
src.setTo(Scalar(255,255,255), gray == 0)
// Save
imwrite("path/to/other/img", src);

Error when converting Qimage to Mat opencv

When I convert a QImage to cv::Mat the Mat comes out blurred.
This is the code that converts it:
QPixmap pixmap(*ui->imgLabel->pixmap());
QImage image = pixmap.toImage();
image.convertToFormat(QImage::Format_RGB888);
Mat matImage = Mat(image.height(), image.width(), CV_8UC3, image.scanLine(0));
This is the original image zoomed:
This is the image created:
Grateful for any help.
I don't know QT, but have you tried ready solutions from WEB? For example, from this link I found another method of conversion:
Mat qimage2mat(const QImage& qimage) {
cv::Mat mat = cv::Mat(qimage.height(), qimage.width(), CV_8UC4, (uchar*)qimage.bits(), qimage.bytesPerLine());
cv::Mat mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC3 );
int from_to[] = { 0,0, 1,1, 2,2 };
cv::mixChannels( &mat, 1, &mat2, 1, from_to, 3 );
return mat2;
};

OpenCV: Use GaussianBlur or Sobel Derivatives on QImage

I hope you could help me.
I' m using QT and try to do a simple detection of edges on a image. But my program crash when i launch
cv::GaussianBlur( src, src, cv::Size(3,3), 0, 0, cv::BORDER_DEFAULT );
or
cv::Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, cv::BORDER_DEFAULT );
here is my code:
QImage *image1;
IplImage *cv_image1;
image1 = new QImage("./image.png"); // Format is ARGB32
cv_image1 = QImage2IplImage(image1);
cv::Mat src(cv_image1);
cv::imshow(window_name, src); // Work Well
cv::Mat src_gray;
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
cv::GaussianBlur(src, src, cv::Size(3,3), 0, 0, cv::BORDER_DEFAULT); //Crash Here
cv::imshow( window_name, src);
I think that was a problem of format.
But in another program with QIMAGES in ARGB32 this code work well.
Thank you.
Try going with proper QImage to cv::Mat conversion using this functions and you should be fine (I also included a conversion from cv::Mat to QImage):
cv::Mat cvmat_from_qimage(const QImage& qimage)
{
cv::Mat mat = cv::Mat(qimage.height(), qimage.width(), CV_8UC4, (uchar*)qimage.bits(), qimage.bytesPerLine());
cv::Mat mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC3 );
int from_to[] = { 0,0, 1,1, 2,2 };
cv::mixChannels( &mat, 1, &mat2, 1, from_to, 3 );
return mat2;
}
QImage qimage_from_cvmat(const cv::Mat& mat)
{
cv::Mat rgb;
cvtColor(mat, rgb, CV_BGR2RGB);
return QImage((const unsigned char*)(rgb.data), rgb.cols, rgb.rows, QImage::Format_RGB888);
}
I Found a solution.
That' s weird but when I do:
cvtColor(src, src_gray, CV_RGB2GRAY );
cv::Sobel(src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, cv::BORDER_CONSTANT);
without the cv::GaussianBlur it works well. I just change the last parameter to cv::BORDER_CONSTANT