How to turn a pair of X, Y points in decimal into an image more accurately? - matlab

Normally this table is around 600 points but I didn't want to type it all, let's say I have points like this:
240.021000000000 291.414100000000
250.985100000000 297.566300000000
260.143500000000 310.125800000000
270.605100000000 315.355400000000
279.775500000000 327.352000000000
288.302300000000 335.765900000000
301.487400000000 348.374900000000
313.892100000000 340.501400000000
323.391400000000 328.044800000000
334.615100000000 322.182400000000
Where number on the left is X and number on the right is Y of a coordinate where there is a "thing" or let's say where the color is white and rest is black.
And I want to turn this into an image, what I did so far is this:
% Added 50 more pixels to not stick to edge of image
image = uint8(zeros(max(table(:, 1))+50, max(table(:, 2)+50))
for i = size(table(:))
image(round(table(i, 1)), round(table(i, 2))) = 256;
end
imshow(image);
I am wondering how accurate this is and how I can improve it or if I can improve it?
Reason here is I will do this for two tables and need to compare the similarity of two images that belong to these tables, but I don't even have an image and rounding didn't feel like the best way since 270.49999999 and 270.5000001 are similar, yet 270 and 271 are different. There can also be points that overlap each other if all is just rounded up or just rounded down.

I see two approaches, you can increase the resolution by binning your image to be N*600 by N*600 point instead of 600x600, for example 6000x6000, then each 0.1 value will be in a different pixel. Or, you can convolve your 1 pixel with a distribution like a 5x5 Gaussian of signa=1 that will capture the spread around that point position. For example using exp(- ((x-xn).^2+(x-yn).^2)/2) where xn and yn are the n-th point coordinate in your question, and x and y are obtained via [x y]=meshgrid(1:600) or whatever your image size is....

Related

How do i effectively compare an image with another image whose resolution is double of the original image?

I have two sets of 3D images (they come in form of 2D stacks). Image A is 10 micron, with size: 1000 x 1024 x 1017, while image B is 5 micron, with size: 2004 x 2048 x 2036. I like to make some computations on randomly chosen set of the 2D slices of A, and then compare this to the same set of slices for B. However, since B has twice the number of slices for each slice of A, will it be sensible to compare two slices of B to each of A? If so, how do i determine exactly which of the two slices of B make up a slice of A?
While contemplating on this, i also thought of blowing up A by 2 using imresize function for each 2D slice that i chose for the computation. Will it be okay to compare this new B with the A, considering that i have completely ignored what happens with the z-coordinate?
Thank you.
As you mentioned this is microCT, I am assuming that both images are different size resolution of the same object. This means that pixels have specific spatial location, not only value, therefore for this case, there are no pixels (assuming a pixel is a infinitesimally small dot in the center of the cube) that match in both images.
So, lets assume that in image A, the locations of the pixel centers are their indices (1,1,1), (1,1,2) etc. This means that the image starts (pixel boundaries) at "world value" 0.5, and ends at size(imgA)+0.5
Now, first lets transform the desired pixel coordinates for interpolation to this range. imgB pixel centers are then in locations (ind-0.5)*size(imgA)/size(imgB)+0.5.
Example: Assume
size(imgA,1)=3; size(imgB,1)=4;
therefore the pixels in imgA are at x location 1:3. The pixels on imgB are, using the above formula, in [0.8750 1.6250 2.3750 3.1250].
Note how the first pixel is 0.375 from 0.5 (our image border) and the next pixel is at 0.75 (double 0.375*2).
We scaled a higher resolution image to the same "real world" coordinates.
Now to the real stuff.
We need to create the desired coordinates in the reference (A) image. For that, we do:
[y, x, z]=...
ndgrid((1:size(imgB,1)-0.5)*size(imgA,1)/size(imgB,1)+0.5),...
(1:size(imgB,2)-0.5)*size(imgA,2)/size(imgB,2)+0.5),...
(1:size(imgB,3)-0.5)*size(imgA,3)/size(imgB,3)+0.5);
Now these 3 have the coordinates we want. Caution! each of these are size(imgB) !!! You need to have the RAM 5*size(imgB) in total to work with this.
Now we can interpolate
imAinB=interp3(imgA,x,y,z,'linear'); % Or nearest
It seems to be that your function is imresize3. You can change one volume to the other's dimentions with:
B = imresize3(V,[numrows numcols numplanes])
You can also explore interpolation methods.

