How to find K random different pixels in an image? [duplicate] - matlab

This question already has answers here:
Randomly Selecting Pixels in a Picture Matlab
(3 answers)
Closed 7 years ago.
I know how to find a random pixel by using rand function, for both x&y in the limits of the image. Then do it K times with a loop.
However I'd like to do it in smarter way and make sure I don't pick the same
(x, y) coordinate. Thanks in advance!

Use randperm (no toolbox required):
K = 10;
[h, w, c] = size(image);
[X, Y] = ind2sub([h w], randperm(h*w, K));

The tricky part here is avoiding repetition. If you have the Statistics Toolbox you can use randsample:
k = 10;
[m,n] = size(image(:,:,1)); %// works with 3- and 1-channel images
s = randsample(m*n, k); %// get k random indices
[X, Y] = ind2sub([m, n], s); %// convert indices to x,y coordinates
On my test run with a 512x512x3 image I got the following coordinates:
X =
464 143 174 235 437 201 348 272 212 260
Y =
499 449 508 148 107 114 341 196 60 224

randi generates integers between 1 and a specified limit, you can use that with your image size to generate pixel coordinates. To make sure you don't pick the same coordinates again maintain a matrix of logicals and mark pixels you are picking.
If you just want to pick K random pixels from the image I would suggest use something like randi(imgSize,K,2) to generate a matrix of indices. You could end up with duplicates in the matrix and to eliminate those you can use unique with the 'rows' argument.

Related

Grouping neighbours in separate arrays in MATLAB

I have an annotated 512x512x3 fingerprint image, with the annotations being the positions of loops and deltas in the image. Red denotes loop, and blue denotes delta.
I need to find the position of these points. I can do this using impixel(), but I wanted a more automated approach.
I did the following:
x=[];
y=[];
for i = 1:512
for j = 1:512
marked = im(i,j,:);
if marked(:,:,1)==255
x=[x i];
y=[y j];
end
end
end
x = unique(x);
y = unique(y);
and got the positions of the pixels where the color red is the position of the loops.
My array y holds the y coordinates of all the red pixels, like this:
[116 117 118 119 120 121 122 191 192 193 194 195 196 197]
At first glance, it is clear that the values can be grouped into 2 groups, for the two red points. But I am unsure how to divide the values into two groups. I thought about creating a threshold using the mean of the values, but that might not work if the points are close by.
Any help might be useful.
If you know in advance how many red points there will be (2 in the example), you could use kmeans -
y_groups = kmeans(y',2);
If you don't know the number of groups, then if the points always contain the same number of pixels, you could work it out from that - in the example there are 7 pixels per point so
npts = numel(y) / 7;
y_groups = kmeans(y',npts);
We could add a loop afterwards to get the mean of each group (there are many other ways you could look into for this too e.g. grpstats):
y_means = NaN(npts,1);
for I = 1:npts
y_means(I) = mean(y(y_groups == I));
end

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')

MATLAB Data Interpolation - Basics

I have a dataset consisting of a position and a signal - the signal is sampled at scattered positions (0, 115, 230....):
0 1.709219858
115 1.676595745
230 1.643026005
345 1.609456265
460 1.574940898
575 1.540898345
690 1.506855792
806 1.473286052
I would like to smooth this data and then interpolate it to fill in the intervening positions i.e.:
0 x
1 x
2 x
3 x
4 x
5 x
6 x
7 x
8 x
9 x
10 x
Where x is the smoothed signal. I've been smoothing data with the commands:
>> hann250=hanning(250);
>> smooth250=conv(signal,hann250,'same');
But I am not sure at all how to interpolate the data - what commands can I use and what would I type? I'm totally new to MATLAB! I am also not sure what interpolation method I need but I intend to try various one's and see (once I know how!). Thanks,
T
You could try spline interpolation:
http://www.mathworks.com/help/matlab/ref/spline.html
% read x, y from your file
xx = linspace(min(x), max(x), 1000); % generate 1000 equally spaced points
yy = spline(x,y,xx); % interpolate
plot(x,y); % original
hold all;
plot(xx,yy); % new
You can use interp1:
data = [0 1.7092
115.0000 1.6766
230.0000 1.6430
345.0000 1.6095
460.0000 1.5749
575.0000 1.5409
690.0000 1.5069
806.0000 1.4733];
index_interp = 0:806; %// indices on which to interpolate
data_interp = interp1(data(:,1),data(:,2),index_interp,'linear');
There are other interpolation methods available in addition to 'linear'; see the above link.

Resampling Matrix and restoring in one single Matrix

I am new to this forum, so please bear with me.
I have been working on this Matlab problem for a while now:
I have a digital elevation model (DEM) new_sub(x,y) in tif format. So it is a x-by-y matrix containing heights (z). I wish to resample parts of this DEM in different resolutions and restore this in another matrix. So far I have been working with for loops to change the resolution of different areas of the DEM and then wrote the results to an xyz-file:
x y z
1 1 123
1 2 233
1 3 231
2 1 235
2 2 531
2 3 452
and so forth.
Here is the code:
xmax = size(new_sub,2);
ymax = size(new_sub,1);
for k=1:200 % y
for l=1:xmax % x
fprintf(fid, '%d %d %d \n',l,xmax+1-k,new_sub(k,l));
end
end
% 1:4
for k=200/2+1:size(new_sub,1)/2
for l=1:size(new_sub,2)/2
fprintf(fid, '%d %d %d \n',l*2,ymax+2-k*2,new_sub(k*2,l*2));
end
end
This does work, but seems to be rather complicated. Moreover, it does not allow me to store the resampled areas in a single matrix within Matlab.
Is there a more efficient way of resampling certain areas of a Matrix with different resolutions, writing them into a new Matrix containg all resampled areas and then writing it to a file? I was looking into repmap, but could not think of a clever way of using it!
Your help is much appreciated!
THeo
To re-sample a matrix in Matlab:
For example matrix M:
M = [1 2 3 4 5;
6 7 8 9 10;
11 12 13 14 15;
16 17 18 19 20;
21 22 23 24 25];
If we wanted to sample on every nth pixel, it is as simple as this:
m = M(1:n:end, 1:n:end)
So for n=2
m = 1 3 5
11 13 15
21 23 25
I suggest you read up on indexing in matlab and also on using the colon operator to create vectors in matlab
Now in order to get in the "x y z" format you mentioned, first use meshgrid to generate matrices of X and Y coordinates.
[X, Y] = meshgrid(1:n:size(M,1), 1:n:size(M,2))
notice I use n to downsample X and Y. Now you just need to flatten the three matrices and combine them:
final = [X(:), Y(:), m(:)]
Finally to save as a file I suggest you type help save or help dlmwrite in the Matlab command promt and use either of those functions to save final
To me the easiest way to do looks like using imresize. You can treat your elevation map as an image I. Then you can cut sections out by indexing and rescaling as follows:
I = imread('my.tiff'); % read
section = I(1:200, :); % cut the first 200 rows and all columns
sectionResized = imresize(section, [numrows numcols]) % resample
imwrite(sectionResized, 'mynew.tiff'); % save