I'm currently plotting 2 separate 3-dimensional amorphous blobs which overlap each other. I have created the blobs by deforming a unit circle (as you can see in the code provided below). My question is: is there an easy way to isolate the overlapping region? I need to isolate the overlapping region and then color it differently (as in turn the region green, for example) to clearly show where the overlap is. My actual program has many shapes that overlap, however for the sake of simplicity, i have produced the following code to illustrate what i am trying to do:
% Create Sphere with 100 points
N = 100; % sphere grid points
[X,Y,Z] = sphere(N); % get x,y,z coordinates for sphere
num=size(X,1)*size(X,2); % get total amount of x-coordinates (m*n)
% Loop through every x-coordinate and apply scaling if applicable
for k=1:num % loop through every coordinate
value=X(k); % store original value of X(k) as value
if value<0 % compare value to 0
X(k)=0.3*value; % if < 0, scale value
end
end
% Loop through every z-coordinate and apply scaling if applicable
for k=1:num % loop through every coordinate
value=Z(k); % store original value of X(k) as value
if value>0 % compare value to 0
Z(k)=0.3*value; % if < 0, scale value
end
end
mesh(X,Y,Z,'facecolor','y','edgecolor','y','facealpha',...
0.2,'edgealpha',0.2);
hold on
mesh(-1*(X-1),Y,Z,'facecolor','r','edgecolor','r','facealpha',...
0.2,'edgealpha',0.2);
hold off
axis equal
I'm not necessarliy looking for code, just an effective algorithm or process to achieve the desired results as I need to adapt this result into the more sophisticated program I have.
Maintain an array (n-dimensional) of integers, as you draw your objects, increment each corresponding point in the array. When done, loop through the array, and each element > 1 has an overlap between two or more objects, use the array coordinate to color the objects based on the number of overlaps.
I have worked in 2D with the MATLAB builtin function inpolygon to find out overlapping areas. However, it does not natively support 3d. I would suggest you try the inhull function which you can find here at file exchange. Please note it only supports convex hulls.
If that doesn´t help you maybe you find some inspiration in this discussion.
Related
I am writing a code that is trying to color the complex plane, such that all points exactly a distance of 1 unit from them are different colors. Comparing the distance between a large number of points takes too long for my code.
What I have tried doing so far is to create a point at the origin, then it creates a single point on the unit circle, colors it different and then moves to the next point on the unit circle. My code compares each point to every other point created by checking the distance between them to see if it's 1, and if it is, then compares the color to ensure they are different. My code works for a small number of points but gets very slow as the number of points grows (as after I complete the unit circle around the origin, I create unit circle around each point that I just created an so on). How can a cut down the number of comparisons I make?
p=[p;p(m,1)+exp(1i*j*h),1]; % the list of points already created
l=length(p)-1; % the length for my for loop
toss=[]; % creates storage of colors already used
for k1=1:l % checks every point previously created
% if statement checks the distance between two point
if abs(p(end,1)-p(k1,1))>(1-tol) & abs(p(end,1)-p(k1,1))<(1+tol)
toss=[toss,p(k1,2)]; % adds the color of any point in a unit step
end
end
colornum=[1,2,3,4,5,6]; % defines colors as number
toss=unique(toss); % condenses all the colors already used
Arr3 = setxor(colornum,toss); %creates a vector of unused colors
p(end,2)=Arr3(1); % assigns the first available color
I would like for the output to be a large matrix with the first column being the position in the complex plane and the second column being the number corresponding to a color
The slowing is probably because of the loop and if statement.
Try to vectorize it :
point_to_compare = p(end,1);
vec_to_compare = p(1:end-1,1);
points_to_add = [abs(abs(vec_to_compare - point_to_compare)-1)<tol; false];
toss = p(points_to_add,2);
I have built a 3D model from a 2D image. I want to know how much accurate my model is using some statistical test. I think there are many available methods to do this like correlation and mean squares as mentioned in this question, Is it possible to compare 3D images?.
I couldn't find a clear description of the available tests in other sites. I've found an implementation which compares 2D images using square means here, http://www.mathworks.com/matlabcentral/answers/81048-mse-mean-square-error. I'm not sure if this can be used to calculate the model accuracy. Also, I didn't find an explanation of how the tests work, i.e. what parameters are compared (color, intensity, etc.) ?
EDIT: For more clarity, the 3D model represents every pixel in the 2D image as a voxel which has a color associated with it. The purpose of this model is to reconstruct the different color regions found in the 2D image into the 3D representation. So, the number of pixels that has some color (they represent a region) is calculated from the 2D image. A similar number of voxels will be constructed in the 3D model and given the same color. What matters in this modeling problem is the following,
1- size of the regions (must be almost similar in the 2D image and the model).
2-Connectivity level of a region in the 2D image and its corresponding region constructed in the 3D image must be similar. By connectivity I mean to check if the region components are scattered through the image or they are connected forming one large connected region instead of many small scattered regions of the same color.
EDIT2: I think color correlogram is suitable. I have found a code that implements it, but it is not clear to me. Here is the code,
% Soumyabrata Dev
% E-mail: soumyabr001#e.ntu.edu.sg
% http://www3.ntu.edu.sg/home2012/soumyabr001/
I= imread ('img.jpg');
correlogram_vector=[];
[Y,X]=size(rgb2gray(I));
% quantize image into 64 colors = 4x4x4, in RGB space
[img_no_dither, ~] = rgb2ind(I, 64, 'nodither');
% figure, imshow(img_no_dither, map);
%rgb = ind2rgb(img_no_dither, map); % rgb = double(rgb)
distance_vector= [1 3];
[~,d]=size(distance_vector);
count_matrix=zeros(64,d); total_matrix=zeros(64,d);
prob_dist=cell(1,d);
for serial_no=1:1:d
for x=1:X
for y=1:Y
color=img_no_dither(y,x);
% At the given distance
[positive_count,total_count]=get_n(distance_vector(serial_no),x,y,color,img_no_dither,X,Y);
count_matrix(color+1,serial_no)=count_matrix(color+1,serial_no)+positive_count;
total_matrix(color+1,serial_no)=total_matrix(color+1,serial_no)+total_count;
end
end
prob_dist{serial_no}=count_matrix(:,serial_no)./(1+total_matrix(:,serial_no));
end
for serial_no=1:d
correlogram_vector=cat(1,correlogram_vector,prob_dist{serial_no});
end
end
This is the method get_n,
function [positive_count,total_count]=get_n(n,x,y,color,img_no_dither,X,Y)
% This function is useful to get the validity map of the neighborhood case.
% It can handle any number of neighborhood distances.
% Input
% n=The order of the neighborhood
% x & y= x y co-ordinates of the given pixel
% color= particular quantized color
% img_no_dither= The color quantized image matrix
% X & Y= The original dimensions of the input image
% Output
% positive_count= The number of occurences which have the same color
% total_count= The total number of valid cases for this particular instant
valid_vector8n=zeros(1,8*n); % This is because of the propoerty of inf-norm. Each distance has 8 times the order
positive_count=0; total_count=0;
nbrs_x=zeros(1,8*n); nbrs_y=zeros(1,8*n);
% The counting of the pixels is done in the following manner: From the
% given pixel, go left-->up-->right-->down-->left-->up
% Y co-ordinates of nbrs
nbrs_y(1)=y;
d=1;
for k=2:1+n
nbrs_y(k)=y-d;
d=d+1;
end
nbrs_y(1+n:1:3*n+1)=y-n;
d=0;
for k=3*n+1:5*n+1
nbrs_y(k)=y-n+d;
d=d+1;
end
nbrs_y(5*n+1:1:7*n+1)=y+n;
d=0;
for k=7*n+1:1:7*n+1+(n-1)
nbrs_y(k)=y+n-d;
d=d+1;
end
% X co-ordinates of nbrs
nbrs_x(1)=x-n;
nbrs_x(2:1:1+n)=x-n;
d=0;
for k=1+n:1:3*n+1
nbrs_x(k)=x-n+d;
d=d+1;
end
nbrs_x(3*n+1:5*n+1)=x+n;
d=0;
for k=5*n+1:7*n+1
nbrs_x(k)=x+n-d;
d=d+1;
end
nbrs_x(7*n+1:7*n+1+(n-1))=x-n;
% Assigning the validity of the neighborhood
for i=1:8*n
if nbrs_x(i)>0 && nbrs_x(i)<=X && nbrs_y(i)>0 && nbrs_y(i)<=Y
valid_vector8n(i)=1;
else
valid_vector8n(i)=0;
end
end
% Couting the number of common colors in the valid areas of the
% neighborhood.
for j=1:8*n
if valid_vector8n(j)==1
data= img_no_dither(nbrs_y(j),nbrs_x(j));
if (data==color)
positive_count=positive_count+1;
end
total_count=total_count+1;
end
end
end
Can anyone please clarify how this code works?
The code above is for autocorrelogram not correlogram. I've read that the first is better, but it can only calculate the spatial probability using pixels of the same colors (can't be applied on pairs of pixels which have different colors). Is this right?
Thank You.
TLDR: Classical workflow:
find matching features in both models,
calculate the distance,
??????,
PROFIT!!
So i have this code to obtain radial gravity on Earth in function of the latitude:
G=6.6e-11;
M=5.976e24;
N=1000;
r=6371000;
w=2*pi/(24*3600);
for i=1:1:360
Theta=i*pi/180;
x(i)=i;
Vi(i)=-G*M/(r*r);
Phii(i)=r*w*w*sin(Theta)*sin(Theta);
gr(i)=Vi(i)+Phii(i);
end
plot(x,gr)
And it runs well. I want to make a graph of a circle made of a border of points (representing angle (i)) that change colour according to the value of gr(I want to set ranges of values of gr so that if the value obtained falls in a specific category, the point will have a specific colour).
I'm really new to MATLAB. Is there any possible way to make this?
Thanks in advance.
Here is the basic algorithm that I would do:
Determine how many colours you want to represent in your plot.
Create a colour map that has this many points for what you want to compute.
Determine a linearly increasing vector that varies from the minimum value of gr to the maximum value of gr with as many points as you have determined in Step #2
For each point in gr:
a. Determine which point yields the closest distance of this point to the vector in Step #3
b. Use this to index which colour you want.
c. Convert your angle into Cartesian co-ordinates, then plot this point with the colour found in Step 4b.
Let's tackle each point in detail.
Step #1 - Determine how many colours you want
This is pretty simple. Just determine how many colours you want. For now, let's assume that you want 20 colours, so:
num_colours = 20;
Step #2 - Create a colour map
What we can do is create a 20 x 3 matrix where each row determines a RGB tuple that denotes the amount of red, green and blue that each colour will occupy. MATLAB has built-in colour maps that will help you facilitate this. Here are all of the available colour maps that MATLAB has:
Each colour map has a special variable where you can provide it an integer number, and it'll return this 2D matrix of as many rows as the number you have provided. Each row gives you an RGB triplet which denotes the proportion of red, green and blue respectively. This matrix varies from the beginning of the colour map (top row) to the end (bottom row). All you have to do is use any name seen in the figure I've shown you above to create a colour map of that type. For example, if you wanted to get a bones colour map of 15 points, simply do:
colour_map = bones(15);
If you wanted to get a jet colour map of 25 points, simply do:
colour_map = jet(25);
.... you get the idea right? I like hsv so let's use the HSV colour map. You can use any colour map you want, but let's just stick with HSV for the sake of this example.
As such:
colour_map = hsv(num_colours);
Step #3 - Get that linearly increasing vector
You want certain colours to map into certain ranges, which is why this step is important. Given a value in gr, we want to figure out which colour we want to choose, and all you have to do is determine which value in gr is the closest to a value in this vector in Step #3. Therefore, you can use linspace to do this for you:
bin_vector = linspace(min(gr), max(gr), num_colours);
This will create a num_colours 1D array where the beginning of this array starts at the minimum value of gr and varies up to the maximum value of gr and each value is equally spaced such that we generate a num_colours array.
Step #4 - Bring it all home
Now, for each point in gr, we need to figure out which point is the closest to that vector in Step #3, we then use this to figure out the colour we want, then we need to convert our angle into Cartesian co-ordinates, then plot this point.
For illustration purposes, I'm going to assume your radius is 1. You can figure out how to get the x and y co-ordinates by simply doing cos(theta) and sin(theta), where theta is the angle you are examining. Since your gr array has 360 slots, I'm going to assume a resolution of 1 degree per slot. Therefore, you can easily do this in a for loop. Make sure you use hold on because we are going to call plot multiple times, and we don't want to overwrite the plot each time we call plot. You want all of the points to stay in the plot.
Without further ado:
figure; %// Create blank figure
hold on; %// Remember all points
%// For each point in our array...
for idx = 1 : 360
%// Find the closest slot between gr and our vector in Step #3
[~,min_idx] = min(abs(gr(idx) - bin_vector));
%// Grab this colour
clr = colour_map(min_idx,:);
%// Plot the point with this colour
plot(cosd(idx), sind(idx), '.', 'Color', clr, 'MarkerSize', 10);
end
Take notice that cosd and sind take in degrees as the input argument while cos and sin take in radians. Also, take note that I also changed the size of the point so that it's bigger. With the above logic, and your array in gr, this is what I get:
If you want the radius to get larger, all you have to do is multiply each cosd and sind term with your radius. Therefore, you can do something like this:
radius = 2;
for idx = 1 : 360
... %// Insert colour code here
...
...
%// Now plot
plot(radius*cosd(idx), radius*sind(idx), '.', 'Color', clr, 'MarkerSize', 10);
end
Just leave the code the same, but for the plot command, just multiply each x and y value by the radius.
Minor note in efficiency
The way you're calculating your gr array is using an inefficient for loop. There are some situations (like mine above) where you need to use a for loop, but for simple computations there is no need. It's better if you vectorize its creation. Therefore, you can get rid of the for loop to calculate your gr array like so:
x = 1 : 360;
Theta = x*pi/180;
Phii = r*w*w*sin(Theta).*sin(Theta);
Vi = -G*M/(r*r);
gr = Vi + Phii;
x is simply a vector going from 1 to 360, and that's done in the first line. Also, Vi is just an array which contains a single value and if you know how operations work between a scalar and an array, you can just do an addition with this single value and it'll add every value in your array by this much. As such, there's no need to create an array for Vi. Also, take a look at how I calculated Phii. I'm using element-by-element operations as Theta is now an array. You want to create an array Phii that takes corresponding values of Theta, and applies that formula to each value in Theta to produce Phii.
Hope this helps. Good luck!
I want to assign vector to a contourf graph, in order to show the direction and magnitude of wind.
For this I am using contourf(A) and quiver(x,y), where as A is a matrix 151x401 and x,y are matrices with the same sizes (151x401) with magnitude and direction respectively.
When I am using large maps i get the position of the arrows but they are to densily placed and that makes the graph look bad.
The final graph has the arrows as desired, but they are to many of them and too close, I would like them to be more scarce and distributed with more gap between them, so as to be able to increase their length and at the same time have the components of the contour map visible.
Can anyone help , any pointers would be helpful
i know its been a long time since the question was asked, but i think i found a way to make it work.
I attach the code in case someone encounters the same issues
[nx,ny]= size(A) % A is the matrix used as base
xx=1:1:ny; % set the x-axis to be equal to the y
yy=1:1:nx; % set the y-axis to be equal to the x
contourf(xx,yy,A)
hold on, delta = 8; %delta is the distance between arrows)
quiver(xx(1:delta:end),yy(1:delta:end),B(1:delta:end,1:delta:end),C(1:delta:end,1:delta:end),1) % the 1 at the end is the size of the arrows
set(gca,'fontsize',12);, hold off
A,B,C are the corresponding matrices ones want to use
If I explain why, this might make more sense
I have a logical matrix (103x3488) output of a photo of a measuring staff having been run through edge detect (1=edge, 0=noedge). Aim- to calculate the distance in pixels between the graduations on the staff. Problem, staff sags in the middle.
Idea: User inputs co-ordinates (using ginput or something) of each end of staff and the midpoint of the sag, then if the edges between these points can be extracted into arrays I can easily find the locations of the edges.
Any way of extracting an array from a matrix in this manner?
Also open to other ideas, only been using matlab for a month, so most functions are unknown to me.
edit:
Link to image
It shows a small area of the matrix, so in this example 1 and 2 are the points I want to sample between, and I'd want to return the points that occur along the red line.
Cheers
Try this
dat=imread('83zlP.png');
figure(1)
pcolor(double(dat))
shading flat
axis equal
% get the line ends
gi=floor(ginput(2))
x=gi(:,1);
y=gi(:,2);
xl=min(x):max(x); % line pixel x coords
yl=floor(interp1(x,y,xl)); % line pixel y coords
pdat=nan(length(xl),1);
for i=1:length(xl)
pdat(i)=dat(yl(i),xl(i));
end
figure(2)
plot(1:length(xl),pdat)
peaks=find(pdat>40); % threshhold for peak detection
bigpeak=peaks(diff(peaks)>10); % threshold for selecting only edge of peak
hold all
plot(xl(bigpeak),pdat(bigpeak),'x')
meanspacex=mean(diff(xl(bigpeak)));
meanspacey=mean(diff(yl(bigpeak)));
meanspace=sqrt(meanspacex^2+meanspacey^2);
The matrix pdat gives the pixels along the line you have selected. The meanspace is edge spacing in pixel units. The thresholds might need fiddling with, depending on the image.
After seeing the image, I'm not sure where the "sagging" you're referring to is taking place. The image is rotated, but you can fix that using imrotate. The degree to which it needs to be rotated should be easy enough; just input the coordinates A and B and use the inverse tangent to find the angle offset from 0 degrees.
Regarding the points, once it's aligned straight, all you need to do is specify a row in the image matrix (it would be a 1 x 3448 vector) and use find to get non-zero vector indexes. As the rotate function may have interpolated the pixels somewhat, you may get more than one index per "line", but they'll be identifiable as being consecutive numbers, and you can just average them to get an approximate value.