conversion between RGB and HSV space - matlab

I am currently trying to convert two objects from RGB space to HSV space using the rgb2hsv function, one being an image, the other being a matrix of RGB values, but my results for the value part of the matrix are not consistent.
The results for value in matrix I are between 1 and 255, but in the second matrix D, they are between 0 and 1. Does anybody know why this is the case?
I = imread('00000001.jpg');
I = rgb2hsv(I);
D = [221 12 26; 30 68 76; 40 47 27; 165 87 25; 37 59 26; 148 125 91];
D = rgb2hsv(D);

When you call rgb2hsv with a N-by-3 matrix, it is interpreted as a colormap, not an image or even image intensities. A colormap has values on [0,1], while a uint8 image has values on [0,255]. This is what rgb2hsv expects.
The colormap syntax explained by the help page for rgb2hsv:
H = rgb2hsv(M) converts an RGB color map to an HSV color map.
Each map is a matrix with any number of rows, exactly three columns,
and elements in the interval 0 to 1.
When you run D = rgb2hsv(D); it is running it with the above syntax, rather than treating the input as an image.
That said, you can just divide the third column of the output D by 255 since the resulting bizarro colormap seems to simply have scaled value elements.

I simply multiplied by 255 on the resulting matrix from running rgb2hsv on an image. I verified that the hue, saturation, and value were then the correct value and it was. This solved my problem. Be sure to verify. Another weird thing was that those values are a percentage, so 1 means 100% and 0.5 means 50%. This also threw me off.

Related

Matlab data interpolation

I have a doubt regarding the function interp1 in matlab.
I have an X array of 248 elements with its corresponding Y array. I would like to build a correspondence between the values on the array X and a custom array of gray scale values,e.g. linspace(5,250,248). I don't want to take the value 0 and 255. If i define that max(X) has the value 250 and the min(X) as the value 0, which is the corresponding gray scale value of a generic x_i?
I though to use interp1 but my code is not working. Some suggestion?
Thank you in advance
I = mat2gray(A,[amin amax]) converts the matrix A to an intensity image I that contains values in the range 0 (black) to 1 (white). amin and amax are the values in A that correspond to 0 and 1 in I. Values less than amin become 0, and values greater than amax become 1.

get pixel coordination by rgb values matlab

