Read data from file: keep separation by empty line in file - matlab

I can make a matrix x and y from data.dat which consists of 2 columns using this code:
load data.dat
x=data(:,1);
y=data(:,2);
What if I want to make matrices x1, x2, ... xn and the same with y,
where x1, x2, are based on the separation by a blank line in the file data.dat:
54.510 1.420
55.294 1.819
55.859 1.935
55.999 2.381
9.017 1.600
9.518 1.916
9.868 2.217
9.896 2.368
10.113 2.533
10.424 2.552
.... ...
Based on this data example, I expect
x1=[54.510;55.294;55.859;55.999]
x2=[9.017;9.518;9.868;9.896;10.113;10.424]
y1=[1.420;1.819;1.935;2.381]
y2=[1.600;1.916;2.217;2.368;2.533;2.552]

You can use fgets to read the data from your file. It is assumed that your file is called test.dat:
(see the comments for explanations on the functionality)
% introduce a counter for all the 'blocks in the file'
block = 1;
% initialize empty vectors for x and y
x = [];
y = [];
% open the file (in this case 'test.dat')
file = fopen('test.dat');
% read the first line of the file
tline = fgets(file);
% continue as long as there are lines in the file
while ischar(tline)
% fgets returs a string, convert to float to process:
q = str2num(tline);
% if q is empty, we have a blank line, otherwise, append the values to
% x and y
if ~isempty(q)
x(end+1) = q(1);
y(end+1) = q(2);
else
% if there is a blank line, write x and y to a cell X and Y
% you need a cell here, because the number of elements per block may
% differ
X{block} = x;
Y{block} = y;
% advance the block counter
block = block + 1;
% clear and re-initialize x and y - this is necessary because the next
% block may contain less values. you do not want artifacts.
clear x y
x = [];
y = [];
end
% read the next line
tline = fgets(file);
% at the end of the file, fgets returns not a string but a number, -1
% in this case, assign x and y to X and Y
% no need to increment block, because you are at the end of the file
if tline == -1
X{block} = x;
Y{block} = y;
end
end
% close the file once all operations are done
fclose(file);
You now have a cell X and a cell Y which contain the data from your file. E.g.
X{1} =
Columns 1 through 2
54.51 55.294
Columns 3 through 4
55.859 55.999
I am aware that you won't get variables called x1, x2, ... xn with this approach. However, I believe that cells X{1}, X{2}, ... X{n} are both easier to generate, populate and handle than individual variables.

Related

Visualizing matrix values in real time

Suppose I have a 5x5 matrix.
The elements of the matrix change (are refreshed) every second.
I would like to be able to display the matrix (not as a colormap but with the actual values in a grid) in realtime and watch the values in it change as time progresses.
How would I go about doing so in MATLAB?
A combination of clc and disp is the easiest approach (as answered by Tim), here's a "prettier" approach you might fancy, depending on your needs. This is not going to be as quick, but you might find some benefits, such as not having to clear the command window or being able to colour-code and save the figs.
Using dispMatrixInFig (code at the bottom of this answer) you can view the matrix in a figure window (or unique figure windows) at each stage.
Example test code:
fig = figure;
% Loop 10 times, pausing for 1sec each loop, display matrix
for i=1:10
A = rand(5, 5);
dispMatrixInFig(A,fig)
pause(1)
end
Output for one iteration:
Commented function code:
function dispMatrixInFig(A, fig, strstyle, figname)
%% Given a figure "fig" and a matrix "A", the matrix is displayed in the
% figure. If no figure is supplied then a new one is created.
%
% strstyle is optional to specify the string display of each value, for
% details see SPRINTF. Default is 4d.p. Can set to default by passing '' or
% no argument.
%
% figname will appear in the title bar of the figure.
if nargin < 2
fig = figure;
else
clf(fig);
end
if nargin < 3 || strcmp(strstyle, '')
strstyle = '%3.4f';
end
if nargin < 4
figname = '';
end
% Get size of matrix
[m,n] = size(A);
% Turn axes off, set origin to top left
axis off;
axis ij;
set(fig,'DefaultTextFontName','courier', ...
'DefaultTextHorizontalAlignment','left', ...
'DefaultTextVerticalAlignment','bottom', ...
'DefaultTextClipping','on');
fig.Name = figname;
axis([1, m-1, 1, n]);
drawnow
tmp = text(.5,.5,'t');
% height and width of character
ext = get(tmp, 'Extent');
dy = ext(4);
wch = ext(3);
dwc = 2*wch;
dx = 8*wch + dwc;
% set matrix values to fig positions
x = 1;
for i = 1:n
y = 0.5 + dy/2;
for j = 1:m
y = y + 1;
text(x,y,sprintf(strstyle,A(j,i)));
end
x = x + dx;
end
% Tidy up display
axis([1-dwc/2 1+n*dx-dwc/2 1 m+1]);
set(gca, 'YTick', [], 'XTickLabel',[],'Visible','on');
set(gca,'XTick',(1-dwc/2):dx:x);
set(gca,'XGrid','on','GridLineStyle','-');
end
I would have thought you could achieve this with disp:
for i=1:10
A = rand(5, 5);
disp(A);
end
If you mean that you don't want repeated outputs on top of each other in the console, you could include a clc to clear the console before each disp call:
for i=1:10
A = rand(5, 5);
clc;
disp(A);
end
If you want to display your matrix on a figure it is quite easy. Just make a dump matrix and display it. Then use text function to display your matrix on the figure. For example
randMatrix=rand(5);
figure,imagesc(ones(20));axis image;
hold on;text(2,10,num2str(randMatrix))
If you want to do it in a for loop and see the numbers change, try this:
for i=1:100;
randMatrix=rand(5);
figure(1),clf
imagesc(ones(20));axis image;
hold on;text(2,10,num2str(randMatrix));
drawnow;
end

