I understand that this is the command to use otsu in opencv:
cvThreshold(src, dst, 128, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
However, I don't understand what that src and dst is, explained on the opencv website as:
input array (single-channel, 8-bit or 32-bit floating point).
What is an 8-bit or 32-bit floating point, single channel array?
http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#threshold
Single channel means graysclale. 8 bits means unsigned char (CV_8U in OpenCV). 32bit means float (CV_32F in OpenCV)
My issue was getting the image in the right format but I found at least two ways:
CvCapture* capture = cvCaptureFromFile("picture.png");
IplImage* frame = cvQueryFrame(capture);
2.
IplImage* frame = cvLoadImage("picture.png", CV_LOAD_IMAGE_GRAYSCALE);
I am also under the impression that the picture needs to be grey scaled first, not sure how to do that for the first option though. Anyway, for src and dst these work.
Related
I'm currently using OpenCV (in C++) to normalize some data in the form of images. Since I'm planning to train an autoencoder I found some articles and papers suggesting that it's better if the data is normalised in the range from -1 to 1 (tanh vs sin). I managed to do this with the following code:
cv::VideoCapture cap(video);
cv::Mat frame;
cap.read(frame);
//convert to grayscale
cv::cvtColor(*frame, *frame, cv::COLOR_BGR2GRAY);
//normalise
frame->convertTo(*frame, CV_32FC1); //change data type from CV_8UC1 to CV_32FC1
cv::normalize(*frame, *frame, -1, 1, cv::NORM_MINMAX);
//downscale
cv::resize(*frame, *frame, cv::Size(256, 256));
The next thing I want to do is to save the normalised image and for this I'm using cv::imwrite(), so I have the following line: cv::imwrite("normImage.tiff", *frame);.
I'm wondering, however, if writing the image to .TIFF format actually reverses the normalisation and I haven't been able to verify whether that's the case or not. I'd also like to ask if there's a better way/format to write the image using OpenCV?
Cheers
I am using Network Optix Video management service. Using their application I am building a plugin. For my purpose I want to export frame as an image from a video. for that I used following code to convert to cv object and saving into my file.
cv::Mat img_color;
cv::Mat img(
videoFrame->height(),/*_rows*/
videoFrame->width(), /*_cols*/
CV_8UC1, //< BGR color space (default for OpenCV) /*_type*/
(void*) videoFrame->data(0), /*_data*/
(size_t) videoFrame->lineSize(0)); /*_step*/
cv::cvtColor(img, img_color, CV_GRAY2RGB);
m_lastVideoFrameTimestampUs = videoFrame->timestampUs();
std::string file_path = "/var/www/html/images/"+std::to_string(m_lastVideoFrameTimestampUs)+".jpg";
cv::imwrite(file_path,img_color);
below screenshot is what I am getting on Network Optix client application.
But, this is what I am getting as an image file on my machine.
cvtColor doesn't have any effect on the image
I think, CV_8UC1 argument should be modified so that I will get RGB image
EDIT - 1:
changes CV_8UC1 to CV_8UC3
Result turned into 3 segments of image
CV_8UC1 means that it is 8-bit single-channel array, you are getting a grayscale image at first and you can not except cvtColor to get it colorized again. cvtColor which you used will convert the image to BGR but all the channels will be in same value so it will continue to seem as grayscale.
In this case you can use CV_8UC3 which means that it is an 8-bit unsigned integer matrix/image with 3 channels(If your image in 3 channels)
I wrote a code for watershed segmentation in C API. Now I am converting all those into C++. so, cvsaveimage becomes imwrite. But when I use imwrite ,all i get is a black image.
this is the code:-
Mat img8bit;
Mat img0;
img0 = imread("source.png", 1);
Mat wshed(img0.size(), CV_32S);
wshed.setTo(cv::Scalar::all(0));
////after performing watershed segmentation and
// displaying the watershed image from wshed//
wshed.convertTo(img8bit, CV_32FC3, 255.0);
imwrite("Watershed.png", img8bit);
The original image that I want to save is in wshed. I saw suggestions from the net that we need to convert it to 16 bit or higher so that the imwrite saves it right. Like you see,I tried that. But the wshed image is being displayed correctly when using imshow.The img0 is grey image/black and white while the wshed image is coloured. any help on this?
Edit- I changed the 4th line to
Mat wshed(img0.size(), CV_32FC3);
When calling Mat::convertTo() with a scalar (255 in your case), the values of every matrix item will be multiplied by this scalar value. This will cause all most every result pixel values exceed 255 (i.e. white pixels) except those of 0s where they remain 0 (i.e. black pixels). This is why you will get the black-white pixel in the end.
To make it work, simply change it to:
wshed.convertTo(img8bit, CV_32FC3);
You said:
The original image that I want to save is in wshed. I saw suggestions
from the net that we need to convert it to 16 bit or higher so that
the imwrite saves it right.
If saving the image does not work you should keep in mind that the image data has to be either 8-Bits or 16-Bit unsigned when using the imwrite Function, not 16-Bits or higher.
This is stated in the documentation:
The function imwrite saves the image to the specified file. The image
format is chosen based on the filename extension (see imread() for the
list of extensions). Only 8-bit (or 16-bit unsigned (CV_16U) in case
of PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with ‘BGR’
channel order) images can be saved using this function. If the format,
depth or channel order is different, use Mat::convertTo() , and
cvtColor() to convert it before saving. Or, use the universal
FileStorage I/O functions to save the image to XML or YAML format.
I need to convert a CV_8U image with 3 channels to an image which must be a single channel CV_32S. But when I'm trying to do so, the image I get is all black. I don't understand why my code is not working.
I'm dealing with a grayscale image, this is why I split the 3 channels image into a vector of single channel image, and then process only the first channel.
//markers->Image() returns a valid image, so this is not the problem
cv::Mat dst(markers->Image().size(), CV_32SC1);
dst = cv::Scalar::all(0);
std::vector<cv::Mat> vectmp;
cv::split(markers->Image(), vectmp);
vectmp.at(0).convertTo(dst, CV_32S);
//vectmp.at(0) is ok, but dst is black...?
Thank you in advance.
Have you tried to get values of result image? Like this:
for (int i=0; i<result.rows; i++)
{
for (int j=0; j<result.cols; j++)
{
cout << result.at<int>(i,j) << endl;
}
}
I have converted (also used convertTo) random gray-scale single-channel image to CV_32S (it is a signed 32bit integer value for each pixel) my output was like this:
80
111
132
And when I tried to show it I also get black image. From documentation:
If the image is 16-bit unsigned or 32-bit integer, the pixels are
divided by 256. That is, the value range [0,255*256] is mapped to
[0,255].
So if you divide these small numbers to 255 than you will get 0 (int type). That's why imshow displays black image.
If you want to display your 32-bit image and see a meaningful result, you need to multiply all of its elements by 256 prior to calling imshow. Otherwise, imshow will scale your values down to zero and you will get a black image (as Astor has pointed out).
Since the original values are 8 bit unsigned, they must be less than 255. Therefore multiplying them by 256 is safe and will not overflow a 32-bit integer.
EDIT I just realized your output type is a signed 32-bit integer, but the original type is unsigned 8-bit integer. In that case, you need to scale your values appropriately (have a look at scaleAdd).
Finally, you may want to make sure your image is in YCbCr format before you start throwing away image channels.
I had the same problem, solved it indirectly by trying to convert a 8UC1 to 32S instead of 8UC3.
RgbToGray accept to create a gray image using 8UC3 or 8UC1 element type.
8UC1 image is my marker image.
I've done this in Opencvsharp :
Mat buf3 = new Mat(iplImageMarker);
buf3.ConvertTo(buf3, MatType.CV_32SC1);
iplImageMarker= (IplImage)buf3;
iplImageMarker=iplImageMarker* 256;
I believe this is what you are looking for. Convert your image to this, 8 bit, single channel. CV_8UC1. You are starting with a 8 bit image and changing it to 32 bit single channel? Why? Keep it 8 bit.
What is the default pixel type of imread create? I test different images, all of them give me unsigned
char with different channels. Would imread create a pixel type with signed char if I do not ask it
explicitly?
cv::Mat img = cv::imread("lena.jpg", -1); //always give me unsigned char
I checked the document of cv::imread, but it said nothing about the default pixel of imread create.
The link of the document
http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#Mat imread(const string& filename, int flags)
Most .jpg images are 8 bit images. Therfore their default data-type is unsigned char or char.
Some images like .png or .tif also support 16 bit pixel value, so their data type is unsigned short. But it is not necessary as they may be 8 bit.
To load the image as-is in OpenCV, use imread like this:
cv::Mat img = cv::imread(imagePath, CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH);
There are different combinations of these flags:
Load as 8 bit (whatever the original depth is):
CV_LOAD_IMAGE_COLOR
Load with original depth:
CV_LOAD_IMAGE_COLOR | CV_LOAD_IMAGE_ANYDEPTH
Load as grayscale (no matter how many channels the image has):
CV_LOAD_IMAGE_GRAYSCALE
Load as grayscale with original depth:
CV_LOAD_IMAGE_GRAYSCALE| CV_LOAD_IMAGE_ANYDEPTH
In your case, lena.jpg is 8 bit image, so you are getting unsigned char data type.
Update:
For newer versions of OpenCV, use the flags defined by enum in the C++ interface. Just replace CV_LOAD_IMAGE_* with cv::IMREAD_*.
e.g. CV_LOAD_IMAGE_GRAYSCALE becomes cv::IMREAD_GRAYSCALE.