how can I get the x,y coordinates for pixels in an image by rgb values in matlab ?
for example : I've got an image that I want to locate the pixels coordinates od the black area in it..
If you want to find all coordinates of pixles with values (R, G, B) then
[y, x] = find(img(:,:,1)==R & img(:,:,2)==G & img(:,:,3)==B);
For black pixels choose R=0, G=0, B=0
There is a built-in function that does this: impixel.
From the official documentation:
Return Individual Pixel Values from Image
% read a truecolor image into the workspace
RGB = imread('myimg.png');
% determine the column c and row r indices of the pixels to extract
c = [1 12 146 410];
r = [1 104 156 129];
% return the data at the selected pixel locations
pixels = impixel(RGB,c,r)
% result
pixels =
62 29 64
62 34 63
166 54 60
59 28 47
Link: https://it.mathworks.com/help/images/ref/impixel.html
[EDIT]
Ok, I misunderstood your question. So to accomplish what you are looking for just use the following code:
img = imread('myimg.png');
r = img(:,:,1) == uint8(0);
g = img(:,:,2) == uint8(0);
b = img(:,:,3) == uint8(255);
[rows_idx,cols_idx] = find(r & g & b);
The example above finds all the pure blue pixels inside the image (#0000FF) and returns their indices. You can also avoid casting values to uint8, it should work anyway by implicitly converting values during comparison.

How to plot an n-points discrete segment between two given points in Matlab?

Given two points, what's the best way to plot - in Matlab - a n-points discrete segment that has these points as extremes?
What if I have to plot a chain of discrete segments like that?
Thank you in advance!
The following is an example of what I'm trying to achieve in the easiest possible way
Assuming your points are stored in the fashion p = [35,0; 40,0.2; 45,0], i.e.
p =
35.0000 0
40.0000 0.2000
45.0000 0
Then you can create an array for all x values by finding the mininum and maximum values of the x coordinate. Here, the x coordinate is the first column of p, i.e. p(:,1). You can use the colon operator : to create the x array by
x = min(p(:,1)) : 1 : max(p(:,1))
The 1 in the middle is the step width. For your example, this will create the array
x =
35 36 37 38 39 40 41 42 43 44 45
Now you can interpolate all y value linearly with the interp1 function. This does a linear interpolation by default. The syntax is thus
y = interp1(p(:,1), p(:,2), x)
Finally you can plot the vectors x and y using plot. If you only want to print circles, use 'o' as LineSpec specifier. To connect the circles using a line, use '-o'. There's an extensive list of options here. You can also add the color of the line / markers to this format spec. Black circles would be 'ok':
plot(x, y, 'ok')

How do I create a custom nonlinear filter?

So I am interested in creating a custom nonlinear filter. My mask is a 3 by 3 matrix and what I want to do is take my center point and look at the values directly neighboring it (excluding the diagonal elements). I want to subtract the middle element by each of those neighboring-values and then find either the minimum of these values. Basically Im looking at elevation data and I want to find the smallest delta-Z to the middle point.
Example:
Z = [64 21 31 59
38 30 92 26
81 47 43 60
53 23 18 71];
So lets say I was just looking at Z(3,3) = 43 for now. I would take 43 and subtract 92, 60, 18, and 47; yielding -49, -17, 25, and -4 respectively. Then I want it to only output -49. This process would repeat for every element in the Z matrix. How would I go about doing this? Thanks!
#chappjc's answer is perfectly acceptable. However, if you want to go in a colfilt inspired approach, you can transform your pixel neighbourhoods with im2col so that 3 x 3 overlapping neighbourhoods are placed into columns. What'll happen here is that the pixel neighbourhoods are constructed in a column-major format, so columns of each pixel neighbourhood are stacked into a single column. You would take all of these stacked columns and place them into a 2D matrix. In our case, the number of rows will be 9, while we will have as many columns as there are valid pixel neighbourhoods. This is the result of when you are using im2col. How the pixel neighbourhoods are obtained are again in column major format. Starting from the top left of the image, 3 x 3 pixel neighbourhoods are gathered progressing down the rows. Once we reach the bottom of the matrix, we then move to the next column, then progress down the rows again. This behaviour of how im2col works is vital for this algorithm to work.
Once you do this, extract the second, fourth, sixth and eighth rows of this respectively to obtain the west, north, south and east elements (the cardinal directions) in a neighbourhood. You would subtract the fifth row, which will be the centre of the neighbourhood with each of their respective cardinal directions, then take the minimum value. However, before you do this, you'll need to pad the array with a 1 pixel border so that you can process the border pixels in Z. This pixel border is assumed to be zero.
In other words, try doing something like this:
Zpad = padarray(Z, [1 1]);
A = im2col(Zpad, [3 3]);
cardinal_directions = A(2:2:8,:);
out = reshape(min(bsxfun(#minus, A(5,:), cardinal_directions), [], 1), size(Z));
Looks like a mouthful! Let's go through this slowly. I used padarray and created a 1 pixel border of zeroes that surrounds the original matrix Z and stored it in Zpad. I then use im2col to transform each 3 x 3 pixel neighbourhood of the padded result into columns of 9 elements each. I then extract the cardinal directions of each pixel neighbourhood by sampling the second, fourth, sixth and eighth rows of the output of im2col. Once I extract these cardinal directions, I extract the fifth row, which is the centre of each pixel neighbourhood and do a subtraction with their corresponding pixel neighbourhoods. I then take the minimum over all of the columns using min and operating over all of the rows (specifying the dimension of operation to be 1).
I use bsxfun to facilitate the subtraction of the centre pixel in each neighbourhood with their respective cardinal directions. This output will be a single vector, and so I will need to reshape the vector back into a matrix. This row vector has its elements arranged in column major format, so that's why I need to reshape the array back into a proper matrix.
This is what I get with your example:
out =
26 -43 -61 28
-43 -62 49 -66
28 -34 -49 -11
-28 -30 -53 11
If you want to double check that this is right, take a look at Z(2,2). We see that the centre element is 30, while the cardinal elements are 21, 38, 47 and 92. Taking 30 and subtracting with each element gives us 9, -8, -17 and -62. The minimum of all of these is -62 which is what is seen at out(2,2). Similarly, your example with Z(3,3) yields -49 at out(3,3), which is what you expected. You'll have to take care of what happens along the border of out. I zero-padded this matrix, and so there are entries along the border where you are taking the centre of the neighbourhood and subtracting with zero. You haven't properly defined what you want to do along the border, so I'm assuming that the cardinal directions along the border if you go outside of Z are zero in this case.
For min/max filtering, ordfilt2 is probably the most efficient (perhaps imdilate/imerode, but that's another story).
First, create a mask that indicates the four immediate neighbors to consider:
>> mask = false(3); mask([2 4 6 8]) = true
mask =
0 1 0
1 0 1
0 1 0
Filter with that mask:
>> Zmax = ordfilt2(Z,4,mask); % last value (4th non-zero) is max
>> out = Z - Zmax
out =
26 -43 -61 28
-43 -62 49 -66
28 -34 -49 -11
-28 -30 -53 11
Anyway, to manage negative numbers, remember to use a capable data type.
BTW, see this answer about using ordfilt2 and imdilate for peak finding, a similar task.

Convert correlation matrix to an RGB image matlab

I have a correlation Matrix outputed by the corr(X) function.
I need to display it in an RGB image format with the following specs.
Negative correlation should be red and possitive correlation should be green.
The values of the correlation matrix are in the range of [ -1 , 1 ].
1 -0,0286473845495979 0,185190317331816
-0,0286473845495979 1 -0,309327144422681
0,185190317331816 -0,309327144422681 1
I convert the matrix to the range of [ -255 , 255 ] and I need to display the negative values in red and the possitive values in green, with the corresponding color intensity ...
0 -262 208
-262 0 -334
208 -334 0
Any help would be great !
red = [1,0,0];
green = [0,1,0];
R = linspace(red(1),green(1),256);
G = linspace(red(2),green(2),256);
B = linspace(red(3),green(3),256);
map = [R', G', B'];
colormap(map)
colorbar
See How to create a custom colormap programmatically? for an explanation. Also you'll notice it goes a yellowy-brown in the middle. If you don't want this then I suggest either making the middle black or white, the answer I linked to should explain how to achieve that.