Errorbar line missing in Matlab

The following code produces the image shown:
probabilities = datasetlist(1,:);
avgscores = datasetlist(2,:);
x = probabilities;
y = probabilities;
err = avgscores;
hold on
for k = 1:length(x)
e1 = errorbar(x(k),y(k),err(k),'-');
if err(k) == min(err)
set(e1,'Color','r')
set(e1,'MarkerEdgeColor','r')
set(e1,'Marker','*')
else
set(e1,'Color','k')
set(e1,'MarkerEdgeColor','k')
set(e1,'Marker','.')
end
end
hold on
e1.LineStyle = '-';
But, there should be a line connecting the datapoints. I even set the e1.LineStyle, but that didn't work. How can I produce that line?
You have no line because you don't plot vectors, but single values each time, which is why you get something that is closer to a scatter plot.
Below are two of the ways to fix this:
Solution 1 is a workaround that changes your existing code minimally.
Solution 2 is much shorter code that achieves a same-looking result, by plotting vectors directly. (recommended).
function q40765062
%% Prepare the data:
datasetlist = [0.4:0.05:0.7; abs(randn(1,7))];
probabilities = datasetlist(1,:);
avgscores = datasetlist(2,:);
x = probabilities;
y = probabilities;
err = avgscores;
%% Solution 1:
figure();
hold on
for k = 1:length(x)
e1 = errorbar(x(k),y(k),err(k),'-');
if err(k) == min(err)
set(e1,'Color','r')
set(e1,'MarkerEdgeColor','r')
set(e1,'Marker','*')
else
set(e1,'Color','k')
set(e1,'MarkerEdgeColor','k')
set(e1,'Marker','.')
end
end
plot(x,y,'-k'); % < The main difference in this solution.
%% Solution 2:
figure();
[~,I] = min(err); % < We compute the index of the minimal value before plotting anything.
errorbar(x,y,err,'-*k'); hold on; % < Notice how we use the entire vectors at the same time.
errorbar(x(I),y(I),err(I),'-*r'); % < We only plot one value this time; in red.

Hough transform to detect and delete lines

