I want to convert any image I use as input to CV_32FC1 type. My code is below:
char fname[MAX_PATH];
while (openFileDlg(fname))
{
Mat img = imread(fname, CV_LOAD_IMAGE_UNCHANGED);
Mat src(img.rows, img.cols, CV_32FC1);
Mat dst(img.rows, img.cols, CV_32FC1);
if (img.type() == 0)
{
img.convertTo(img, CV_32FC1, 1.0f / 255.0f);
src = img.clone();
}
else
{
img.convertTo(img, CV_32FC1);
}
std::cout << img.type() << ' ' << src.type();
}
For grayscale images it works, but when I use a color image, the conversion doesn't work. For example: for CV_32FC1 the value is 5. When I upload a color image it gives me the value 16, and after conversion is 21. Any ideas?
You see inconsistent results for Gray and RGB images to the difference in channel numbers in both cases, 32FC1 can be broken down as:
32F - 32 bit floating value
C1 - Single channel
But RGB image or BGRA images have 3, 4 channels respectively, so we can't use C1 for them, hence we need to use 32FC3 for 3-channel image and 32FC4 for 4-channel image.
Related
I want to convert colorBGR image into grey scale in opencv without using direct command CV_RGB2GRAY. Here I uploaded my code which gives me a bluish color of the image which is not a proper grey output image. Please check the below code and tell me where I m going wrong or you can give me another solution to convert the color image into grey output image without CV_RGB2GRAY.
Thanks in advance.
Mat image=imread("Desktop\\Sample input\\ip1.png");
Mat grey( image.rows,image.cols, CV_8UC3);
for(int i=0;i<image.rows;i++)
{
for(int j=0;j<image.cols;j++)
{
int blue = image.at<Vec3b>(i,j)[0];
int green = image.at<Vec3b>(i,j)[1];
int red = image.at<Vec3b>(i,j)[2];
grey.at<Vec3b>(i,j) = 0.114*blue+0.587*green+ 0.299*red ;
}
}
imshow("grey image",grey);
If you intend to convert the image which you are taking by imread() functions, you can take the image as input as a grayscale image directly by
Mat image = imread("Desktop\\Sample input\\ip1.png",CV_LOAD_IMAGE_GRAYSCALE);
or, by
Mat image = imread("Desktop\\Sample input\\ip1.png",0);
It is because CV_LOAD_IMAGE_GRAYSCALE corresponds to the constant 0. And when in imread() function gets this argument zero, it will load an image with intensity one.
And if want to convert any image to grayscale then the out image image should like
Mat grey = Mat::zeros(src_image.rows, src_image.cols, CV_8UC1);
as grayscale image is of only one channel and then you can convert the image like this:
for(int i=0;i<image.rows;i++)
{
for(int j=0;j<image.cols;j++)
{
int blue = image.at<Vec3b>(i,j)[0];
int green = image.at<Vec3b>(i,j)[1];
int red = image.at<Vec3b>(i,j)[2];
grey.at<uchar>(i, j) = (uchar) (0.114*blue + 0.587*green + 0.299*red);
}
}
It will give you the grayscale image.
In your code, the grey Mat has 3 channels. For a grayscale image you only need 1 channel (8UC1).
Also, when you are writing the values in the grayscale image, you need to use uchar instead of Vec3b because each pixel in the grayscale image is only made up of one unsigned char value, not a vector of 3 values.
So, you need to replace these lines:
Mat grey(image.rows, image.cols, CV_8UC1);
and
grey.at<uchar>(i, j) = 0.114*blue + 0.587*green + 0.299*red;
The following code reads an image from a file into a cv::Mat object.
#include <string>
#include <opencv2/opencv.hpp>
cv::Mat load_image(std::string img_path)
{
cv::Mat img = cv::imread(img_path, CV_LOAD_IMAGE_GRAYSCALE);
cv::Scalar intensity = img.at<uchar>(0, 0);
std::cout << intensity << std::endl;
return img;
}
I would expect the cv::Mat to have only one channel (namely, the intensity of the image) but it has 4.
$ ./test_load_image
[164, 0, 0, 0]
I also tried converting the image with
cv::Mat gray(img.size(), CV_8UC1);
img.convertTo(gray, CV_8UC1);
but the gray matrix is also a 4 channels one.
I'd like to know if it's possible to have a single channel cv::Mat. Intuitively, that's what I would expect to have when dealing with a grayscale (thus, single channel) image.
The matrix is single channel. You're just reading the values in the wrong way.
Scalar is a struct with 4 values. Constructing a Scalar with a single value will result in a Scalar with the first value set, and the remaining at zero.
In your case, only the first values make sense. The zeros are as default for Scalar.
However, you don't need to use a Scalar:
uchar intensity = img.at<uchar>(0, 0);
std::cout << int(intensity) << std::endl; // Print the value, not the ASCII character
I'm trying to extract and display
Y channel from YUV converted image
My code is as follows:
Mat src, src_resized, src_gray;
src = imread("11.jpg", 1);
resize(src, src_resized, cvSize(400, 320));
cvtColor(src_resized, src_resized, cv::COLOR_BGR2RGB);
/*
I've tried both with and without the upper conversion
(mentioned here as bug
http://stackoverflow.com/questions/7954416/converting-yuv-into-bgr-or-rgb-in-opencv
in an opencv 2.4.* version - mine is 2.4.10 )
*/
cvtColor(src_resized, src_gray, CV_RGB2YUV); //YCrCb
vector<Mat> yuv_planes(3);
split(src_gray,yuv_planes);
Mat g, fin_img;
g = Mat::zeros(Size(src_gray.cols, src_gray.rows),0);
// same result withg = Mat::zeros(Size(src_gray.cols, src_gray.rows), CV_8UC1);
vector<Mat> channels;
channels.push_back(yuv_planes[0]);
channels.push_back(g);
channels.push_back(g);
merge(channels, fin_img);
imshow("Y ", fin_img);
waitKey(0);
return 0;
As result I was expecting a Gray image showing luminescence.
Instead I get a B/G/R channel image depending on the position of (first/second/third)
channels.push_back(yuv_planes[0]);
as shown here:
What am I missing? (I plan to use the luminance to do a sum of rows/columns and extracting the License Plate later using the data obtained)
The problem was displaying the luminescence only in one channel instead of filling all channels with it.
If anyone else hits the same problem just change
Mat g, fin_img;
g = Mat::zeros(Size(src_gray.cols, src_gray.rows),0);
vector<Mat> channels;
channels.push_back(yuv_planes[0]);
channels.push_back(g);
channels.push_back(g);
to
(fill all channels with desired channel)
Mat fin_img;
vector<Mat> channels;
channels.push_back(yuv_planes[0]);
channels.push_back(yuv_planes[0]);
channels.push_back(yuv_planes[0]);
I'm trying to inpaint missing depth values of a depth map using the method described here. To summarize the method:
Downsize depth map to 20% of the original size
Inpaint all black (unknown) pixels in the downsized image
Upsize to original size
Replace all black pixels in the original image with corresponding values from the upsized image
Super simple and everything works well. A video showing the results can be found here.
However, I wonder why the left and top image border are still black although they should be inpainted (can be seen in the video). My first thought was that this could have to do something with the border interpolation (black pixels outside the image boundary), but than I would expect this also to happen on the other image borders. My second thought was that it is something specific to the used inpainting method (method by Alexandru Telea), but changing it to the Navier-Stokes based method didn't change the results.
Can somebody explain to me why this happens and how to tell OpenCV to also inpaint these regions, if possible?
Thanks in advance.
After asked by #theodore in http://answers.opencv.org/question/86569/inpainting-depth-map-still-black-image-borders/?comment=86587#comment-86587 I've used the sample images to test the inpaint behavious. It looks like it does not handle the border correctly, so creating a border with cv::copyMakeBorder can be used.
Here's the extended version with some kind of unit testing:
int main(int argc, char* argv[])
{
cv::Mat input = cv::imread("C:/StackOverflow/Input/depthInpaint.png");
cv::Mat img;
cv::cvtColor(input, img, CV_BGR2GRAY);
cv::Mat inpainted;
const unsigned char noDepth = 0; // change to 255, if values no depth uses max value or use the mask image
//cv::inpaint(img, (img == noDepth), depth, 5.0, cv::INPAINT_TELEA); // img is the 8-bit input image (depth map with blank spots)
double inpaintRadius = 5;
int makeBorder = 1;
cv::Mat borderimg;
cv::copyMakeBorder(img, borderimg, makeBorder, makeBorder, makeBorder, makeBorder, cv::BORDER_REPLICATE);
cv::imshow("border", borderimg);
cv::inpaint(borderimg, (borderimg == noDepth), inpainted, inpaintRadius, cv::INPAINT_TELEA); // img is the 8-bit input image (depth map with blank spots)
cv::Mat originalEmbedded = borderimg(cv::Rect(makeBorder, makeBorder, img.cols, img.rows));
cv::Mat inpaintedEmbedded = inpainted(cv::Rect(makeBorder, makeBorder, img.cols, img.rows));
cv::Mat diffImage;
cv::absdiff(img, originalEmbedded, diffImage);
cv::imshow("embedding correct?", diffImage > 0);
cv::Mat mask = img == noDepth;
cv::imshow("mask", mask);
cv::imshow("input", input);
cv::imshow("inpainted", inpainted);
cv::imshow("inpainted from border", inpaintedEmbedded);
cv::waitKey(0);
return 0;
}
Here's the reduced version if you believe it to be correct:
int main(int argc, char* argv[])
{
cv::Mat input = cv::imread("C:/StackOverflow/Input/depthInpaint.png");
cv::Mat img;
cv::cvtColor(input, img, CV_BGR2GRAY);
cv::Mat inpainted;
const unsigned char noDepth = 0; // change to 255, if values no depth uses max value or use the mask image
//cv::inpaint(img, (img == noDepth), depth, 5.0, cv::INPAINT_TELEA); // img is the 8-bit input image (depth map with blank spots)
double inpaintRadius = 5;
int makeBorderSize = 1;
cv::Mat borderimg;
//cv::copyMakeBorder(img, borderimg, borderSize, borderSize, borderSize, borderSize, cv::BORDER_REPLICATE);
cv::copyMakeBorder(img, borderimg, makeBorderSize, makeBorderSize, makeBorderSize, makeBorderSize, cv::BORDER_REPLICATE);
//cv::imshow("border", borderimg);
cv::inpaint(borderimg, (borderimg == noDepth), inpainted, inpaintRadius, cv::INPAINT_TELEA); // img is the 8-bit input image (depth map with blank spots)
// extract the original area without border:
cv::Mat inpaintedEmbedded = inpainted(cv::Rect(makeBorderSize, makeBorderSize, img.cols, img.rows));
cv::imshow("input", input);
cv::imshow("inpainted from border", inpaintedEmbedded);
cv::waitKey(0);
return 0;
}
Here's Input:
Here's the input with border (bordersize 5 to visualize the effect better):
Here's the output:
I have an RGB large-image, and an RGB small-image.
What is the fastest way to replace a region in the larger image with the smaller one?
Can I define a multi-channel ROI and then use copyTo? Or must I split each image to channels, replace the ROI and then recombine them again to one?
Yes. A multi channel ROI and copyTo will work. Something like:
int main(int argc,char** argv[])
{
cv::Mat src = cv::imread("c:/src.jpg");
//create a canvas with 10 pixels extra in each dim. Set all pixels to yellow.
cv::Mat canvas(src.rows + 20, src.cols + 20, CV_8UC3, cv::Scalar(0, 255, 255));
//create an ROI that will map to the location we want to copy the image into
cv::Rect roi(10, 10, src.cols, src.rows);
//initialize the ROI in the canvas. canvasROI now points to the location we want to copy to.
cv::Mat canvasROI(canvas(roi));
//perform the copy.
src.copyTo(canvasROI);
cv::namedWindow("original", 256);
cv::namedWindow("canvas", 256);
cv::imshow("original", src);
cv::imshow("canvas", canvas);
cv::waitKey();
}