How to save the size of image in txt file with matlab - image

I want to find the size of an image (height, width, and area) and save the size value in txt file. I tried this command:
img = imread('TN4.jpg');
abu=rgb2gray(img);
imwrite(abu,'abu.jpg');
cb=imclearborder(abu);
imwrite(cb,'cb.jpg')
thresh=graythresh(cb);
b=im2bw(cb,thresh);
imwrite(b,'b.jpg');
bw=bwareaopen(b,100);
bwfill=imfill(bw,'holes');
imwrite(bwfill,'bw.jpg');
s = regionprops(bwfill,'BoundingBox');
out = bsxfun(#times,img,uint8(bwfill));
objects=cell(numel(s),1);
for idx = 1:numel(s)
bb=floor(s(idx).BoundingBox);
objects{idx} = out(bb(2):bb(2)+bb(4), bb(1):bb(1)+bb(3),:);
end
k1=objects{1};
c1=rgb2gray(k1);
t1=graythresh(c1);
biner1=im2bw(c1,t1);
[height, width] = size(biner1);
a1 = bwarea(biner1);
h1=height(biner1);
w1=width(biner1);
X = [(h1);(w1);(a1)];
save datagrading.txt X -ascii
but i got warning massage
??? Index exceeds matrix dimensions.
Error in ==> exercise at 35
h1=height(biner1);
can anyone help me?
Thank you

height and width are scalars yet (it looks like to me...) you are assuming that they are functions.... no they're not functions. Just use height and width on its own and place it into your X matrix:
[height, width] = size(biner1);
a1 = bwarea(biner1);
%h1=height(biner1); %// Remove
%w1=width(biner1); %// Remove
X = [height;width;a1]; %// Change
save datagrading.txt X -ascii
Since you have multiple objects and you want to save the height, width and area of these objects, just loop over each one, find the quantities you desire, place them into an overall matrix and save it:
X = zeros(3, numel(objects));
for k = 1 : numel(objects)
k1=objects{k}; %// Change
c1=rgb2gray(k1);
t1=graythresh(c1);
biner1=im2bw(c1,t1);
[height, width] = size(biner1);
a1 = bwarea(biner1);
X(:,k) = [height;width;a1];
end
save datagrading.txt X -ascii
X is now a 3 x s matrix where s is the total number of objects you have. Therefore, each column contains the height, width and area of each object.

You declared
[height, width] = size(biner1);
So height(biner1) will refer to the biner1-th element of height, which is not existent.
Use X = [(height);(width);(a1)]; instead.

Related

Matlab - Scale Colorbar of Image

How can I scale the colorbar axis of a false color image?
I read this post,and copied the code but it seems not to work correctly:
MATLAB Colorbar - Same colors, scaled values
Please see the two images below. In the first (without the scaling) the coloraxis goes
[1 2 3 4 5 6]*10^4
In the second image, it goes
[0.005 0.01 0.015 0.02 0.025]
The correct scaling (with C = 100000) would be
[0.1 0.2 0.3 0.4 0.5 0.6]
Without scaling
Wrong scaling
I want that the coloraxis is scaled by 1/C and I can freely choose C, so that when the pixel value = 10^4 and C=10^6 the scale should show 10^-2.
The reason why I multiply my image first by C is to get more decimals places, because all values below 1 will be displayed as zero without the C scaling.
When I run the code I get yticks as a workspace variable with the following values:
[500 1000 1500 2000 2500]
My code:
RGB = imread('IMG_0043.tif');% Read Image
info = imfinfo('IMG_0043.CR2'); % get Metadata
C = 1000000; % Constant to adjust image
x = info.DigitalCamera; % get EXIF
t = getfield(x, 'ExposureTime');% save ExposureTime
f = getfield(x, 'FNumber'); % save FNumber
S = getfield(x, 'ISOSpeedRatings');% save ISOSpeedRatings
date = getfield(x,'DateTimeOriginal');
I = rgb2gray(RGB); % convert Image to greyscale
K = 480; % Kamerakonstante(muss experimentel eavaluiert werden)
% N_s = K*(t*S)/power(f,2))*L
L = power(f,2)/(K*t*S)*C; %
J = immultiply(I,L); % multiply each value with constant , so the Image is Calibrated to cd/m^2
hFig = figure('Name','False Color Luminance Map', 'ToolBar','none','MenuBar','none');
% Create/initialize default colormap of jet.
cmap = jet(16); % or 256, 64, 32 or whatever.
% Now make lowest values show up as black.
cmap(1,:) = 0;
% Now make highest values show up as white.
cmap(end,:) = 1;
imshow(J,'Colormap',cmap) % show Image in false color
colorbar % add colorbar
h = colorbar; % define colorbar as variable
y_Scl = (1/C);
yticks = get(gca,'YTick');
set(h,'YTickLabel',sprintfc('%g', [yticks.*y_Scl]))
ylabel(h, 'cd/m^2')% add unit label
title(date); % Show date in image
caxis auto % set axis to auto
datacursormode on % enable datacursor
img = getframe(gcf);
nowstr = datestr(now, 'yyyy-mm-dd_HH_MM_SS');
folder = 'C:\Users\Taiko\Desktop\FalseColor\';
ImageFiles = dir( fullfile(folder, '*.jpg') );
if isempty(ImageFiles)
next_idx = 1;
else
lastfile = ImageFiles(end).name;
[~, basename, ~] = fileparts(lastfile);
file_number_str = regexp('(?<=.*_)\d+$', basename, 'match' );
last_idx = str2double(file_number_str);
next_idx = last_idx + 1;
end
newfilename = fullfile( folder, sprintf('%s_%04d.jpg', nowstr, next_idx) );
imwrite(img.cdata, newfilename);
Problems:
1) You are getting YTick of the figure (gca) but not the color bar. That would give you the "pixel" coordinates of the graph, instead of the actual values. Use yticks = get(h,'YTick');.
2) caxis auto Should come before overwriting YTicks (and after enabling the color bar); otherwise the scale and ticks will mismatch.
3) Do you mean C = 100000?
Result:

