I am somewhat confused on how a depth image from a Kinect v1 is to be handled within MATLAB. I am using these (http://www.mathworks.com/matlabcentral/fileexchange/30242-kinect-matlab) mex-files, to read my depth images from saved *.oni files. As a result, I get images of resolution 640x480 or 320x240. The values in the images range roughly from 0-4500.
What type of image am I dealing here with now? Reading this http://www.mathworks.de/de/help/matlab/creating_plots/working-with-8-bit-and-16-bit-images.html I would assume it would have to be an indexed image, because it is no RGB image and the values are not linearly scaled. On the other hand, I believe the values in the image are actual distances to Kinect's focal plane in mm and therefore have a meaning other than an index.
When I want to look at the image using
imshow(depthMap);
I only see black. I have to use something like
imshow(depthMap, [0 9000])
to actually see something. Why exactly is that? What does imshow(depthMap) do with the values?
Do you think its correct to use depthMap as it is in my algorithms, but look at it using
imshow(depthMap, [0 9000])
?
depthMap is not an indexed image, but every pixel codes the distance from the focal plane in mm, as you correctly believe.
To show such an image using imshow, I suggest to use auto-scaling by default, i.e. imshow(depthMap,[]), or use a fixed scale (as you're currently doing) if there is a useful meaning to the minimum and maximum. Turn on the colorbar to visualize the correspondence between color and depth, either via the GUI, or by calling colorbar().
imshow with no scale argument will scale the color limits to [0 1], unless the image is of class uint8, where the color limits are set to [0 255]. In other words, with no scale argument, values of 0 and lower are mapped to black, values of 1 and higher are mapped to white. See also caxis.
Related
Through a combination of non-matlab/non-native tools (GDAL) as well as native tools (geoimread) I can ingest Sentinel-2A data either a indiviual bands or as an RGB image having employed gdal merge. I'm stuck at a point where using
imshow(I, [])
Produces a black image, with apparently no signal. The range of intensity values in the image are 271 - 4349. I know that there is a good signal in the image because when I do:
bit_depth = 2^15;
I = swapbytes(I);
[I_indexed, color_map] = rgb2ind(I, bit_depth);
I_double = im2double(I_indexed, 'indexed');
ax1 = figure;
colormap(ax1, color_map);
image(I_double)
i.e. index the image, collect a colormap, set the colormap and then call the image function, I get a likeness of the region I'm exploring (albeit very strangely colored)
I'm currently considering whether I should try:
Find a low-level description of Sentinel-2A data, implement the scaling/correction
Use a toolbox, possibly this one.
Possibly adjust ouput settings in one of the earlier steps involving GDAL
Comments or suggestions are greatly appreciated.
A basic scaling scheme is:
% convert image to double
I_double = im2double(I);
% scaling
max_intensity = max(I_double(:));
min_intensity = min(I_double(:));
range_intensity = max_intensity - min_intensity;
I_scaled = 2^16.*((I_double - min_intensity) ./ range_intensity);
% display
imshow(uint16(I_scaled))
noting the importance of casting to uint16 from double for imshow.
A couple points...
You mention that I is an RGB image (i.e. N-by-M-by-3 data). If this is the case, the [] argument to imshow will have no effect. That only applies automatic scaling of the display for grayscale images.
Given the range of intensity values you list (271 to 4349), I'm guessing you are dealing with a uint16 data type. Since this data type has a maximum value of 65535, your image data only covers about the lower 16th of this range. This is why your image looks practically black. It also explains why you can see the signal with your given code: you apply swapbytes to I before displaying it with image, which in this case will shift values into the higher intensity ranges (e.g. swapbytes(uint16(4349)) gives a value of 64784).
In order to better visualize your data, you'll need to scale it. As a simple test, you'll probably be able to see something appear by just scaling it by 8 (to cover a little more than half of your dynamic range):
imshow(8.*I);
This question already has an answer here:
What does the index refer to when selecting a pixel on an image in Matlab?
(1 answer)
Closed 6 years ago.
I have gray scale image "lena.bmp". I want read this image in matlab using imread() function.
When i use code below to read and show image my image is dark (black).
img = imread('lena.bmp');
imshow(img);
But when i use code below, I have no problem to view.
[img map]= imread('lena.bmp');
imshow(img,map);
It seems that my first code doses not reading image in grayscale mode (like what rgb2gray function generate).
My image is as follows:
What can i do to solve this problem?
Your image is an "indexed" image. That means it contains integer values which act as "labels" more than anything, and each of those labels is mapped to a colour (i.e. an rgb triplet). Your map variable represents that mapping; at row 5 you have the rgb triplet that corresponds to 'label' "5", for instance.
To see what I mean, do unique(img) and you'll see that the values of your img array are in fact quite regular. The command rgbplot can demonstrate the actual colourmap graphically. Run rgbplot(map) on your map variable to see the mapping for each of the red green and blue colours.
Now, save and read the image below on your computer as img2 and compare the array values.
This image was generated by converting from the "indexed" image you linked to, to a "grayscale" one using photoediting software (the GIMP). The difference is that
in a grayscale image, the pixel values represent actual intensities, rather than integer 'labels'. Imread reads grayscale images as uint8 images by default, meaning it assigns intensity values to pixels ranging from 0 (black) to 255 (white). Since these values happen to be integers you could still cheat and treat them as 'labels' and force a colour-mapping on them. But if you assign a 'linear map' (i.e. value 1 = intensity 1, value 2 = intensity 2, etc) then your image will look as you would expect.
You'll see that the values from unique(img2) are quite different. If you imshow(img2) you'll see this displays as you'd expect. If you don't specify a colormap for imshow, it will assume that the map is a linear mapping from the lowest to the highest value in the image array, which explains why your indexed image looked weird, since its values were never supposed to correspond to intensities.
Also try imagesc(img2) which will show this but using the "current" colormap. imagesc causes the colormap to be "scaled", so that the lowest colour goes to the lowest value in the image, and similarly for the highest.
The default colormap is jet so you should see a psychedelic looking image but you should be able to make out lena clearly. If you try colormap gray you should see the gray version again. Also try colormap hot. Now to make sense of the colormaps, try the rgbplot command on them (e.g. rgbplot(gray), rgbplot(hot) etc).
So, going back to imshow, imshow basically allows you to display an indexed image, and specify what colormap you want to use to display it. If you don't specify the colormap, it will just use a linear interpolation from the lowest value to the highest as your map. Therefore imshow(img) will show the image pretty much in the same way as imagesc(img) with a gray colormap. And since the values in your first img represent evenly spaced 'labels' rather than actual intensities, you'll get a rubbish picture out.
EDIT: If you want to convert your indexed image to a grayscale image, matlab provides the ind2gray function, e.g.:
[img, map] = imread('lena.bmp');
img_gray = ind2gray(img, map);
This is probably what you need if you mean to process pixel values as intensities.
Just clarifying a point about the Otsu thresholding method that lacks definition in the documentation & wikipedia articles. If you apply the Otsu method (in matlab the function graythresh) it returns a threshold value between 0 and 1.
Given 2 hypothetical grayscale images:
dark (with pixel intensities in the range of 0 to 100) and
light (with pixel intensities in the range of 155 to 255)
If I got an Otsu threshold of 0.75 for both dark and light images respectively, what grayscale pixel intensity would it map to in each case?
dark -> 75 and light -> 231 E.g. relative to the range of values in each image
dark -> 75 and light -> 191 E.g. relative to the range 0 to max pixel value
dark -> 191 and light -> 191 E.g. relative to the full range of grayscale pixel values (0-255)?
The accepted answer by #Ratbert makes the incorrect claims that
The correct answer is the first one
and
graythresh uses the min and max values in the image as boundaries,
which is the most logical behavior.
and rayryeng appears to agree with it. David Parks appears to have empirically verified it.
The correct answer is given by Anand which strangely seems to have a negative vote. He explains very convincingly that
full range of grayscale pixel values' depends on the data type of the input image
As he explains,
this is the third option
except for the fact that the dark image could not possibly get a threshold of 0.75.
First let us clarify the difference between the claims for the simplest case, in clear MATLAB, so there is no confusion. For an image with values ranging from min to max, the question poses three possibilities which, when translated to an equation are:
threshold = min + (max-min) * graythresh
threshold = max * graythresh
threshold = 255 * graythresh
Suppose the image consists of just two points one with an intensity of 0, and the other with 100. This means dark = uint8([0 100]);. A second image light = dark+155;. When we compute 255*graythresh(dark) we get exactly 49.5. When we compute 255*graythresh(light) we get exactly 204.5. These answers make it patently obvious that the third option is the only possibility.
There is one further fine point. If you try 255*graythresh(uint8(1:2)) the answer is 1, and not 1.5. So it appears that if you are using greythresh to threshold an image, you should use image <= 255*graythesh(image) with a less-than-or-equal-to, rather than a plain less-than.
Your third answer seems most right to me, with the clarification that 'full range of grayscale pixel values' depends on the data type of the input image. For example, for a uint8 image, an Otsu threshold of 0.75 corresponds to around 191. For a uint16 image, this would correspond to 49151.
Well, for posterity sake I did a comparison of the approaches mentioned before. I took a typical image with a full range of grayscale pixel intensities, then took a dark and light version of the same image and got the graythresh value for each. I Applied the Otsu threshold using each of the above mappings.
The light image pretty clearly demonstrates that the algorithm is producing a threshold over the range of the images' pixel intensities. Were we to assume a full range of pixel intensities, the Otsu algorithm would be producing a threshold below any actually present in the image, which doesn't make much sense, at least presuming the existing black background is transparent/irrelevant.
I suppose someone could make an argument for assuming the full range of pixel intensities if you assume the existing black part of the image were relevant darkness. I would certainly welcome comments there.
Full size images seen below
Amending my words above: When I blacken all but the top half of the light image and take the Otsu threshold again I get the same threshold value of 0.3020. Were the dark parts of the image relevant to the Otsu threshold being produced the extra darkness would have affected the value, therefore, Ratbert's answer is empirically demonstrated as correct.
The correct answer is the first one :
dark = 75 and light = 230, relative to the range of values in each image
graythresh uses the min and max values in the image as boundaries, which is the most logical behavior.
Here with i have attached two consecutive frames captured by a cmos camera with IR Filter.The object checker board was stationary at the time of capturing images.But the difference between two images are nearly 31000 pixels.This could be affect my result.can u tell me What kind of noise is this?How can i remove it.please suggest me any algorithms or any function possible to remove those noises.
Thank you.Sorry for my poor English.
Image1 : [1]: http://i45.tinypic.com/2wptqxl.jpg
Image2: [2]: http://i45.tinypic.com/v8knjn.jpg
That noise appears to result from camera sensor (Bayer to RGB conversion). There's the checkerboard pattern still left.
Also lossy jpg contributes a lot to the process. You should first have an access to raw images.
From those particular images I'd first try to use edge detection filters (Sobel Horizontal and Vertical) to make a mask that selects between some median/local histogram equalization for the flat areas and to apply some checker board reducing filter to the edges. The point is that probably no single filter is able to do good for both jpeg ringing artifacts and to the jagged edges. Then the real question is: what other kind of images should be processed?
From the comments: if corner points are to be made exact, then the solution more likely is to search for features (corner points with subpixel resolution) and make a mapping from one set of points to the other images set of corners, and search for the best affine transformation matrix that converts these sets to each other. With this matrix one can then perform resampling of the other image.
One can fortunately estimate motion vectors with subpixel resolution without brute force searching all possible subpixel locations: when calculating a matched filter, one gets local maximums for potential candidates of exact matches. But this is not all there is. One can try to calculate a more precise approximation of the peak location by studying the matched filter outputs in the nearby pixels. For exact match the output should be symmetric. Otherwise the 'energies' of the matched filter are biased towards the second best location. (A 2nd degree polynomial fit + finding maximum can work.)
Looking closely at these images, I must agree with #Aki Suihkonen.
In my view, the main noise comes from the jpeg compression, that causes sharp edges to "ring". I'd try a "de-speckle" type of filter on the images, and see if this makes a difference. Some info that can help you implement this can be found in this link.
In a more quick and dirty fashion, you apply one of the many standard tools, for example, given the images are a and b:
(i) just smooth the image with a Gaussian filter, this can reduce noise differences between the images by an order of magnitude. For example:
h=fspecial('gaussian',15,2);
a=conv2(a,h,'same');
b=conv2(b,h,'same');
(ii) Reduce Noise By Adaptive Filtering
a = wiener2(a,[5 5]);
b = wiener2(b,[5 5]);
(iii) Adjust ntensity Values Using Histogram Equalization
a = histeq(a);
b = histeq(b);
(iv) Adjust Intensity Values to a Specified Range
a = imadjust(a,[0 0.2],[0.5 1]);
b = imadjust(b,[0 0.2],[0.5 1]);
If your images are supposed to be black and white but you have captured them in gray scale there could be difference due to noise.
You can convert the images to black and white by defining a threshold, any pixel with a value less than that threshold should be assigned 0 and anything larger than that threshold should be assigned 1, or whatever your gray scale range is (maybe 255).
Assume your image is I, to make it black and white assuming your gray scale image level is from 0 to 255, assume you choose a threshold of 100:
ind = find(I < 100);
I(ind) = 0;
ind = find(I >= 100);
I(ind) = 255;
Now you have a black and white image, do the same thing for the other image and you should get very small difference if the camera and the subject have note moved.
we are doing a mat lab based robotics project.which actually sorts objects based on its color so we need an algorithm to detect specific color from the image captured from a camera using mat lab.
it will be a great help if some one can help me with it.its the video of the project
In response to Amro's answer:
The five squares above all have the same Hue value in HSV space. Selecting by Hue is helpful, but you'll want to impose some constraints on Saturation and value as well.
HSV allows you to describe color in a more human-meaningful way, but you still need to look at all three values.
As a starting point, I would use the rgb space and the euclidian norm to detect if a pixel has a given color. Typically, you have 3 values for a pixel: [red green blue]. You also have also 3 values defining a target color: [255 0 0] for red. Compute the euclidian norm between those two vectors, and apply a decision threshold to classify the color of your pixel.
Eventually, you want to get rid of the luminance factor (i.e is it a bright red or a dark red?). You can switch to HSV space and use the same norm on the H value. Or you can use [red/green blue/green] vectors. Before that, apply a low pass filter to the images because divisions (also present in the hsv2rgb transform) tend to increase noise.
You probably want to convert to the HSV colorspace, and detect colors based on the Hue values. MATLAB offers the RGB2HSV function.
Here is an example submission on File Exchange that illustrate color detection based on hue.
For obtaining a single color mask, first of all convert the rgb image gray using rgb2gray. Also extract the desired color plane from the rgb image ,(eg for obtaining red plain give rgb_img(:,:,1)). Subtract the given plane from the gray image........