I have two images (I1 and I2) that I want to plot through subplot as follows. For sake of simplicity I created two fake images with size 512x512 pixels.
I1 = randn(512);
I2 = randn(512);
% display
f1 = figure();
axis on;
subplot(1,2,1), imshow(uint8(I1));
subplot(1,2,2), imshow(uint8(I2));
I want the Y axis to show just the following ticks: 0 100 200 300 400 500. Therefore exactly as the X axis, so that it is clear that the image size is also bigger than 500 pixels. How can I do it? Thanks a lot!
You should move the axis on to the end of the script and specify the XTick and XTickLabel properties.
I1 = randn(512);
I2 = randn(512);
% display
f1 = figure();
s1=subplot(1,2,1);
imshow(uint8(I1));
set(s1,'XTick',0:100:500);
set(s1,'XTickLabel',0:100:500);
axis on;
s2=subplot(1,2,2);
imshow(uint8(I2));
set(s2,'XTick',0:100:500);
set(s2,'XTickLabel',0:100:500);
axis on;
Related
I am using the MATLAB function ginput to label my image data for further process. Here is my code:
file_name = "test.jpg";
% Read the image
img = imread(file_name);
% Get the image dimension
imgInfo = imfinfo(file_name);
width = imgInfo.Width;
height = imgInfo.Height;
% Using ginput function to label the image
figure(1);
imshow(img);
hold on;
[x, y] = ginput(4); % Manually label 4 points
scatter(x, y, 100, 'ro', 'filled'); % Plot the marked points on img
hold off;
My Problem:
I found that the output x and yare not integers, so they are not representing the pixel indices.
Sometimes, these two conditions max(x) > width and max(y) > height are satisfied. It seems to suggest that the 4 points I marked using ginput are outside the image (but actually it is not).
I am aware of this issue is related to Image Coordinate System setting, but I am still not sure how to convert x and y obtained from ginput function to the actual pixel indices?
Thanks.
The code below shows a 2x2 image, enlarges the axes so we can see it, then turns on the axes ticks and labels. What this does is allow you to see the coordinate system used to render images in an axes object.
imshow([255,0;0,255])
set(gca,'position',[0.2,0.2,0.6,0.6])
axis on
The coordinates returned by ginput match these coordinates.
In short, what you need to do is simply round the coordinates returned by ginput to get indices into the image:
[x, y] = ginput(4); % Manually label 4 points
x = round(x);
y = round(y);
I can get an image plot on the X-Y plane using imagesc, but now I would like to have it on the X-Z plane for further usage. Is there any way to do so? Thanks!
I'd use surface instead of imagesc:
INPUT = [3,4,5
4,5,6];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
figure();
ZZ = padarray(INPUT,[1 1],0,'post'); % See note #2
[XX,YY] = meshgrid((1:size(INPUT,2)+1)-0.5,(1:size(INPUT,1)+1)-0.5);
% imagesc
subplot(3,1,1); imagesc(INPUT); xlim([0 4]); ylim([0.5 2.5]);
view([-50 50]); xlabel('x'); ylabel('y'); zlabel('z'); grid on;
title('imagesc');
% Normal (X-Y):
subplot(3,1,2); surface(XX,YY,0*XX,ZZ,'EdgeColor','none','FaceColor','flat');
view([-50 50]); xlabel('x'); ylabel('y'); zlabel('z'); axis ij; box on; grid on;
title('X-Y surface'); caxis([min(INPUT(:)),max(INPUT(:))]);
% Rotated (X-Z):
subplot(3,1,3); surface(XX,0*ZZ,YY,ZZ,'EdgeColor','none','FaceColor','flat');
view([-50 50]); xlabel('x'); ylabel('y'); zlabel('z'); axis ij; box on; grid on;
title('X-Z surface'); caxis([min(INPUT(:)),max(INPUT(:))]);
Several notes:
You might need to flipud or fliplr some of the inputs in the 2nd surface plot (depending on how you define the Y -> Z transition).
Presentation-wise the output is the same, but, if you try to compare the values of the nodes you will not get the same result between the X-Y and the imagesc outputs. The reason for this is that the surface is defined using the vertices, and an Image object is defined using the value in the center of each square.
Output:
I am a crystallographer trying to analyse crystals orientations from up to 5000 files. Can Matlab convert angle values in a table that look like this:
Into a table that looks like this?:
Here's a more concrete example based on Lakesh's idea. However, this will handle any amount of rotation. First start off with a base circular image with a strip in the middle. Once you do this, simply run a for loop that stacks all of these rotated images in a grid that resembles the angles seen in your rotation values matrix for every rotation angle that we see in this matrix.
The trick is to figure out how to define the base orientation image. As such, let's define a white square, with a black circle in the middle. We will also define a red strip in the middle. For now, let's assume that the base orientation image is 51 x 51. Therefore, we can do this:
%// Define a grid of points between -25 to 25 for both X and Y
[X,Y] = meshgrid(-25:25,-25:25);
%// Define radius
radius = 22;
%// Generate a black circle that has the above radius
base_image = (X.^2 + Y.^2) <= radius^2;
%// Make into a 3 channel colour image
base_image = ~base_image;
base_image = 255*cast(repmat(base_image, [1 1 3]), 'uint8');
%// Place a strip in the middle of the circle that's red
width_strip = 44;
height_strip = 10;
strip_locs = (X >= -width_strip/2 & X <= width_strip/2 & Y >= -height_strip/2 & Y <= height_strip/2);
base_image(strip_locs) = 255;
With the above, this is what I get:
Now, all you need to do is create a final output image which has as many images as we have rows and columns in your matrix. Given that your rotation matrix values are stored in M, we can use imrotate from the image processing toolbox and specify the 'crop' flag to ensure that the output image is the same size as the original. However, with imrotate, whatever values don't appear in the image after you rotate it, it defaults to 0. You want this to appear white in your example, so we're going to have to do a bit of work. What you'll need to do is create a logical matrix that is the same size as the input image, then rotate it in the same way like you did with the base image. Whatever pixels appear black (which are also false) in this rotated white image, these are the values we need to set to white. As such:
%// Get size of rotation value matrix
[rows,cols] = size(M);
%// For storing the output image
output_image = zeros(rows*51, cols*51, 3);
%// For each value in our rotation value matrix...
for row = 1 : rows
for col = 1 : cols
%// Rotate the image
rotated_image = imrotate(base_image, M(row,col), 'crop');
%// Take a completely white image and rotate this as well.
%// Invert so we know which values were outside of the image
Mrot = ~imrotate(true(size(base_image)), M(row,col), 'crop');
%// Set these values outside of each rotated image to white
rotated_image(Mrot) = 255;
%// Store in the right slot.
output_image((row-1)*51 + 1 : row*51, (col-1)*51 + 1 : col*51, :) = rotated_image;
end
end
Let's try a few angles to be sure this is right:
M = [0 90 180; 35 45 60; 190 270 55];
With the above matrix, this is what I get for my image. This is stored in output_image:
If you want to save this image to file, simply do imwrite(output_image, 'output.png');, where output.png is the name of the file you want to save to your disk. I chose PNG because it's lossless and has a relatively low file size compared to other lossless standards (save JPEG 2000).
Edit to show no line when the angle is 0
If you wish to use the above code where you want to only display a black circle if the angle is around 0, it's just a matter of inserting an if statement inside the for loop as well creating another image that contains a black circle with no strip through it. When the if condition is satisfied, you'd place this new image in the right grid location instead of the black circle with the red strip.
Therefore, using the above code as a baseline do something like this:
%// Define matrix of sample angles
M = [0 90 180; 35 45 60; 190 270 55];
%// Define a grid of points between -25 to 25 for both X and Y
[X,Y] = meshgrid(-25:25,-25:25);
%// Define radius
radius = 22;
%// Generate a black circle that has the above radius
base_image = (X.^2 + Y.^2) <= radius^2;
%// Make into a 3 channel colour image
base_image = ~base_image;
base_image = 255*cast(repmat(base_image, [1 1 3]), 'uint8');
%// NEW - Create a black circle image without the red strip
black_circle = base_image;
%// Place a strip in the middle of the circle that's red
width_strip = 44;
height_strip = 10;
strip_locs = (X >= -width_strip/2 & X <= width_strip/2 & Y >= -height_strip/2 & Y <= height_strip/2);
base_image(strip_locs) = 255;
%// Get size of rotation value matrix
[rows,cols] = size(M);
%// For storing the output image
output_image = zeros(rows*51, cols*51, 3);
%// NEW - define tolerance
tol = 5;
%// For each value in our rotation value matrix...
for row = 1 : rows
for col = 1 : cols
%// NEW - If the angle is around 0, then draw a black circle only
if M(row,col) >= -tol && M(row,col) <= tol
rotated_image = black_circle;
else %// This is the logic if the angle is not around 0
%// Rotate the image
rotated_image = imrotate(base_image, M(row,col), 'crop');
%// Take a completely white image and rotate this as well.
%// Invert so we know which values were outside of the image
Mrot = ~imrotate(true(size(base_image)), M(row,col), 'crop');
%// Set these values outside of each rotated image to white
rotated_image(Mrot) = 255;
end
%// Store in the right slot.
output_image((row-1)*51 + 1 : row*51, (col-1)*51 + 1 : col*51, :) = rotated_image;
end
end
The variable tol in the above code defines a tolerance where anything within -tol <= angle <= tol has the black circle drawn. This is to allow for floating point tolerances when comparing because it's never a good idea to perform equality operations with floating point values directly. Usually it is accepted practice to compare within some tolerance of where you would like to test for equality.
Using the above modified code with the matrix of angles M as seen in the previous example, I get this image now:
Notice that the top left entry of the matrix has an angle of 0, which is thus visualized as a black circle with no strip through it as we expect.
General idea to solve your problem:
1. Store two images, 1 for 0 degrees and 180 degrees and another for 90 and 270 degrees.
2. Read the data from the file
3. if angle = 0 || angle == 180
image = image1
else
image = image2
end
To handle any angle:
1. Store one image. E.g image = imread('yourfile.png')
2. angle = Read the data from the file
3. B = imrotate(image,angle)
I have two images: im2 needs to be overlayed over im1 with a constant alpha map of 0.5. Whenever I set the 'AlphaData' for im2 (to reveal im1 below), the size of the figure/axes changes slightly. If my axes occupies the whole figure, some border pixels go missing. The following example demonstrates this problem by two example images, where im2 has a yellow border so you can clearly notice this problem:
close all;
frame_sz = [106 777];
% create a white im1
im1 = ones([frame_sz 3]);
% create im2 with a yellow border
im2 = zeros([frame_sz 3]);
im2(:,1,[1 2]) = 1;
im2(:,end,[1 2]) = 1;
im2(1,:,[1 2]) = 1;
im2(end,:,[1 2]) = 1;
% create the figure at a specific location with size equal to image
screen_sz = get(0,'ScreenSize');
fg_h = figure('units', 'pixels', 'position', ...
[screen_sz([3 4])-frame_sz([2 1])-40 frame_sz([2 1])], ...
'paperpositionmode', 'auto');
ax_h = axes('Parent',fg_h);
% show first image
imshow(im1, 'Parent',ax_h, 'InitialMagnification','fit');
hold on;
% display im2 ontop of im1
h = image(im2, 'Parent',ax_h);
% set the axis such that image occupies the whole figure
set(ax_h, 'Units','normalized', ...
'position', [0 0 1 1], 'visible', 'off');
axis off;
%%%%%%%%%%%% PROBLEM HAPPENS HERE %%%%%%%%%%%%%
% as soon as I set the AlphaData couple of pixels
% go missing from the right and bottom side
set(h, 'AlphaData', ones(frame_sz([1 2]))*0.5);
The problem occurs regardless of if I am overlaying using image() or just simply using image() to display an image. As soon as I set the AlphaData, the sizing of the axes slightly changes and chops off some borders.
How do I fix this?
I have an image in MATLAB:
im = rgb2gray(imread('some_image.jpg');
% normalize the image to be between 0 and 1
im = im/max(max(im));
And I've done some processing that resulted in a number of points that I want to highlight:
points = some_processing(im);
Where points is a matrix the same size as im with ones in the interesting points.
Now I want to draw a circle on the image in all the places where points is 1.
Is there any function in MATLAB that does this? The best I can come up with is:
[x_p, y_p] = find (points);
[x, y] = meshgrid(1:size(im,1), 1:size(im,2))
r = 5;
circles = zeros(size(im));
for k = 1:length(x_p)
circles = circles + (floor((x - x_p(k)).^2 + (y - y_p(k)).^2) == r);
end
% normalize circles
circles = circles/max(max(circles));
output = im + circles;
imshow(output)
This seems more than somewhat inelegant. Is there a way to draw circles similar to the line function?
You could use the normal PLOT command with a circular marker point:
[x_p,y_p] = find(points);
imshow(im); %# Display your image
hold on; %# Add subsequent plots to the image
plot(y_p,x_p,'o'); %# NOTE: x_p and y_p are switched (see note below)!
hold off; %# Any subsequent plotting will overwrite the image!
You can also adjust these other properties of the plot marker: MarkerEdgeColor, MarkerFaceColor, MarkerSize.
If you then want to save the new image with the markers plotted on it, you can look at this answer I gave to a question about maintaining image dimensions when saving images from figures.
NOTE: When plotting image data with IMSHOW (or IMAGE, etc.), the normal interpretation of rows and columns essentially becomes flipped. Normally the first dimension of data (i.e. rows) is thought of as the data that would lie on the x-axis, and is probably why you use x_p as the first set of values returned by the FIND function. However, IMSHOW displays the first dimension of the image data along the y-axis, so the first value returned by FIND ends up being the y-coordinate value in this case.
This file by Zhenhai Wang from Matlab Central's File Exchange does the trick.
%----------------------------------------------------------------
% H=CIRCLE(CENTER,RADIUS,NOP,STYLE)
% This routine draws a circle with center defined as
% a vector CENTER, radius as a scaler RADIS. NOP is
% the number of points on the circle. As to STYLE,
% use it the same way as you use the rountine PLOT.
% Since the handle of the object is returned, you
% use routine SET to get the best result.
%
% Usage Examples,
%
% circle([1,3],3,1000,':');
% circle([2,4],2,1000,'--');
%
% Zhenhai Wang <zhenhai#ieee.org>
% Version 1.00
% December, 2002
%----------------------------------------------------------------
Funny! There are 6 answers here, none give the obvious solution: the rectangle function.
From the documentation:
Draw a circle by setting the Curvature property to [1 1]. Draw the circle so that it fills the rectangular area between the points (2,4) and (4,6). The Position property defines the smallest rectangle that contains the circle.
pos = [2 4 2 2];
rectangle('Position',pos,'Curvature',[1 1])
axis equal
So in your case:
imshow(im)
hold on
[y, x] = find(points);
for ii=1:length(x)
pos = [x(ii),y(ii)];
pos = [pos-0.5,1,1];
rectangle('position',pos,'curvature',[1 1])
end
As opposed to the accepted answer, these circles will scale with the image, you can zoom in an they will always mark the whole pixel.
Hmm I had to re-switch them in this call:
k = convhull(x,y);
figure;
imshow(image); %# Display your image
hold on; %# Add subsequent plots to the image
plot(x,y,'o'); %# NOTE: x_p and y_p are switched (see note below)!
hold off; %# Any subsequent plotting will overwrite the image!
In reply to the comments:
x and y are created using the following code:
temp_hull = stats_single_object(k).ConvexHull;
for k2 = 1:length(temp_hull)
i = i+1;
[x(i,1)] = temp_hull(k2,1);
[y(i,1)] = temp_hull(k2,2);
end;
it might be that the ConvexHull is the other way around and therefore the plot is different. Or that I made a mistake and it should be
[x(i,1)] = temp_hull(k2,2);
[y(i,1)] = temp_hull(k2,1);
However the documentation is not clear about which colum = x OR y:
Quote: "Each row of the matrix contains the x- and y-coordinates of one vertex of the polygon. "
I read this as x is the first column and y is the second colum.
In newer versions of MATLAB (I have 2013b) the Computer Vision System Toolbox contains the vision.ShapeInserter System object which can be used to draw shapes on images. Here is an example of drawing yellow circles from the documentation:
yellow = uint8([255 255 0]); %// [R G B]; class of yellow must match class of I
shapeInserter = vision.ShapeInserter('Shape','Circles','BorderColor','Custom','CustomBorderColor',yellow);
I = imread('cameraman.tif');
circles = int32([30 30 20; 80 80 25]); %// [x1 y1 radius1;x2 y2 radius2]
RGB = repmat(I,[1,1,3]); %// convert I to an RGB image
J = step(shapeInserter, RGB, circles);
imshow(J);
With MATLAB and Image Processing Toolbox R2012a or newer, you can use the viscircles function to easily overlay circles over an image. Here is an example:
% Plot 5 circles at random locations
X = rand(5,1);
Y = rand(5,1);
% Keep the radius 0.1 for all of them
R = 0.1*ones(5,1);
% Make them blue
viscircles([X,Y],R,'EdgeColor','b');
Also, check out the imfindcircles function which implements the Hough circular transform. The online documentation for both functions (links above) have examples that show how to find circles in an image and how to display the detected circles over the image.
For example:
% Read the image into the workspace and display it.
A = imread('coins.png');
imshow(A)
% Find all the circles with radius r such that 15 ≤ r ≤ 30.
[centers, radii, metric] = imfindcircles(A,[15 30]);
% Retain the five strongest circles according to the metric values.
centersStrong5 = centers(1:5,:);
radiiStrong5 = radii(1:5);
metricStrong5 = metric(1:5);
% Draw the five strongest circle perimeters.
viscircles(centersStrong5, radiiStrong5,'EdgeColor','b');
Here's the method I think you need:
[x_p, y_p] = find (points);
% convert the subscripts to indicies, but transposed into a row vector
a = sub2ind(size(im), x_p, y_p)';
% assign all the values in the image that correspond to the points to a value of zero
im([a]) = 0;
% show the new image
imshow(im)