Mid line through a set of dicom images in matlab

I have a set of Dicom images on matlab and i would like to add a midline going through all the images
I am outputting the images via imshow3d function
thanks
Edit: here's what i have, the random points are not in the middle they just run through the image
>> clc;
>>clear;
>>%imports dicom images
>>run DicomImport.m;
>>%random points for shortest distance test
>>a = [1 10 200];
>>b = [500 512 300];
>>ab = b - a;
>>n = max(abs(ab)) + 1;
>>s = repmat(linspace(0, 1, n)', 1, 3);
>>for d = 1:3
>> s(:, d) = s(:, d) * ab(d) + a(d);
>>end
>>s = round(s);
>>Z = 593;
>>N = 512;
>>X = zeros(N, N, Z);
>>X(sub2ind(size(X), s(:, 1), s(:, 2), s(:, 3))) = 1;
>>C = find(X);
>>ans.Img(C) = 5000;
>> %shows image
>>imshow3D(ans.Img);
So it looks like ans.Img contains the 3D matrix consisting of your image stack. It looks like you've got something going, but allow me to do this a bit differently. Basically, you need to generate a set of coordinates where we can access the image stack and draw a vertical line in the middle of the each image in the image stack. Do something like this. First get the dimensions of the stack, then determine the halfway point for the columns. Next, generate a set of coordinates that will draw a line down the middle for one image. After you do this, repeat this for the rest of the slices and get the column major indices for these:
%// Get dimensions
[rows,cols,slices] = size(ans.Img);
%// Get halfway point for columns
col_half = floor(cols/2);
%// Generate coordinates for vertical line for one slice
coords_middle_row = (1:rows).';
coords_middle_col = repmat(col_half, rows, 1);
%// Generate column major indices for the rest of the slices:
ind = sub2ind(size(ans.Img), repmat(coords_middle_row, slices, 1), ...
repmat(coords_middle_col, slices, 1), ...
reshape(kron(1:slices, ones(rows, 1)), [], 1));
%// Set the pixels accordingly
ans.Img(ind) = 5000;
This code is quite similar to the answer I provided to one of your earlier question; i.e. I don't use imshow3D but the framework is similar and simpler to modify in order to suit your need. In this case, upon pressing a pushbutton a line appears at the middle of the stack and you can scroll through it with the slider. I hope this can be of help.
function LineDicom(~)
clc
clear
close all
%// Load demo data
S = load('mri');
%// Get dimensions and number of slices.
ImageHeight = S.siz(1); %// Not used here
ImageWidth = S.siz(2); %// Not used here
NumSlices = S.siz(3);
S.D = squeeze(S.D);
%// Create GUI
hFig = figure('Position',[100 100 400 400],'Units','normalized');
%// create axes with handle
handles.axes1 = axes('Position', [0.2 0.2 0.6 0.6]);
%// create y slider with handle
handles.y_slider = uicontrol('style', 'Slider', 'Min', 1, 'Max', NumSlices, 'Value',1, 'Units','normalized','position', [0.08 0.2 0.08 0.6], 'callback', #(s,e) UpdateY);
handles.SlideryListener = addlistener(handles.y_slider,'Value','PostSet',#(s,e) YListenerCallBack);
%// Create pusbutton to draw line
handles.DrawLineButton= uicontrol('style', 'push','position', [40 40 100 30],'String','Draw line', 'callback', {#DrawLine,handles});
%// Flag to know whether pushbutton has been pushed
handles.LineDrawn = false;
%// Show 1st slice
imshow(S.D(:,:,1))
guidata(hFig,handles);
%// Listeners callbacks followed by sliders callbacks. Used to display each
%// slice smoothly.
function YListenerCallBack
handles = guidata(hFig);
%// Get current slice
CurrentSlice = round(get(handles.y_slider,'value'));
hold on
imshow(S.D(:,:,CurrentSlice));
%// If button was button, draw line
if handles.LineDrawn
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
end
drawnow
guidata(hFig,handles);
end
function UpdateY(~)
handles = guidata(hFig); %// Get handles.
CurrentSlice = round(get(handles.y_slider,'value'));
hold on
imshow(S.D(:,:,CurrentSlice));
if handles.LineDrawn
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
end
drawnow
guidata(hFig,handles);
end
%// Pushbutton callback to draw line.
function DrawLine(~,~,handles)
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
handles.LineDrawn = true;
guidata(hFig,handles);
end
end
Sample output:
and after moving the slider up:
Is this what you meant? If not I'll remove that answer haha and sorry.

Skipping some axis labels in a plot with imagesc

I have created a big heat map using matlab's imagesc command. It plots the error output for each combination of the values in x and y axes. As can be seen in the figure there are too many axes labels. This might become even denser as I plan to increase the number of points in both x and y axes - which means I will get more outputs on a finer grid.
I want to be flexible with the labels, and skip some of them. I want to do this for both X and Y. I also want to be flexible with the "ticks" and draw either all of them or maybe skip some of them. Keep in mind that both the X and Y values are not increasing in order, at first the increment is 0.01 for 9 points, then 0.1, then 1 or 3 or whatever. I will change these increments too.
I tried to show what I want the graph look like in the second image. I want roughly the labels shown in red boxes only. As I said these are not set values, and I will make the increments smaller which will lead to denser plot.
Thank you for your help.
OS: Windows 7, 8 (64 bit)
Matlab version: Matlab 2014 a
You can manipulate the ticks and labels like this:
ticksarray=[1 33 41 100 ...] % edit these to whatever you want
tickslabels={'1', '33', '41', '100'; ...} % match the size of both arrays
set(gca,'XTick',ticksarray)
set(gca,'XTickLabel',tickslabels)
The same thing applies to the y-axis.
Small working example:
x=1:100;
y=2*x.^2-3*x+2;
plot(x,y)
ticksarray=[1 33 41 100];
tickslabels={'1', '33', '41', '100'};
set(gca,'XTick',ticksarray)
set(gca,'XTickLabel',tickslabels)
Example:
figure(1)
load clown
subplot(211)
imagesc(X);
subplot(212)
imagesc(X);
h = gca;
Now you can either set a maximum number of labels per axis:
%// define maximum number of labels
maxLabel = 3;
h.XTick = linspace(h.xlim(1),h.xlim(2),maxLabel);
h.YTick = linspace(h.ylim(1),h.ylim(2),maxLabel);
or define how many labels should be skipped:
%// define number of labels to skip
skipLabel = 2;
h.XTick = h.XTick(1:skipLabel:end);
h.YTick = h.YTick(1:skipLabel:end)
You can also get a different number of ticks and labels, more complicated though:
maxLabel = 3;
maxTicks = 6;
h.XTick = linspace(h.xlim(1),h.xlim(2),maxTicks);
h.YTick = linspace(h.ylim(1),h.ylim(2),maxTicks);
h.XTickLabel( setdiff( 1:maxTicks, 1:maxTicks/maxLabel:maxTicks ) ) = repmat({''},1,maxTicks-maxLabel);
h.YTickLabel( setdiff( 1:maxTicks, 1:maxTicks/maxLabel:maxTicks ) ) = repmat({''},1,maxTicks-maxLabel);
If you use a prior version of Matlab 2014b, then you will need the set command to set all properties:
%// define maximum number of labels
maxLabel = 3;
Xlim = get(h,'Xlim');
Ylim = get(h,'Ylim');
set(h,'XTick', linspace(Xlim(1),Xlim(2),maxLabel));
set(h,'YTick', linspace(Ylim(1),Ylim(2),maxLabel));
%// or define number of labels to skip
skipLabel = 2;
XTick = get(h,'XTick');
YTick = get(h,'YTick');
set(h,'XTick', XTick(1:skipLabel:end));
set(h,'YTick', YTick(1:skipLabel:end));
%// or combined
maxLabel = 3;
maxTicks = 6;
Xlim = get(h,'Xlim');
Ylim = get(h,'Ylim');
set(h,'XTick', linspace(Xlim(1),Xlim(2),maxTicks));
set(h,'YTick', linspace(Ylim(1),Ylim(2),maxTicks));
XTickLabel = cellstr(get(h,'XTickLabel'));
YTickLabel = cellstr(get(h,'YTickLabel'));
XTickLabel( setdiff( 1:maxTicks, 1:maxTicks/maxLabel:maxTicks ),: ) = repmat({''},1,maxTicks-maxLabel);
YTickLabel( setdiff( 1:maxTicks, 1:maxTicks/maxLabel:maxTicks ),: ) = repmat({''},1,maxTicks-maxLabel);
set(h,'XTickLabel',XTickLabel);
set(h,'YTickLabel',YTickLabel);
After applying the second method proposed by #thewaywewalk I got the second figure below. Apparently the labels need to be structured as well, because they only take the first so many labels.
Then I tried to manipulate the labels as shown below, and got the third image.
skipLabel = 2;
XTick = get(h,'XTick');
YTick = get(h,'YTick');
set(h,'XTick', XTick(1:skipLabel:end));
set(h,'YTick', YTick(1:skipLabel:end));
XTickLabel = get(h,'XTickLabel');
labelsX = cell( length(1: skipLabel:length(XTick)) , 1);
j = 1;
for i = 1: skipLabel:length(XTick)
labelsX{j} = XTickLabel(i, :);
j = j + 1;
end
set(h,'XTickLabel', labelsX);
YTickLabel = get(h,'YTickLabel');
labelsY = cell( length(1: skipLabel:length(YTick)) , 1);
j = 1;
for i = 1: skipLabel:length(YTick)
labelsY{j} = YTickLabel(i, :);
j = j + 1;
end
set(h,'YTickLabel', labelsY);
The Y axis labels seem to be in place as before (right next to tick), however the X axis labels seem to be shifted to the left a little. How can I correct this?
Another note: How can I change the scientific values into normal numbers? Also, probably there is a better approach at manipulating the labels.

matlab plot graph of data over an image

What I would like to do is plot an image of a graph (from say a pdf file or a scanned image). Next, I would like to overlay an axis on the graph in the image, and then plot data on that axis (over the image).
Using imtool, I know the coordinates of the graph in the image (x range = ~52-355 pixels, and y range = 23(top) - 262(bottom) pixels in this case).
This is what I have tried:
I = imread('C:\MATLAB\R2014a\help\images\ref\ftrans2_fig.png');
I = squeeze(uint8(mean(I,3)));
figure, imshow(I)
[rows, cols] = size(I);
x_data = (-1 : .01 : +1)';
y_data = 1 - x_data.^2;
h1 = axes('Position',([52, 23, 355-52, 262-23] ./ [cols, rows, cols, rows] ));
set(h1, 'Color', 'none')
hold on
plot(x_data, y_data, '-rx')
Question: Knowing the pixel coordinates of the graph in the image, how do I determine the proper position of the axis in the figure, (my code fails to account for the actual size of the figure box, the gray border around the image). I have to do this for several images and sets of data, so I would like an automated method, assuming I find the coordinates of the graphs in the image ahead of time.
Thanks for your reply! (1st time posting, please be kind)
You may be able to solve your problem by forcing the image onto the same axis as the plot. Try this:
I = imread('C:\MATLAB\R2014a\help\images\ref\ftrans2_fig.png');
I = squeeze(uint8(mean(I,3)));
[rows, cols] = size(I);
x_data = (-1 : .01 : +1)';
y_data = 1 - x_data.^2;
h1 = axes('Position',([52, 23, 355-52, 262-23] ./ [cols, rows, cols, rows] ));
set(h1, 'Color', 'none')
hold on
image(I, 'Parent', h1);
plot(h1, x_data, y_data, '-rx')
That should at ensure that the plot axis and the image axis have the same origin, as they will be one and the same. You may need to adjust your sizing code. Let me know if that doesn't do it for you.
Good Luck!
I think I have it figured out.
It would have been easier if I could use:
figure, h1=imshow(I)
get(h1,'Position')
but that results in "The name 'Position' is not an accessible property for an instance of class 'image'."
Instead, this appears to work:
I = imread('C:\MATLAB\R2014a\help\images\ref\ftrans2_fig.png');
I = squeeze(uint8(mean(I,3)));
in_mag = 300;
figure, imshow(I, 'Border', 'tight', 'InitialMagnification', in_mag)
[rows, cols] = size(I);
x_data = (-1 : .01 : +1)';
y_data = 1 - x_data.^2;
% Coord of graph in image pixels
x_0 = 50; x_max = 354; y_0 = 262; y_max = 23;
h1 = axes('Position',([x_0, rows-y_0, x_max-x_0, y_0-y_max] ...
./ [cols, rows, cols, rows] ));
set(h1,'Color','none')
hold on
plot(x_data, y_data, '-rx')
ylim([0,1.4])
set(gca,'YColor', [0 0 1], 'XColor', [0 0 1])
However, if anybody has a better idea, I would be very happy to explore it!
Thanks

Image with accordion effect

I have read in an image file to MATLAB and I am trying to stretch it in one direction, but a variable amount (sinusoidal). This would create an accordion affect on the image. I have toyed around with imresize, however that only resizes the image linearly. I would like the amount of "stretch" to vary for each image line. I tried to convey this with the following code:
periods = 10; % Number of "stretch" cycles
sz = size(original_image,2)/periods;
s = 0;
x = 0;
for index = 1:periods
B = original_image(:,round(s+1:s+sz));
if mod(index,2) == 0
amp = 1.5;
else
amp = 0.75;
end
xi = size(B,2)*amp;
new_image(:,x+1:x+xi) = imresize(B, [size(B,1) size(B,2)*amp]);
s = s + sz;
x = x+xi;
end
You can see that segments of the image are stretched, then compressed, then stretched, etc, like an accordion. However, each segment has a uniform amount of stretch, whereas I'd like it to be increasing then decreasing as you move along the image.
I have also looked at MATLAB's example of Applying a Sinusoidal Transformation to a Checkerboard which seems very applicable to my problem, however I have been trying and I cannot get this to produce the desired result for my image.
Any help is much appreciated.
UPDATE:
Thank you for Answer #1. I was unable to get it to work for me, but also realized it would resulted in loss of data, as the code only called for certian lines in the original image, and other lines would have been ignored.
After experimenting further, I developed the code below. I used a checkerboard as an example. While combersome, it does get the job done. However, upon trying the script with an actual high-resolution image, it was extremely slow and ended up failing due to running out of memory. I believe this is because of the excessive number of "imresize" commands that are used in loop.
I = checkerboard(10,50);
I = imrotate(I,90);
[X Y] = size(I);
k = 4; % Number of "cycles"
k = k*2;
x = 1;
y = 2;
z = 2;
F = [];
i = 1;
t = 0;
s = 0;
for j = 1:k/2
t = t + 1;
for inc = round(s+1):round(Y/k*t)
Yi = i + 1;
F(:,(x:y)) = imresize(I(:,(inc:inc)),[X Yi]);
x = y + 1;
y = x + z;
z = z + 1;
i = i + 1;
end
y = y - 2;
z = z - 4;
for inc = round(Y/k*t+1):round(Y/k*(t+1))
Yi = i - 1;
F(:,(x:y)) = imresize(I(:,(inc:inc)),[X Yi]);
x = y + 1;
y = x + z;
z = z - 1;
i = i - 1;
end
y = y + 2;
z = z + 4;
s = Y/k*(t+1);
t = t + 1;
end
Fn = imresize(F, [X Y]);
imshow(Fn);
Does anyone know of a simpler way to achieve this? If you run the code above, you can see the effect I am trying to achieve. Unfortunately, my method above does not allow me to adjust the amplitude of the "stretch" either, only the number of "cycles," or frequency. Help on this would also be appreciated. Much thanks!
Here is how I would approach it:
Determine how the coordinate of each point in your Final image F maps into your Initial image I of size (M,N)
Since you want to stretch horizontally only, given a point (xF,yF) in your final image, that point would be (xI,yI) in your initial image where xI and yI can be obtained as follows:
yI = yF;
xI = xF + Lsin(xFK);
Notes:
these equations do not guarantee that xI remains within the range [1:N] so cropping needs to be added
K controls the how many wrinkles you want to have in your accordion effect. For example, if you only want one wrinkle, K would be 2*pi/N
L controls how much stretching you want to apply
Then simply express your image F from image I with the transforms you have in 1.
Putting it all together, the code below creates a sample image I and generates the image F as follows:
% Generate a sample input image
N=500;
xF=1:N;
I=(1:4)'*xF/N*50;
% Set the parameters for your accordion transform
K=2*pi/N;
L=100;
% Apply the transform
F=I(:, round(min(N*ones(1,N), max(ones(1,N), (xF + L*sin(xF*K))))) );
% Display the input and output images side by side
image(I);
figure;
image(F);
If you run this exact code you get:
As you can see, the final image on the right stretches the center part of the image on the left, giving you an accordion effect with one wrinkle.
You can fiddle with K and L and adjust the formula to get the exact effect you want, but note how by expressing the transform in a matrix form MATLAB executes the code in a fraction of second. If there is one take away for you is that you should stay away from for loops and complex processing whenever you can.
Have fun!

Resources