I'd like to take in an RGB image, find the points in the image that are white, and get the cartesian coordinates of those points in the image. I've gotten most of the way there, but when I try to plot the cartesian coordinates, I get a vertically tiled image (i.e. 5 overlapped copies of what I should see). Anyone know what could be causing this?
,
Code: (JPG comes in as 2448 x x3264 x 3 uint8)
I = imread('IMG_0245.JPG');
imshow(I); % display unaltered image
% Convert image to grayscale
I = rgb2gray(I);
% Convert image to binary (black/white)
I = im2bw(I, 0.9);
% Generate cartesian coordinates of image
imageSize = size(I);
[x, y] = meshgrid( 1:imageSize(1), 1:imageSize(2) );
PerspectiveImage = [x(:), y(:), I(:)];
% Get indices of white points only
whiteIndices = find(PerspectiveImage(:,3));
figure; plot( PerspectiveImage(whiteIndices, 1), PerspectiveImage(whiteIndices, 2),'.');
% Flip vertically to correct indexing vs. plotting issue
axis ij
Very simple. You're declaring your meshgrid wrong. It should be:
[x, y] = meshgrid( 1:imageSize(2), 1:imageSize(1) );
The first parameter denotes the horizontal extents of the 2D grid, and so you want to make this vary for as many columns as you have. Similarly, the second parameter denotes the vertical extents of the 2D grid, and so you want to make this for as many rows as you have.
I had to pre-process some of your image to get some good results because your original image had a large white border surrounding the image. I had to remove this border by removing all pure white pixels. I also read in the image directly from StackOverflow:
I = imread('http://s7.postimg.org/ovb53w4ff/Track_example.jpg');
mask = all(I == 255, 3);
I = bsxfun(#times, I, uint8(~mask));
This was the image I get after doing my pre-processing:
Once I do this and change your meshgrid call, I get this:
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 m trying to compute an efficient way to transform an image in cartesian coordinates into a polar representation. I know some functions such as ImToPolar are doing it and it works perfectly but takes a considerable much time for big images, especially when they require to be processed back and forth.
Here´s my input image:
and then I generate a polar mesh using a cartesian mesh centered at 0 and the function cart2pol(). Finally, I plot my image using mesh(theta, r, Input).
And here´s what I obtain:
Its exactly the image I need and it´s the same as ImToPolar or maybe better.
Since MATLAB knows how to compute it, does anybody know how to extract a matrix in polar representation from this output? Or maybe a fast (like in fast fourier transform) way to compute a Polar transform (and inverse) on MATLAB?
pol2cart and meshgrid and interp2 are sufficient to create the result:
I=imread('http://i.stack.imgur.com/HYSyb.png');
[r, c,~] = size(I);
%rgb image can be converted to indexed image to prevent excessive copmutation for each color
[idx, mp] = rgb2ind(I,32);
% add offset to image coordinates
x = (1:c)-(c/2);
y = (1:r)-(r/2);
% create distination coordinates in polar form so value of image can be interpolated in those coordinates
% angle ranges from 0 to 2 * pi and radius assumed that ranges from 0 to 400
% linspace(0,2*pi, 200) leads to a stretched image try it!
[xp yp] = meshgrid(linspace(0,2*pi), linspace(0,400));
%translate coordinate from polar to image coordinates
[xx , yy] = pol2cart(xp,yp);
% interpolate pixel values for unknwon coordinates
out = interp2(x, y, idx, xx, yy);
% save the result to a file
imwrite(out, mp, 'result.png')
I am trying to find a way to crop from a circle object (Image A) the largest square that can fit inside it.
Can someone please explain/show me how to find the biggest square fit parameters of the white space inside the circle (Image I) and based on them crop the square in the original image (Image A).
Script:
A = imread('E:/CirTest/Test.jpg');
%imshow(A)
level = graythresh(A);
BW = im2bw(A,level);
%imshow(BW)
I = imfill(BW, 'holes');
imshow(I)
d = imdistline;
[centers, radii, metric] = imfindcircles(A,[1 500]);
imageCrop=imcrop(A, [BoxBottomX BoxBottomY NewX NewY]);
I have a solution for you but it requires a bit of extra work. What I would do first is use imfill but directly on the grayscale image. This way, noisy pixels in uniform areas get inpainted with the same intensities so that thresholding is easier. You can still use graythresh or Otsu's thresholding and do this on the inpainted image.
Here's some code to get you started:
figure; % Open up a new figure
% Read in image and convert to grayscale
A = rgb2gray(imread('http://i.stack.imgur.com/vNECg.jpg'));
subplot(1,3,1); imshow(A);
title('Original Image');
% Find the optimum threshold via Otsu
level = graythresh(A);
% Inpaint noisy areas
I = imfill(A, 'holes');
subplot(1,3,2); imshow(I);
title('Inpainted image');
% Threshold the image
BW = im2bw(I, level);
subplot(1,3,3); imshow(BW);
title('Thresholded Image');
The above code does the three operations that I mentioned, and we see this figure:
Notice that the thresholded image has border pixels that need to be removed so we can concentrate on the circular object. You can use the imclearborder function to remove the border pixels. When we do that:
% Clear off the border pixels and leave only the circular object
BW2 = imclearborder(BW);
figure; imshow(BW2);
... we now get this image:
Unfortunately, there are some noisy pixels, but we can very easily use morphology, specifically the opening operation with a small circular disk structuring element to remove these noisy pixels. Using strel with the appropriate structuring element in addition to imopen should help do the trick:
% Clear out noisy pixels
SE = strel('disk', 3, 0);
out = imopen(BW2, SE);
figure; imshow(out);
We now get:
This mask contains the locations of the circular object we now need to use to crop our original image. The last part is to determine the row and column locations using this mask to locate the top left and bottom right corner of the original image and we thus crop it:
% Find row and column locations of circular object
[row,col] = find(out);
% Find top left and bottom right corners
top_row = min(row);
top_col = min(col);
bottom_row = max(row);
bottom_col = max(col);
% Crop the image
crop = A(top_row:bottom_row, top_col:bottom_col);
% Show the cropped image
figure; imshow(crop);
We now get:
It's not perfect, but it will of course get you started. If you want to copy and paste this in its entirety and run this on your computer, here we are:
figure; % Open up a new figure
% Read in image and convert to grayscale
A = rgb2gray(imread('http://i.stack.imgur.com/vNECg.jpg'));
subplot(2,3,1); imshow(A);
title('Original Image');
% Find the optimum threshold via Otsu
level = graythresh(A);
% Inpaint noisy areas
I = imfill(A, 'holes');
subplot(2,3,2); imshow(I);
title('Inpainted image');
% Threshold the image
BW = im2bw(I, level);
subplot(2,3,3); imshow(BW);
title('Thresholded Image');
% Clear off the border pixels and leave only the circular object
BW2 = imclearborder(BW);
subplot(2,3,4); imshow(BW2);
title('Cleared Border Pixels');
% Clear out noisy pixels
SE = strel('disk', 3, 0);
out = imopen(BW2, SE);
% Show the final mask
subplot(2,3,5); imshow(out);
title('Final Mask');
% Find row and column locations of circular object
[row,col] = find(out);
% Find top left and bottom right corners
top_row = min(row);
top_col = min(col);
bottom_row = max(row);
bottom_col = max(col);
% Crop the image
crop = A(top_row:bottom_row, top_col:bottom_col);
% Show the cropped image
subplot(2,3,6);
imshow(crop);
title('Cropped Image');
... and our final figure is:
You can use bwdist with L_inf distance (aka 'chessboard') to get the axis-aligned distance to the edges of the region, thus concluding the dimensions of the largest bounded box:
bw = imread('http://i.stack.imgur.com/7yCaD.png');
lb = bwlabel(bw);
reg = lb==2; %// pick largest area
d = bwdist(~reg,'chessboard'); %// compute the axis aligned distance from boundary inward
r = max(d(:)); %// find the largest distance to boundary
[cy cx] = find(d==r,1); %// find the location most distant
boundedBox = [cx-r, cy-r, 2*r, 2*r];
And the result is
figure;
imshow(bw,'border','tight');
hold on;
rectangle('Position', boundedBox, 'EdgeColor','r');
Once you have the bounding box, you can use imcrop to crop the original image
imageCrop = imcrop(A, boundedBox);
Alternatively, you can
imageCrop = A(cy + (-r:r-1), cx + (-r:r-1) );
What is the preferred way of converting from axis coordinates (e.g. those taken in by plot or those output in point1 and point2 of houghlines) to pixel coordinates in an image?
I see the function axes2pix in the Mathworks documentation, but it is unclear how it works. Specifically, what is the third argument? The examples just pass in 30, but it is unclear where this value comes from. The explanations depend on a knowledge of several other functions, which I don't know.
The related question: Axis coordinates to pixel coordinates? suggests using poly2mask, which would work for a polygon, but how do I do the same thing for a single point, or a list of points?
That question also links to Scripts to Convert Image to and from Graph Coordinates, but that code threw an exception:
Error using /
Matrix dimensions must agree.
Consider the following code. It shows how to convert from axes coordinates to image pixel coordinates.
This is especially useful if you plot the image using custom XData/YData locations other than the default 1:width and 1:height. I am shifting by 100 and 200 pixels in the x/y directions in the example below.
function imageExample()
%# RGB image
img = imread('peppers.png');
sz = size(img);
%# show image
hFig = figure();
hAx = axes();
image([1 sz(2)]+100, [1 sz(1)]+200, img) %# shifted XData/YData
%# hook-up mouse button-down event
set(hFig, 'WindowButtonDownFcn',#mouseDown)
function mouseDown(o,e)
%# get current point
p = get(hAx,'CurrentPoint');
p = p(1,1:2);
%# convert axes coordinates to image pixel coordinates
%# I am also rounding to integers
x = round( axes2pix(sz(2), [1 sz(2)], p(1)) );
y = round( axes2pix(sz(1), [1 sz(1)], p(2)) );
%# show (x,y) pixel in title
title( sprintf('image pixel = (%d,%d)',x,y) )
end
end
(note how the axis limits do not start at (1,1), thus the need for axes2pix)
There may be a built-in way that I haven't heard of, but this shouldn't be hard to do from scratch...
set(axes_handle,'units','pixels');
pos = get(axes_handle,'position');
xlim = get(axes_handle,'xlim');
ylim = get(axes_handle,'ylim');
Using these values, you can convert from axes coordinates to pixels easily.
x_in_pixels = pos(1) + pos(3) * (x_in_axes-xlim(1))/(xlim(2)-xlim(1));
%# etc...
The above uses pos(1) as the x-offset of the axes within the figure. If you don't care about this, don't use it. Likewise, if you want it in screen coordinates, add the x-offset of the position obtained by get(figure_handle,'position')
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)