I want to use the Hough transform to detect lines in my image.But instead of plotting the lines I want to delete each line detected in my original image.
image=imread('image.jpg');
image = im2bw(image);
BW=edge(image,'canny');
imshow(BW);
figure,imshow(BW);
[H,T,R] = hough(BW);
P = houghpeaks(H,100,'threshold',ceil(0.3*max(H(:))));
lines = houghlines(BW,T,R,P,'FillGap',5,'MinLength',7);
Now after this I have got all the lines. But I want to delete all these lines from my original image, keeping rest of the image as before. Is there some way I can do this?
Edit I am uploading an image.I want to delete all the lines and keep the circular part.This is just an example image.Basically my objective is to delete the line segments and keep rest of the image
The issue you have is that your lines are thicker than one pixel.
The lines from the hough transform seem to be one pixel thick and
that doesn't help.
I propose that you delete the lines that you get from the Hough transform first.
This will sort of divide the hockey rink of whatever it is into segments
that will be easier to process.
Then you label each segment with bwlabel. For each object, find the
endpoints and fit a line between the endpoints. If the line and the object
have more pixels in common than a certain threshold, then we say that the object
is a line and we delete it from the image.
You may have to play around with the Hough transform's threshold value.
This technique has some flaws though. It will delete a filled square,
rectangle or circle but you haven't got any of those so you should be ok.
Results
Explanation
This is your code that I modified a bit. I removed the gradient because it
it easier to work with solid objects. The gradient gave very thin lines.
I also work on the complement image because the bw functions work with 1
as forgound rather than 0 as in your original image.
org_image_bw=im2bw(double(imread('http://i.stack.imgur.com/hcphc.png')));
image = imcomplement(org_image_bw);
[H,T,R] = hough(image);
P = houghpeaks(H,100,'threshold',ceil(0.27*max(H(:))));
lines = houghlines(image,T,R,P,'FillGap',5,'MinLength',7);
Loop through the lines you have got and delete them
processed_image = image;
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
% // Use the question of a line y = kx + m to calulate x,y
% // Calculate the maximum number of elements in a line
numOfElems = max(max(xy(:,1))-min(xy(:,1)),max(xy(:,2))-min(xy(:,2)) ) ;
% // Cater for the special case where the equation of a line is
% // undefined, i.e. there is only one x value.
% // We use linspace rather than the colon operator because we want
% // x and y to have the same length and be evenly spaced.
if (diff(xy(:,1)) == 0)
y = round(linspace(min(xy(:,2)),max(xy(:,2)),numOfElems));
x = round(linspace(min(xy(:,1)),max(xy(:,1)),numOfElems));
else
k = diff(xy(:,2)) ./ diff(xy(:,1)); % // the slope
m = xy(1,2) - k.*xy(1,1); % // The crossing of the y-axis
x = round(linspace(min(xy(:,1)), max(xy(:,1)), numOfElems));
y = round(k.*x + m); % // the equation of a line
end
processed_image(y,x) = 0; % // delete the line
end
This is what the image looks after we have deleted the detected lines. Please note that the original hockey rink and been divided into multiple objects.
Label the remaining objects
L = bwlabel(processed_image);
Run through each object and find the end points.
Then fit a line to it. If, let's say 80% the fitted line covers
the object, then it is a line.
A fitted line could look like this. The diagonal blue line represents the fitted line and covers most of
the object (the white area). We therefore say that the object is a line.
% // Set the threshold
th = 0.8;
% // Loop through the objects
for objNr=1:max(L(:))
[objy, objx] = find(L==objNr);
% Find the end points
endpoints = [min(objx) min(objy) ...
;max(objx) max(objy)];
% Fit a line to it. y = kx + m
numOfElems = max(max(endpoints(:,1))-min(endpoints(:,1)),max(endpoints(:,2))-min(endpoints(:,2)) ) ;
% // Cater for the special case where the equation of a line is
% // undefined, i.e. there is only one x value
if (diff(endpoints(:,1)) == 0)
y = round(linspace(min(endpoints(:,2)),max(endpoints(:,2)),numOfElems));
x = round(linspace(min(endpoints(:,1)),max(endpoints(:,1)),numOfElems));
else
k = diff(endpoints(:,2)) ./ diff(endpoints(:,1)); % the slope
m = endpoints(1,2) - k.*endpoints(1,1); % The crossing of the y-axis
x = round(linspace(min(endpoints(:,1)), max(endpoints(:,1)), numOfElems));
y = round(k.*x + m);
% // Set any out of boundary items to the boundary
y(y>size(L,1)) = size(L,1);
end
% // Convert x and y to an index for easy comparison with the image
% // We sort them so that we are comparing the same pixels
fittedInd = sort(sub2ind(size(L),y,x)).';
objInd = sort(sub2ind(size(L),objy,objx));
% // Calculate the similarity. Intersect returns unique entities so we
% // use unique on fittedInd
fitrate = numel(intersect(fittedInd,objInd)) ./ numel(unique(fittedInd));
if (fitrate >= th)
L(objInd) = 0;
processed_image(objInd) = 0;
% // figure(1),imshow(processed_image)
end
end
Display the result
figure,imshow(image);title('Original');
figure,imshow(processed_image);title('Processed image');
Complete example
org_image_bw=im2bw(double(imread('http://i.stack.imgur.com/hcphc.png')));
image = imcomplement(org_image_bw);
[H,T,R] = hough(image);
P = houghpeaks(H,100,'threshold',ceil(0.27*max(H(:))));
lines = houghlines(image,T,R,P,'FillGap',5,'MinLength',7);
processed_image = image;
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
% // Use the question of a line y = kx + m to calulate x,y
%Calculate the maximum number of elements in a line
numOfElems = max(max(xy(:,1))-min(xy(:,1)),max(xy(:,2))-min(xy(:,2)) ) ;
% // Cater for the special case where the equation of a line is
% // undefined, i.e. there is only one x value.
% // We use linspace rather than the colon operator because we want
% // x and y to have the same length and be evenly spaced.
if (diff(xy(:,1)) == 0)
y = round(linspace(min(xy(:,2)),max(xy(:,2)),numOfElems));
x = round(linspace(min(xy(:,1)),max(xy(:,1)),numOfElems));
else
k = diff(xy(:,2)) ./ diff(xy(:,1)); % the slope
m = xy(1,2) - k.*xy(1,1); % The crossing of the y-axis
x = round(linspace(min(xy(:,1)), max(xy(:,1)), numOfElems));
y = round(k.*x + m); % // the equation of a line
end
processed_image(y,x) = 0; % // delete the line
end
% // Label the remaining objects
L = bwlabel(processed_image);
% // Run through each object and find the end points.
% // Then fit a line to it. If, let's say 80% the fitted line covers
% // the object, then it is a line.
% // Set the threshold
th = 0.8;
% // Loop through the objects
for objNr=1:max(L(:))
[objy, objx] = find(L==objNr);
% Find the end points
endpoints = [min(objx) min(objy) ...
;max(objx) max(objy)];
% Fit a line to it. y = kx + m
numOfElems = max(max(endpoints(:,1))-min(endpoints(:,1)),max(endpoints(:,2))-min(endpoints(:,2)) ) ;
% Cater for the special case where the equation of a line is
% undefined, i.e. there is only one x value
if (diff(endpoints(:,1)) == 0)
y = round(linspace(min(endpoints(:,2)),max(endpoints(:,2)),numOfElems));
x = round(linspace(min(endpoints(:,1)),max(endpoints(:,1)),numOfElems));
else
k = diff(endpoints(:,2)) ./ diff(endpoints(:,1)); % the slope
m = endpoints(1,2) - k.*endpoints(1,1); % The crossing of the y-axis
x = round(linspace(min(endpoints(:,1)), max(endpoints(:,1)), numOfElems));
y = round(k.*x + m);
% // Set any out of boundary items to the boundary
y(y>size(L,1)) = size(L,1);
end
% // Convert x and y to an index for easy comparison with the image
% // We sort them so that we are comparing the same pixels
fittedInd = sort(sub2ind(size(L),y,x)).';
objInd = sort(sub2ind(size(L),objy,objx));
% Calculate the similarity. Intersect returns unique entities so we
% use unique on fittedInd
fitrate = numel(intersect(fittedInd,objInd)) ./ numel(unique(fittedInd));
if (fitrate >= th)
L(objInd) = 0;
processed_image(objInd) = 0;
% // figure(1),imshow(processed_image)
end
end
% // Display the result
figure,imshow(image);title('Original');
figure,imshow(processed_image);title('Processed image');
You could use J. E. Bresenham's algorightm. It is implemented by A. Wetzler in the following matlab function, which I tested myself.
The algorithm will give you the pixel coordinates of where the line would be, given that you will provide the start and end point of the line, which is already given in lines in your code above.
Here is the code I used, which uses the matlab function referenced above:
%This is your code above ========
image=imread('hcphc.png');
image = im2bw(image);
BW=edge(image,'canny');
imshow(BW);
figure,imshow(BW);
[H,T,R] = hough(BW);
P = houghpeaks(H,100,'threshold',ceil(0.3*max(H(:))));
lines = houghlines(BW,T,R,P,'FillGap',5,'MinLength',7);
% =========
% Proposed solution:
% This will work for as many lines as you detected
for k=1:length(lines)
% Call Bresenham's algorithm
[x, y] = bresenham(lines(k).point1(1), lines(k).point1(2), ...
lines(k).point2(1), lines(k).point2(2));
% This is where you replace the line, here I use 0, but you can use
% whatever you want. However, note that if you use BW, you should only
% replace with 0 or 1, because is a logical image. If you want to use
% the original image, well, you know what to do.
BW(y, x) = 0;
% And now watch the lines disapear! (you can remove this line)
imagesc(BW), drawnow; pause(1);
end
Remember, download the matlab function first.