How to make a heat map on top of worldmap using hist3 in MATLAB?

My x-axis is latitudes, y-axis is longitudes, and z-axis is the hist3 of the two. It is given by: z=hist3(location(:,1:2),[180,360]), where location(:,1) is the latitude column, and location(:,2) is the longitude column.
What I now want is, instead of plotting on a self-created XY plane, I want to plot the same on a worldmap. And instead of representing the frequency of each latitude-longitude pair with the height of the bars of hist3, I want to represent the frequency of each location by a heat map on top of the world map, corresponding to each latitude-longitude pair's frequency on the dataset. I have been searching a lot for this, but have not found much help. How to do this? I could only plot the skeleton of the worldmap like this:
worldmap world
load geoid
geoshow(geoid, geoidrefvec, 'DisplayType', 'texturemap');
load coast
geoshow(lat, long)
I don't know what the colour is being produced based on.
Additionally, if possible, I would also like to know how to plot the hist3 on a 3D map of the world (or globe), where each bar of the hist3 would correspond to the frequency of each location (i.e., each latitude-longitude pair). Thank you.
The hist3 documentation, which you can find here hist3, says:
Color the bars based on the frequency of the observations, i.e. according to the height of the bars. set(get(gca,'child'),'FaceColor','interp','CDataMode','auto');
If that's not what you need, you might wanna try it with colormap. More info about it here colormap. I haven't tried using colormap on histograms directly, so If colormap doesn't help, then you can try creating a new matrix manually which will have values in colors instead of the Z values the histogram originally had.
To do that, you need to first calculate the maximum Z value with:
maxZ=max(Z);
Then, you need to calculate how much of the colors should overlap. For example, if you use RGB system and you assign Blue for the lowest values of the histogram, then Green for the middle and Red for the High, and the green starts after the Blue with no overlap, than it will look artificial. So, if you decide that you will have, for example overlapping of 10 values, than, having in mind that every R, G and B component of the RGB color images have 255 values (8 bits) and 10 of each overlap with the former, that means that you will have 255 values (from the Blue) + 245 values (From the Green, which is 255 - 10 since 10 of the Green overlap with those of the Blue) + 245 (From the Red, with the same comment as for the Green), which is total amount of 745 values that you can assign to the new colored Histogram.
If 745 > maxZ there is no logic for you to map the new Z with more than maxZ values. Then you can calculate the number of overlaping values in this manner:
if 745 > maxZ
overlap=floor(255- (maxZ-255)/2)
end
At this point you have 10 overlapping values (or more if you still think that it doesn't looks good) if the maximum value of the Z is bigger than the total amount of values you are trying to assign to the new Z, or overlap overlapping values, if the maximum of Z is smaller.
When you have this two numbers (i.e. 745 and maxZ), you can write the following code so you can create the newZ.
First you need to specify that newZ is of the same size as Z. You can achieve that by creating a zero matrix with the same size as Z, but having in mind that in order to be in color, it has to have an additional dimension, which will specify the three color components (if you are working with RGB).
This can be achieved in the following manner:
newZ=zeros(size(Z),3)
The number 3 is here, as I said, so you would be able to give color to the new histogram.
Now you need to calculate the step (this is needed only if maxZ > The number of colors you wish to assign). The step can be calculated as:
stepZ=maxZ/Total_Number_of_Colors
If maxZ is, for example 2000 and Total_Number_of_Colors is (With 10 overlaping colours) 745, then stepZ=2.6845637583892617449664429530201. You will also need a counter so you would know what color you would assign to the new matrix. You can initialize it here:
count=0;
Now, finally the assignment is as follows:
For i=1:stepZ:maxZ
count=count+1;
If count>245
NewZ(Z==stepz,3)=count;
elseif count>245 && count<256
NewZ(Z==stepz,3)=count;
NewZ(Z==stepz,2)=count-245;
elseif count>255
NewZ(Z==stepz,2)=count-245;
elseif count>500 && count<511
NewZ(Z==stepz,2)=count-245;
NewZ(Z==stepz,1)=count-500;
else
NewZ(Z==stepz,1)=count-500;
end
end
At this point you have colored your histogram. Note that you can manually color it in different colors than red, green and blue (even if you are working in RGB), but it would be a bit harder, so if you don't like the colors you can experiment with the last bit of code (the one with the for loops), or check the internet of some other automatic way to color your newZ matrix.
Now, how do you think to superimpose this matrix (histogram) over your map? Do you want only the black lines to be shown over the colored histogram? If that's the case, than it can be achieved by resampling the NewZ matrix (the colored histogram) with the same precision as the map. For example, if the map is of size MxN, then the histogram needs to be adjusted to that size. If, on the other hand, their sizes are the same, then you can directly continue to the next part.
Your job is to find all pixels that have black in the map. Since the map is not binary (blacks and whites), it will be a bit more harder, but still achievable. You need to find a satisfactory threshold for the three components. All the lines under this threshold should be the black lines that are shown on the map. You can test these values with imshow(worldmap) and checking the values of the black lines you wish to preserve (borders and land edges, for example) by pointing the cross tool on the top of the figure, in the tools bar on every pixel which is of interest.
You don't need to test all black lines that you wish to preserve. You just need to have some basic info about what values the threshold should have. Then you continue with the rest of the code and if you don't like the result so much, you just adjust the threshold in some trial and error manner. When you have figured that this threshold is, for example, (40, 30, 60) for all of the RGB values of the map that you wish to preserve (have in mind that only values that are between (0,0,0) and (40,30,60) will be kept this way, all others will be erased), then you can add the black lines with the following few commands:
for i = 1:size(worldmap,1)
for j = 1:size(worldmap,2)
if worldmap(i,j,1)<40 && worldmap(i,j,2)<30 && worldmap(i,j,3)<60
newZ(i,j,:)=worldmap(i,j,:)
end
end
I want to note that I haven't tested this code, since I don't have Matlab near me atm, so It can have few errors, but those should be easily debugable.
Hopes this is what you need,
Cheers!

Subpixel edge detection for almost vertical edges

I want to detect edges (with sub-pixel accuracy) in images like the one displayed:
The resolution would be around 600 X 1000.
I came across a comment by Mark Ransom here, which mentions about edge detection algorithms for vertical edges. I haven't come across any yet. Will it be useful in my case (since the edge isn't strictly a straight line)? It will always be a vertical edge though. I want it to be accurate till 1/100th of a pixel at least. I also want to have access to these sub-pixel co-ordinate values.
I have tried "Accurate subpixel edge location" by Agustin Trujillo-Pino. But this does not give me a continuous edge.
Are there any other algorithms available? I will be using MATLAB for this.
I have attached another similar image which the algorithm has to work on:
Any inputs will be appreciated.
Thank you.
Edit:
I was wondering if I could do this:
Apply Canny / Sobel in MATLAB and get the edges of this image (note that it won't be a continuous line). Then, somehow interpolate this Sobel edges and get the co-ordinates in subpixel. Is it possible?
A simple approach would be to project your image vertically and fit the projected profile with an appropriate function.
Here is a try, with an atan shape:
% Load image
Img = double(imread('bQsu5.png'));
% Project
x = 1:size(Img,2);
y = mean(Img,1);
% Fit
f = fit(x', y', 'a+b*atan((x0-x)/w)', 'Startpoint', [150 50 10 150])
% Display
figure
hold on
plot(x, y);
plot(f);
legend('Projected profile', 'atan fit');
And the result:
I get x_0 = 149.6 pix for your first image.
However, I doubt you will be able to achieve a subpixel accuracy of 1/100th of pixel with those images, for several reasons:
As you can see on the profile, your whites are saturated (grey levels at 255). As you cut the real atan profile, the fit is biased. If you have control over the experiments, I suggest you do it again again with a smaller exposure time for instance.
There are not so many points on the transition, so there is not so many information on where the transition is. Typically, your resolution will be the square root of the width of the atan (or whatever shape you prefer). In you case this limits the subpixel resolution at 1/5th of a pixel, at best.
Finally, your edges are not stricly vertical, they are slightly titled. If you choose to use this projection method, to increase the accuracy you should look for a way to correct this tilt before projecting. This won't increase your accuracy by several orders of magnitude, though.
Best,
There is a problem with your image. At pixel level, it seems like there are four interlaced subimages (odd and even rows and columns). Look at this zoomed area close to the edge.
In order to avoid this artifact, I just have taken the even rows and columns of your image, and compute subpixel edges. And finally, I look for the best fitting straight line, using the function clsq whose code is in this page:
%load image
url='http://i.stack.imgur.com/bQsu5.png';
image = imread(url);
imageEvenEven = image(1:2:end,1:2:end);
imshow(imageEvenEven, 'InitialMagnification', 'fit');
% subpixel detection
threshold = 25;
edges = subpixelEdges(imageEvenEven, threshold);
visEdges(edges);
% compute fit line
A = [ones(size(edges.x)) edges.x edges.y];
[c n] = clsq(A,2);
y = [1,200];
x = -(n(2)*y+c) / n(1);
hold on;
plot(x,y,'g');
When executing this code, you can see the green line that best aproximate all the edge points. The line is given by the equation c + n(1)*x + n(2)*y = 0
Take into account that this image has been scaled by 1/2 when taking only even rows and columns, so the right coordinates must be scaled.
Besides, you can try with the other tree subimages (imageEvenOdd, imageOddEven and imageOddOdd) and combine the four straigh lines to obtain the best solution.

Matlab Solid Circles

What we want is to draw several solid circles at random locations, with random gray scale colors, on a dark gray background. How can we do this? Also, if the circles overlap, we need them to change color in the overlapping part.
Since this is an assignment for school, we are not looking for ready-made answers, but for a guide which tools to use in MATLAB!
Here's a checklist of things I would investigate if you want to do this properly:
Figure out how to draw circles in MATLAB. Because you don't have the Image Processing Toolbox (see comments), you will probably have to make a function yourself. I'll give you some starter code:
function [xout, yout] = circle(x,y,r,rows,cols)
[X,Y] = meshgrid(x-r:x+r, y-r:y+r);
ind = find(X.^2 + Y.^2 <= r^2 & X >= 1 & X <= cols & Y >= 1 & Y <= rows);
xout = X(ind);
yout = Y(ind);
end
What the above function does is that it takes in an (x,y) co-ordinate as well as the radius of
the circle. You also will need to specify how many rows and how many columns you want in your image. The reason why is because this function will prevent giving you co-ordinates that are out of bounds in the image that you can't draw. The final output of this will give you co-ordinates of all values inside and along the boundary of the circle. These co-ordinates will already be in integer so there's no need for any rounding and such things. In addition, these will perfectly fit when you're assigning these co-ordinates to locations in your image. One caveat to note is that the co-ordinates assume an inverted Cartesian. This means that the top left corner is the origin (0,0). x values increase from left to right, and y values increase from top to bottom. You'll need to keep this convention in mind when drawing circles in your image.
Take a look at the rand class of functions. rand will generate random values for you and so you can use these to generate a random set of co-ordinates - each of these co-ordinates can thus serve as your centre. In addition, you can use this class of functions to help you figure out how big you want your circles and also what shade of gray you want your circles to be.
Take a look at set operations (logical AND, logical OR) etc. You can use a logical AND to find any circles that are intersecting with each other. When you find these areas, you can fill each of these areas with a different shade of gray. Again, the rand functions will also be of use here.
As such, here is a (possible) algorithm to help you do this:
Take a matrix of whatever size you want, and initialize all of the elements to dark gray. Perhaps an intensity of 32 may work.
Generate a random set of (x,y) co-ordinates, a random set of radii and a random set of intensity values for each circle.
For each pair of circles, check to see if there are any co-ordinates that intersect with each other. If there are such co-ordinates, generate a random shade of gray and fill in these co-ordinates with this new shade of gray. A possible way to do this would be to take each set of co-ordinates of the two circles and draw them on separate temporary images. You would then use the logical AND operator to find where the circles intersect.
Now that you have your circles, you can plot them all. Take a look at how plot works with plotting matrices. That way you don't have to loop through all of the circles as it'll be inefficient.
Good luck!
Let's get you home, shall we? Now this stays away from the Image Processing Toolbox functions, so hopefully these must work for you too.
Code
%%// Paramters
numc = 5;
graph_size = [300 300];
max_r = 100;
r_arr = randperm(max_r/2,numc)+max_r/2
cpts = [randperm(graph_size(1)-max_r,numc)' randperm(graph_size(2)-max_r,numc)']
color1 = randperm(155,numc)+100
prev = zeros(graph_size(1),graph_size(2));
for k = 1:numc
r = r_arr(k);
curr = zeros(graph_size(1),graph_size(2));
curr(cpts(k,1):cpts(k,1)+r-1,cpts(k,2):cpts(k,2)+r-1)= color1(k)*imcircle(r);
common_blob = prev & curr;
curr = prev + curr;
curr(common_blob) = min(color1(1),color1(2))-50;
prev = curr;
end
figure,imagesc(curr), colormap gray
%// Please note that the code uses a MATLAB file-exchange tool called
%// imcircle, which is available at -
%// http://www.mathworks.com/matlabcentral/fileexchange/128-imcircle
Screenshot of a sample run
As you said that your problem is an assignment for school I will therefore not tell you exactly how to do it but what you should look at.
you should be familiar how 2d arrays (matrices) work and how to plot them using image/imagesc/imshow ;
you should look at the strel function ;
you should look at the rand/randn function;
such concepts should be enough for the assignment.

matlab: area under overlapping circles

I have a question to you...
Imagine square with size A x A. Now lets simulate circles with diameter of d, randomly distributed within this square, something like on the image below (in this case d's are the same, but its not the rule, they might be also randomly distributed within some range like d1 to d2).
Lets say that circles are described in matrix as:
circles(1, :) = [x, y, d];
circles(2, :) = [x, y, d];
...and so on
where x, y are coordinates, d is diameter. Now the question is, how to simulate this circles, until given crowding parameter c is reached? c is simply defined as: c = yellow area / square area (in this case A^2).
And the second thing - lets say that everything is simulated and I want to check if some coordinate (x,y) is within or outside yellow area... How to do it? I was doing it by checking if my (x,y) is within area of each circle (but its getting more difficult when instead of circles I use i.e. round shape rectangles), one by one, but there must be some better way of doing it.
Thanks for help : )
Here is an approach that should do the trick:
Start with a large empty matrix (big enough to guarantee that every shape generated is fully inside the matrix). Suppose we do it like this color = zeros(100)
while we have not yet reached the cowding ratio: the midpoint and diameter of one circle, I assume you can manage this
change the color of all points in the circle, for example by setting it to one.
Calculate the crowding ratio (something like c = mean(mean(color))
Note, if you only want to use part of the matrix (enable shapes to fall partially out of the picture) this can for example be achieved by using mean(mean(color(11:end-11)) in step 4, ignoring the 10 pixels near the edge.
Now if you want to know whether point (x,y) is yellow, simply check the value of color(x,y). Or if you want to ignore the edges check color(x+10,y+10)