Detect user mouse click in matlab - matlab

I am trying to make a game in matlab where the user selects a shape and that shape translates and scales down a screen. The user then has to click on the shape and a point is added to their score. I was wondering how to make the program detect the users mouse click on the shape but end the program if they click on white space.

You can go along these lines. The following code basically uses:
fill to draw a polygonal shape;
ginput to get cursor position;
inpolygon to check if that position is inside the polygon.
Code:
xv = [ -3 3 3 -3]; %// x coords of polygon vertices. Arbitrary number
yv = [-5 -5 7 7]; %// y coords of polygon vertices. Same number as for x
fill(xv,yv,'b') %// draw polygon
axis([-10 10 -10 10])
[xp, yp] = ginput(1); %// get point coordinates
inside = inpolygon(xp,yp,xv,yv); %// is it inside?
if inside
%// it's inside. Do something accordingly
else
%// it's outside. Do something else
end

Related

Matlab - rotate a card [duplicate]

This question already has answers here:
How to straighten a tilted square shape in an image?
(2 answers)
Closed 5 years ago.
I have a cropped image of a card:
The card is a rectangle with rounded corners, is brightly colored, and sits on a relatively dark background.
It is, therefore, easy to differentiate between pixels belonging to the card and pixels belonging to the background.
I want to use MATLAB to rotate the card so its sides are vertical and horizontal (and not diagonal) and create an image of nothing but the straightened card.
I need this to work for any reasonable card angle (say +45 to -45 degrees of initial card rotation).
What would be the best way of doing this?
Thanks!
You can do this by finding the lines made by the edges of the card. The angle of rotation is then the angle between one of the lines and the horizontal (or vertical).
In MATLAB, you can use the Hough line detector to find lines in a binary image.
0. Read the input image
I downloaded your image and renamed it card.png.
A = imread('card.png');
We don't need color information, so convert to grayscale.
I = rgb2gray(A);
1. Detect edges in the image
A simple way is to use the Canny edge detector. Adjust the threshold to reject noise and weak edges.
BW = edge(I, 'canny', 0.5);
Display the detected edges.
figure
imshow(BW)
title('Canny edges')
2. Use the Hough line detector
First, you need to use the Hough transform on the black and white image, with the hough function. Adjust the resolution so that you detect all lines you need later.
[H,T,R] = hough(BW, 'RhoResolution', 2);
Second, find the strongest lines in the image by finding peaks in the Hough transform with houghpeaks.
P = houghpeaks(H, 100); % detect a maximum of 100 lines
Third, detect lines with houghlines.
lines = houghlines(BW, T, R, P);
Display the detected lines to make sure you find at least one along the edge of the card. The white border around the black background in your image makes detecting the right edges a bit more difficult.
figure
imshow(A)
hold on
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
plot(xy(:,1), xy(:,2), 'LineWidth', 2, 'Color', 'red');
end
title('Detected lines')
3. Calculate the angle of rotation
lines(3) is the left vertical edge of the card. lines(3).point2 is the end of the line that is at the bottom. We want this point to stay where it is, but we want to vector along the line to be aligned with the vector v = [0 -1]'. (The origin is the top-left corner of the image, x is horizontal to the right and y is vertical down.)
lines(3)
ans =
struct with fields:
point1: [179 50]
point2: [86 455]
theta: 13
rho: 184
Simply calculate the angle between the vector u = lines(3).point1 - lines(3).point2 and the vertical vector v.
u = lines(3).point1 - lines(3).point2; % vector along the vertical left edge.
v = [0 -1]; % vector along the vertical, oriented up.
theta = acos( u*v' / (norm(u) * norm(v)) );
The angle is in radians.
4. Rotate
The imrotate function lets you rotate an image by specifying an angle in degrees. You could also use imwarp with a rotation transform.
B = imrotate(A, theta * 180 / pi);
Display the rotated image.
figure
imshow(B)
title('Rotated image')
Then you would have to crop it.

Matlab - isolating x/y values of a circle within a circle

I am looking for a way to isolate the x and/or y coord of a circle within a circle, as shown in the image.
I need to isolate this so i can set a condition that when a ball enters a circle, i can change some qualities of the ball, i have been able to do this for the outer circle, which is centred at [0 0] using the code below,
while sqrt(XY(1)^2 + XY(2)^2) < 5
but cannot figure out how to do it for the interior circles.
Thanks
If you know the center and the radius of the inner circles you are able to calculate the X and Y coordinates of the circles then, you can use the inpolygon function to thest if a point is inside a circle (inpolygon returns 1 if a point is inside the polygon, 0 otherwise). In this case the polygon is constitued by the points of the circles.
In the following code a point moves across three circles (two of them placed inside the bigger one).
The inpolygon function is used to test if the point (the ball) is inside a circle and in change its colour according to the circle it is inside to.
% Define the radius and centre of three circles
r1=10;
r2=3
r3=4
c1=[0 0];
c2=[3 3];
c3=[-4 -4]
% Calculate the X and Y coord of the three circles
t=0:.01:2*pi;
x=cos(t)*r1
y=sin(t)*r1
x1=cos(t)*r2+c2(1)
y1=sin(t)*r2+c2(2)
x2=cos(t)*r3+c3(1)
y2=sin(t)*r3+c3(2)
% Plot the circles
plot(x,y,'r')
hold on
plot(x1,y1,'g')
plot(x2,y2,'b')
daspect([1 1 1])
% Define the ball trajectory
mx=-10:1:10;
my=-10:1:10;
for i=1:length(mx)
% Plot the ball: black if outside of all the circle
mh=plot(mx(i),my(i),'o','markerfacecolor','k','markeredgecolor','k')
% If the ballk is inside the first circle, make it red
if(inpolygon(mx(i),my(i),x,y))
mh.MarkerFaceColor='r';
mh.MarkerEdgeColor='r';
end
if(inpolygon(mx(i),my(i),x1,y1))
% If the ballk is inside the second circle, make it green
mh.MarkerFaceColor='g';
mh.MarkerEdgeColor='g';
end
if(inpolygon(mx(i),my(i),x2,y2))
% If the ballk is inside the third circle, make it blue
mh.MarkerFaceColor='b';
mh.MarkerEdgeColor='b';
end
pause(1)
end
Hope this helps.
Qapla'

MATLAB how to Draw a circle around a chosen node in a graph?

l have generated a topology of a network with 200 nodes.than l want to draw a circle with black color around a choosen node(satisfying a certain condition IF (condition) ).
to simplify let the user introduce the the index of the node to circle with the black color.
here is my code of the generated topology.l need to add wich instructions to draw the circle around the choosen node ?
X=100;
Y=100;
N=200; %number of nodes
nodesX(1)=rand*X;
nodesY(1)=rand*Y;
for i=2:N
nodesX(i)=rand*X;
nodesY(i)=rand*Y;
d(i-1) =((nodesX(i)-nodesX(i-1)).^2+(nodesY(i)-nodesY(i-1)).^2).^0.5;
while (d(i-1)>200)
nodesX(i)=rand*X;
nodesY(i)=rand*Y;
d(i-1) =((nodesX(i)-nodesX(i-1)).^2+(nodesY(i)-nodesY(i-1)).^2).^0.5;
end
end
h_old=plot(nodesX,nodesY,'m*');
labels=[1:N]';
labels=num2str(labels);
text(nodesX,nodesY,labels);
xlabel('X (Meters)');
ylabel('Y (Meters)');
title(['Network Topology with',num2str(N),'nodes']);
hold on
for k=1:N;
for j=1:N;
if (k~=j)
d=((nodesX(k)-nodesX(j))^2+(nodesY(k)-nodesY(j))^2)^0.5;
end
if (k~=j);
if(d < 50);
line([nodesX(k),nodesX(j)],[nodesY(k),nodesY(j)]);
end
end
end;
end;
Split it into two tasks:
Task 1:
Define a simple function to draw a circle. A cheap and dirty way is to use polar expressions.
function [] = circle(center_x,center_y,r)
theta = 0:0.01:2*pi;
x = center_x + r*cos(theta);
y = center_y + r*sin(theta);
plot(x,y,'k','LineWidth',2)
Task 2:
Pass this function the NodeX and NodeY values of the indexed node as the point at which the circle is centered. You can set the radius of the circle as per your choice. Using r=1 and picking an arbitrary index, I got:
Just one caveat: Make sure your axis are square. Otherwise, a circle might look like an ellipse. If you want to draw a circle around non-square axis, then you can modify the code to generate an ellipse instead.

Complete partial circles in an image using MATLAB

I have binary images and they have semi or less circles. My aim is to find these circles, make them whole circles and remove all other objects . I found this but it is for MATLAB R2013a. I am using R2011b and it doesn't have the function centers = imfindcircles(A,radius).
How can I do that in MATLAB version R2011b?
Images:
Edit:
My aim is to get whole circle. I show this below for the last image.
Too bad about imfindcircles! One thing I can suggest is to invoke regionprops and specify the 'Area' and 'BoundingBox' flags. regionprops was available in MATLAB for as long as I can remember, so we can certainly use it here.
What this will do is that whatever distinct objects that are seen in the image that are connected, we will find both their areas and their bounding boxes that bound them. After you do this, threshold on the area so that any objects that have a very large area most likely contain circles of interest. Bear in mind that I'm only assuming that you have circles in your image. Should you have any objects that have a large area, this method will extract those out too.
As such, let's read in your image directly from Stack Overflow. When you uploaded the image, it's a RGB image, so I'll have to convert to binary:
im = imread('http://i.stack.imgur.com/wQLPi.jpg');
im_bw = im2bw(im);
Next, call regionprops:
s = regionprops(im_bw, 'Area', 'BoundingBox');
Now, collect all of the areas, and let's take a look at all of the unique areas of all objects seen in this image:
areas = [s.Area].';
unique(areas)
ans =
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
19
20
23
24
25
28
29
38
43
72
73
85
87
250
465
3127
If you take a look at the very end, you'll see that we have an object that has 3127 pixels in it. This probably contains our circle. As such, let's pick out that single element that contains this object:
s2 = s(areas == 3127);
In general, you'll probably have more than one circle in your image, so you should threshold the area to select those potential circles. Something like:
s2 = s(areas > 2000);
Now, let's create a new blank image that is the same size as the original image, then simply use the BoundingBox property to extract out the area that encompasses the circle in the original image and copy it over to the same location in the output image. The BoundingBox field is structured in the following way:
[x y w h]
x and y are the top-left corner of the bounding box. x would be the column and y would be the row. w and h are the width and height of the bounding box. As such, we can use this directly to access our image and copy those pixels over into the output image.
out = false(size(im_bw));
bb = floor(s2.BoundingBox); %// Could be floating point, so floor it
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
This is what I get:
What you should probably do is loop over the circles in case we have more than one. The above code assumes that you detected just one circle. Therefore, do something like this:
out = false(size(im_bw));
for idx = 1 : numel(s2) %// For each potential circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
%// Copy over pixels from original bw image to output
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end
A small thing to note is that the bounding box encompasses the entire object, but there could also be some noisy pixels that are disconnected that are within that bounding box. You may have to apply some morphology to get rid of those pixels. A binary opening could suffice.
Here's what I get with your other images. I thresholded the area to search for those that have 2000 pixels or more (I did this above):
Just for self-containment and your copy-and-pasting pleasure, here's the code in one segment:
clear all;
close all;
%im = imread('http://i.stack.imgur.com/qychC.jpg');
%im = imread('http://i.stack.imgur.com/wQLPi.jpg');
im = imread('http://i.stack.imgur.com/mZMBA.jpg');
im_bw = im2bw(im);
s = regionprops(im_bw, 'Area', 'BoundingBox');
areas = [s.Area].';
s2 = s(areas > 2000);
out = false(size(im_bw));
for idx = 1 : numel(s2) %// For each potential circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
%// Copy over pixels from original bw image to output
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end
imshow(out);
All three images are there in the code. You just have to uncomment whichever one you want to use, comment out the rest, then run the code. It will display an image with all of your detected circles.
Edit
You would like to draw complete circles, instead of extracting the shape themselves. That isn't a problem to do. All you need to do is determine the best "radii" that can be enclosed inside each of the bounding boxes. This is simply the maximum of the width and height of each bounding box, then divide these quantities by 2.
After, create a 2D grid of co-ordinates through meshgrid that is the same size as the original image itself, then create a binary image such that the Euclidean distance between the centre of this bounding box with any point in this 2D grid less than the radius is set to logical true while the other positions are set to logical false.
In other words, do this:
clear all;
close all;
im = imread('http://i.stack.imgur.com/qychC.jpg');
%im = imread('http://i.stack.imgur.com/wQLPi.jpg');
%im = imread('http://i.stack.imgur.com/mZMBA.jpg');
im_bw = im2bw(im);
s = regionprops(im_bw, 'Area', 'BoundingBox');
areas = [s.Area].';
s2 = s(areas > 2000);
out = false(size(im_bw));
for idx = 1 : numel(s2) %// For each potential circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
%// Copy over pixels from original bw image to output
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end
figure;
imshow(out);
%// Image that contains all of our final circles
out2 = false(size(im_bw));
[X,Y] = meshgrid(1:size(im_bw,2), 1:size(im_bw,1)); %// Find a 2D grid of co-ordinates
for idx = 1 : numel(s2) %// For each circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
cenx = bb(1) + (bb(3) / 2.0); %// Get the centre of the bounding box
ceny = bb(2) + (bb(4) / 2.0);
radi = max(bb(3), bb(4)) / 2; %// Find the best radius
tmp = ((X - cenx).^2 + (Y - ceny).^2) <= radi^2; %// Draw our circle and place in a temp. image
out2 = out2 | tmp; %// Add this circle on top of our output image
end
figure;
imshow(out2);
This script now shows you the original extracted shapes, and the best "circles" that describes these shapes in two separate figures. Bear in mind that this is a bit different than what I showed you previously with one circle. What I have to do now is allocate a blank image, then incrementally add each circle to this new image. For each circle, I create a temporary binary image that has just a circle I'm looking for, then I add this on top of the new image. At the end, we will show all of the circles in the image that are fully drawn as you desire.
This is what I get for the best circle for each of your images:
Good luck!

geom2d - oriented bounding box

I calculated a rectangle (that does not need to be axis aligned) in an image and now want to check which pixel are inside that rectangle.
I believe the best way is to rotate each point in the image around the center point of the rectangle, such that the bounding box is axis aligned in the "new image". Then, we can quite easily check if a point is inside the rectangle or not.
I tried achieving this, by calculating an oriented bounding box with the geom2d package for my rectangle, which also gives us "the orientation of the length axis. Orientation is counted in degrees, counter-clockwise."
Up to now, I have not been able to understand exactly how the angle is defined. If I do the following:
obox1 = orientedBox([1 3; 4 1; 12 3; 9 5]);
obox2 = orientedBox([12 8; 9 10; 20 2; 24 3]);
figure;
isInside = false(15,25);
imshow(isInside);hold on;
drawOrientedBox(obox1, 'green');
drawOrientedBox(obox2, 'red');
I get
with angle of green box = 14.03° and angle of red box = 154.98°. How do these values need to be interpreted?
Link to geom2d package:
http://www.mathworks.com/matlabcentral/fileexchange/7844-geom2d/content/geom2d/geom2d/orientedBox.m