Matlab: appending cell array

I have 10 binary files, each storing a list of numbers. I want to load each file in turn, and then append a cell array y with the numbers in that file. So if each file contains 20 numbers, I want my final cell to be 10x20. How do I do this? The following code does not work:
for i=1:10
% Load an array into variable 'x'
y = {y x}
end
You only need a minor modification to your code:
y = cell(1,10); %// initiallize if possible. Not necessary
for ii = 1:10 %// better not use i as a variable (would override imaginary unit)
%// Load an array into variable 'x'
y{ii} = x; %// fill ii-th cell with x.
%// Or use y{end+1} = x if you haven't initiallized y
end
If you are reading strictly numbers and want an array (rather than cells), this could work:
% read CSV numbers from file into array
temp = {};
out = [];
for i=1:10
% my example files were called input1.txt, input2.txt, etc
filename = strcat('input', num2str(i), '.txt');
fid = fopen(filename, 'r');
temp = textscan(fid,'%d','delimiter',',');
out(i,:) = cell2mat(temp);
fclose(fid);
end
'out' is a 10x20 array

how to output all the iteration results from a FOR loop into matrix and plot the graph

I have two for loops in a nested format. My second loop calculates the final equation. The display of the result is outside the second loop in order to display when the second loop is complete.
Below is the logic I used in MATLAB. I need to plot graph of eqn2 vs x.
L=100
for x=1:10
eqn1
for y=1:L
eqn2
end
value = num2strn eqn2
disp value
end
Currently the problem I am facing is that value or output of eqn2 is always replaced after each cycle until x reaches 10. Hence, the workspace table of eqn2 and value only shows the last value. My intention is to document all the output values of value in every cycle of x from 1:10.
How can I do this?
You pseudo-coded a little too strongly for my taste - I have tried to reconstruct what you were trying to do. If I understood correctly, this should do address your question (store intermediate results from the calculation in array Z):
L=100
z = zeros(L,10);
for x=1:10
% perform some calculations
eqn1
for y=1:L
% perform some more calculations; it is not clear whether the result of
% this loop over y=1:L yields one value, or L. I am going to assume L values
z(y, x) = eqn2(x, y)
end
value =num2strn eqn2
disp value
end
% now you have the value of each evaluation of the innermost loop available. You can plot it as follows:
figure;
plot( x, z); % multiple plots with a common x parameter; may need to use Z' (transpose)...
title 'this is my plot';
xlabel 'this is the x axis';
ylabel 'this is the y axis';
As for the other questions you asked in your comments, you could probably findd inspiration in the following:
L = 100;
nx = 20; ny = 99; % I am choosing how many x and y values to test
Z = zeros(ny, nx); % allocate space for the results
x = linspace(0, 10, nx); % x and y don't need to be integers
y = linspace(1, L, ny);
myFlag = 0; % flag can be used for breaking out of both loops
for xi = 1:nx % xi and yi are integers
for yi = 1:ny
% evaluate "some function" of x(xi) and y(yi)
% note that these are not constrained to be integers
Z(yi, xi) = (x(xi)-4).^2 + 3*(y(yi)-5).^2+2;
% the break condition you were asking for
if Z(yi, xi) < 5
fprintf(1, 'Z less than 5 with x=%.1f and y=%.1f\n', x(xi), y(yi));
myFlag = 1; % set flag so we break out of both loops
break
end
end
if myFlag==1, break; end % break out of the outer loop as well
end
This may not be what you had in mind - I cannot understand "run the loop untill all the values of z(y,x) <5 and then it should output x". If you run the outer loop to completion (that's the only way you know "all the values of z(y,x)" then your value of x will be the last value it was... This is why I was suggesting running through all values of x and y, collecting the whole matrix Z, and then examining Z for the things you want.
For example, if you wonder if there is a value for X for which all Z < 5, you could do this (if you didn't break out of the for loops):
highestZ = max(Z, [], 1); % "take the highest value of Z in the 1 dimension
fprintf(1, 'Z is always < 5 for x = %d\n', x(highestZ<5));
etc.
If you can't figure it out from here, I give up...