Hexagonal grid representing a cellular network as used in mobile communication systems - matlab

I am relatively new to Matlab and I want to generate a hexagonal grid that represents a cellular network where each hexagon has a specific behaviour.
My question is how does one go from a square grid to hex grid (transfer matrix)?. This is what I have so far.
[X,Y] = meshgrid(0:60);
figure(1), plot(X,Y,'b')
hold on, plot(Y,X,'b')
axis square

A few years ago I wrote some code to do just that:
%// Define input data:
close all
clear all
M_max = 14; %// number of cells in vertical direction
N_max = 10; %// number of cells in horizontal direction
trans = 1; %// hexagon orientation (0 or 1)
%// Do the plotting:
hold on
for m = -M_max:M_max
for n = -N_max:N_max
center = [.5 sqrt(3)/2] + m*[0 -sqrt(3)] + n*[3/2 sqrt(3)/2];
if ~trans
plot([center(1)-1 center(1)],[center(2) center(2)])
plot([center(1) center(1)+1/2],[center(2) center(2)+sqrt(3)/2])
plot([center(1) center(1)+1/2],[center(2) center(2)-sqrt(3)/2])
else %// exchange the two arguments to `plot`
plot([center(2) center(2)],[center(1)-1 center(1)])
plot([center(2) center(2)+sqrt(3)/2],[center(1) center(1)+1/2])
plot([center(2) center(2)-sqrt(3)/2],[center(1) center(1)+1/2])
end %if
end %for
end %for
plot([-15 15],[0 0],'-.') %// adjust length manually
plot([-15 15],[-15*sqrt(3) 15*sqrt(3)],'-.') %// adjust length manually
axis image
set(gca,'xtick',[])
set(gca,'ytick',[])
axis([-10 10 -13.3 13.3]) %// adjust axis size manually
set(gca,'Visible','off') %// handy for printing the image
For example, this is the image generated with the above data:

Related

Speeding up Octave / Matlab plot

Gnoivce and Hartmut helped a lot with this code but it takes a while to run.
The CData property in the bar command doesn't seem to be implemented in the Octave 4.0-4.2.1 version which I'm using. The work around for this was to plot all the single bars individually and set an individual color for each individual bar. People helped me out and got me this far but it takes 5 minutes for the plot to show does anyone know a way of speeding this up?
The following code runs:
marbles.jpg image file used below:
clear all,clf reset,tic,clc
rgbImage = imread('/tmp/marbles.jpg');
hsvImage = rgb2hsv(rgbImage); % Convert the image to HSV space
hPlane = 360.*hsvImage(:, :, 1); % Get the hue plane scaled from 0 to 360
binEdges = 0:360; %# Edges of histogram bins
N = histc(hPlane(:),binEdges); %# Bin the pixel hues from above
C = colormap(hsv(360)); %# create an HSV color map with 360 points
stepsize = 1; % stepsize 1 runs for a while...
for n=binEdges(2:stepsize:end) %# Plot the histogram, one bar each
if (n==1), hold on, end
h=bar(n,N(n));
set(h,'FaceColor',C(n,:)); %# set the bar color individually
end
axis([0 360 0 max(N)]); %# Change the axes limits
set(gca,'Color','k'); %# Change the axes background color
set(gcf,'Pos',[50 400 560 200]); %# Change the figure size
xlabel('HSV hue (in degrees)'); %# Add an x label
ylabel('Bin counts'); %# Add a y label
fprintf('\nfinally Done-elapsed time -%4.4fsec- or -%4.4fmins- or -%4.4fhours-\n',toc,toc/60,toc/3600);
Plot created after 5 mins:
To see original question original question
I'm guessing the loop is the bottleneck in your code that is taking so long? You could remove the loop and create the plot with one call to bar, then call set to modify the hggroup object and its child patch object:
h = bar(binEdges(1:end-1), N(1:end-1), 'histc'); % hggroup object
set(h, 'FaceColor', 'flat', 'EdgeColor', 'none');
hPatch = get(h, 'Children'); % patch object
set(hPatch, 'CData', 1:360, 'CDataMapping', 'direct');
Repeating your code with this fix renders right away for me in Octave 4.0.3:
As I suggested in a comment, I would use image (takes 0.12s on my system for your image).
EDIT: more comments, fix little bug, allow to create bins with stepsize > 1
img_fn = "17S9PUK.jpg";
if (! exist (img_fn, "file"))
disp ("downloading image from imgur.com...");
fflush (stdout);
urlwrite ("http://i.imgur.com/17S9PUK.jpg", "17S9PUK.jpg");
endif
rgbImage = imread (img_fn);
## for debugging so the matrixes fit on screen
if (0)
pkg load image
rgbImage = imresize (rgbImage, [6 8]);
endif
hsvImage = rgb2hsv(rgbImage);
hPlane = 360 .* hsvImage(:, :, 1);
## create bins, I've choosen 2 step to "smooth" the result
binEdges = 1:2:360;
N = histc (hPlane(:), binEdges)';
cm = permute (hsv (numel (binEdges)), [3 1 2]);
## Create an image with x = hue
img = repmat (cm, max(N), 1);
## Create binary mask which is used to black "img" dependent on N
sp = sparse (N(N > 0), (1:360)(N > 0), true, max(N), numel (binEdges));
mask = full (cumsum (flipud (sp)));
## extend mask in depth to suppress RGB
mask = repmat (mask, [1 1 3]);
## use inverted mask to "black out" pixels < N
img(logical (1 - flipud (mask))) = 0;
## show image
image (binEdges, 1:max(N), img)
set (gca, "ydir", "normal");
xlabel('HSV hue (in degrees)');
ylabel('Bin counts');
## print it for stackoverflow
print ("out.png")
Same as above but with bin width 1 (Elapsed time is 0.167423 seconds.)
binEdges = 1:360;

Colour Segmentation by l*a*b

I'm using the code on the MatLab website, "Color-Based Segmentation Using the Lab* Color Space":
http://www.mathworks.com/help/images/examples/color-based-segmentation-using-the-l-a-b-color-space.html
So I'm trying to select some areas myself instead of using the "load region_coordinates", using roipoly(fabric), but i get stuck. How do I save coordinates of the polygon I just drew? I'm actually following advice from lennon310 at Solution II, bottom of page:
A few questions about color segmentation with L*a*b*
I'm not sure when to save region_coordinates and do size(region_coordinates,1)
I made the following changes (Step 1):
1) Removed "load region_coordinates"
2) Added "region_coordinates = roipoly(fabric);"
Here's the code:
`
%% Step 1
fabric = imread(file);
figure(1); %Create figure window. "If h is not the handle and is not the Number property value of an existing figure, but is an integer, then figure(h) creates a figure object and assigns its Number property the value h."
imshow(fabric)
title('fabric')
%load regioncoordinates; % 6 marices(?) labelled val(:,:,1-6), 5x2 (row x column)
region_coordinates = roipoly(fabric);
nColors = 6;
sample_regions = false([size(fabric,1) size(fabric,2) nColors]); %Initializing an Image Dimension, 3x3 (:,:,:) to zero? Zeros() for arrays only I guess.
%Size one is column, size two is row?
for count = 1:nColors
sample_regions(:,:,count) = roipoly(fabric,region_coordinates(:,1,count),region_coordinates(:,2,count));
end
figure, imshow(sample_regions(:,:,2)),title('sample region for red');
%%Step 2
% Convert your fabric RGB image into an L*a*b* image using rgb2lab .
lab_fabric = rgb2lab(fabric);
%Calculate the mean a* and b* value for each area that you extracted with roipoly. These values serve as your color markers in a*b* space.
a = lab_fabric(:,:,2);
b = lab_fabric(:,:,3);
color_markers = zeros([nColors, 2]);%... I think this is initializing a 6x2 blank(0) array for colour storage. 6 for colours, 2 for a&b colourspace.
for count = 1:nColors
color_markers(count,1) = mean2(a(sample_regions(:,:,count))); %Label for repmat, Marker for
color_markers(count,2) = mean2(b(sample_regions(:,:,count)));
end
%For example, the average color of the red sample region in a*b* space is
fprintf('[%0.3f,%0.3f] \n',color_markers(2,1),color_markers(2,2));
%% Step 3: Classify Each Pixel Using the Nearest Neighbor Rule
%
color_labels = 0:nColors-1;
% Initialize matrices to be used in the nearest neighbor classification.
a = double(a);
b = double(b);
distance = zeros([size(a), nColors]);
%Perform classification, Elucidean Distance.
for count = 1:nColors
distance(:,:,count) = ( (a - color_markers(count,1)).^2 + (b - color_markers(count,2)).^2 ).^0.5;
end
[~, label] = min(distance,[],3);
label = color_labels(label);
clear distance;
%% Step 4: Display Results of Nearest Neighbor Classification
%
% The label matrix contains a color label for each pixel in the fabric image.
% Use the label matrix to separate objects in the original fabric image by color.
rgb_label = repmat(label,[1 1 3]);
segmented_images = zeros([size(fabric), nColors],'uint8');
for count = 1:nColors
color = fabric;
color(rgb_label ~= color_labels(count)) = 0;
segmented_images(:,:,:,count) = color;
end
%figure, imshow(segmented_images(:,:,:,1)), title('Background of Fabric');
%Looks different somehow.
figure, imshow(segmented_images(:,:,:,2)), title('red objects');
figure, imshow(segmented_images(:,:,:,3)), title('green objects');
figure, imshow(segmented_images(:,:,:,4)), title('purple objects');
figure, imshow(segmented_images(:,:,:,5)), title('magenta objects');
figure, imshow(segmented_images(:,:,:,6)), title('yellow objects');
`
You can retrieve the coordinates of the polygon using output arguments in the call to roipoly. You can then get a binary mask of the polygon, as well as vertices coordinates if you want.
Simple example demonstrating:
clear
clc
close all
A = imread('cameraman.tif');
figure;
imshow(A)
%// The vertices of the polygon are stored in xi and yi;
%// PolyMask is a binary image where pixels == 1 are white.
[polyMask, xi, yi] = roipoly(A);
This looks like this:
And if you wish to see the vertices with the binary mask:
%// display polymask
imshow(polyMask)
hold on
%// Highlight vertices in red
scatter(xi,yi,60,'r')
hold off
Which gives the following:
So to summarize:
1) The polygon's vertices are stored in xi and yi.
2) You can plot the binaryMask of the polygon using imshow(polyMask).
3) If you need the coordinates of the white pixels, you can use something like this:
[row_white,col_white] = find(polyMask == 1);
You're then good to go. Hope that helps!

How can I align plots/graphics in subplots in MATLAB?

I have 3 objects (a photo and 2 plots) to put into subplots on one figure. It should look like this:
But as one can notice, the photo should not be square but rectangle. I tried to make it this way (found here Matlab: How to align the axes of subplots when one of them contains a colorbar?):
main=subplot(4,4,[5,6,7,9,10,11,13,14,15]) %photo
imagesc(im);
axis('image')
pion=subplot(4,4,[8,12,16]); %right plot (rotated)
view(90, 90)
plot(ypion,Ppion,'.k');
poz=subplot(4,4,1:3); %upper plot
plot(xpoz,Ppoz,'.k');
pos1=get(poz,'Position')
pos2=get(main,'Position')
pos3=get(pion,'Position')
pos1(3) = pos2(3); %width for the upper plot
set(poz,'Position',pos1)
pos3(4) = pos2(4); %height for the right plot
set(pion,'Position',pos3)
All I get is like this:
How can I force the upper plot to have the width as the photo itself (not as the photo subplot)? Setting the equal widths of the subplots doesn't work, as the photo doesn't fill the subplot area.
The command axis image adjust the image axis ratio. So, in principle, if you adjust the plot ratios of the two plots to the same ratio, it will do what you want.
There is one caveat; the image is inherently 3 times wider or higher than the plots, due to the fact that you've plotted it in 3x3 subplots, vs 1x3 for the top and 3x1 for the right plots. So, you'll have to divide either the x or y ratios of the plots by 3.
Some example code:
clc, clf
% generate some bogus data
ypion = rand(500,1);
Ppion = 450*rand(500,1);
xpoz = rand(500,1);
Ppoz = 450*rand(500,1);
% Load photo
photoSub = subplot(4,4,[5,6,7,9,10,11,13,14,15]);
load mandrill
photo = imagesc([X,X]);
colormap(map)
axis image
photoAxs = gca;
photoAxsRatio = get(photoAxs,'PlotBoxAspectRatio')
% right plot
subplot(4,4,[8,12,16]);
plot(Ppion,ypion,'k.');
rightAxs = gca;
axis tight
% upper plot
subplot(4,4,[1 2 3]);
plot(xpoz,Ppoz,'k.');
topAxs = gca;
axis tight
% adjust ratios
topAxsRatio = photoAxsRatio;
topAxsRatio(2) = photoAxsRatio(2)/3.8; % NOTE: not exactly 3...
set(topAxs,'PlotBoxAspectRatio', topAxsRatio)
rightAxsRatio = photoAxsRatio;
rightAxsRatio(1) = photoAxsRatio(1)/3.6; % NOTE: not exactly 3...
set(rightAxs,'PlotBoxAspectRatio', rightAxsRatio)
This gives the following result:
Just to test, changing photo = imagesc([X,X]); to photo = imagesc([X;X]); gives this:
Note that I did not divide the ratios by 3 exactly; it only came out OK if I used factors closer to 4. I do not know why that is; AFAIK, a factor of 3 should do the trick...
Oh well, at least you have something to work with now :)
Here's a solution that removes the guesswork in the accepted answer. This solution is adapted from the original one posted here.
% adjust ratios
photoAxsratio = photoAxs.PlotBoxAspectRatio(1)/photoAxs.PlotBoxAspectRatio(2);
topAxsratio = photoAxsratio * photoAxs.Position(4)/topAxs.Position(4);
topAxs.PlotBoxAspectRatio = [topAxsratio, 1, 1];
rightAxsratio = rightAxs.Position(3) / (photoAxs.Position(3) / photoAxsratio);
rightAxs.PlotBoxAspectRatio = [rightAxsratio, 1, 1];
Preview:
A bit of explanation
Some of the explanation has been posted in the original post, I'm not going to repeat them here.
The idea is to calculate the correct aspect ratio for the figures required to be resized.
We have the following equations:
Photo.width = Photo.height * Photo.ratio
TopAxis.width = TopAxis.height * TopAxis.ratio
RightAxis.width = RightAxis.height * RightAxis.ratio
Let
TopAxis.width = Photo.width
RightAxis.height = Photo.height
We have
TopAxis.height * TopAxis.ratio = Photo.height * Photo.ratio
TopAixs.ratio = Photo.ratio * Photo.height / TopAxis.height
RightAxis.width / RightAxis.ratio = Photo.width / Photo.ratio
RightAxis.ratio = RightAxis.width / (Photo.width / Photo.ratio)
Since the release of matlab R2019b you can now use: tiledlayout and nexttile.
It is now easy to do:
% Load a random scary image
I = im2gray(imread('https://unwinnable.com/wp-content/uploads/2011/10/The-Ring-well.jpg'));
% Some computation...
Sx = sum(I)/max(sum(I));
Sy = sum(I,2)/max(sum(I,2));
% We create an empty 3x3 tiled layout:
% 1 2 3
% 4 5 6
% 7 8 9
tiledlayout(3, 3);
% Starting from the tile 1, we plot a 1x2 tile:
% 1 2 x
% x x x
% x x x
nexttile(1,[1 2])
plot(Sx,'k.')
% Starting from the tile 4, we plot a 2x2 tile:
% x x x
% 4 5 x
% 7 8 x
nexttile(4,[2 2])
imagesc(I)
colormap(gray(256))
% Starting from the tile 6, we plot a 2x1 tile:
% x x x
% x x 6
% x x 9
nexttile(6,[2 1])
plot(Sy,1:numel(Sy),'k.')
Matlab adjust the size of the plots automatically.
And we obtain:
Under the hood the tiled layout looks like this:
For this particular case I suggest using low-level axes directly instead of high-level subplot.
Use the 'OuterPosition' properties of the three axes objects you create to place them in the right place with the appropriate size.
If you want the image to be aligned to the axes(distorted image):
change axis('image') to axis('tight') .
If you want the image aspect ratio to remain, and to align the axes to the image:
Well this is quick and dirty, but after applying axis('tight'), resize the figure to the appropriate scale...

How can I create a plot like this in MATLAB?

I am trying to plot the ranges of different cellular base stations in MATLAB, like this:
But I can't figure out how to do it.
Here's an example of how you can create a plot like this. Note that I created sample data for the plot by randomly generating the positions of cellular base stations using uniformly distributed pseudorandom numbers:
%# Initializations:
minRange = 0; %# Lower x and y range
maxRange = 3.5; %# Upper x and y range
resolution = 1000; %# The number of data points on the x and y axes
cellRange = linspace(minRange, maxRange, resolution);
[x, y] = meshgrid(cellRange); %# Create grids of x and y coordinates
cellCoverage = zeros(size(x)); %# Initialize the image matrix to zero
%# Create the sample image data:
numBases = 200;
cellRadius = 0.75;
for iBase = 1:numBases
point = rand(1,2).*(maxRange - minRange) + minRange;
index = ((x - point(1)).^2 + (y - point(2)).^2) <= cellRadius^2;
cellCoverage(index) = cellCoverage(index) + 1;
end
%# Create the plot:
imagesc(cellRange, cellRange, cellCoverage); %# Scaled plot of image data
axis equal; %# Make tick marks on each axis equal
set(gca, 'XLim', [minRange maxRange], ... %# Set the x axis limit
'YLim', [minRange maxRange], ... %# Set the y axis limit
'YDir', 'normal'); %# Flip the y axis direction
xlabel('X-distance (km)'); %# Add an x axis label
ylabel('Y-distance (km)'); %# Add a y axis label
colormap(jet); %# Set the colormap
colorbar; %# Display the color bar
And here's the resulting plot:
Note also that the data in the image matrix cellCoverage contains no noise and has no smoothing applied, which is why the edges appear sharper than the original image in the post (which I'm guessing is generated from real data, not "fake" sample data like I used here).
Use "image"
image(x),colormap(hsv) <- where x is a matrix of cellular intensities(x,y)
You need to get the coordinate of each station then create a circle polygon around it (with a given radius), then convert this polygon into a grid. Then you sum up these grids (matrices) on top of each other. For speed, instead of using polygons you can also define which cells will be covered by a station, like all cells within 5 rows or columns of a station get the value.
You can also apply a 2D Gaussian filter to your matrix, where only the cells containing a station have a value of 1. The bandwidth of your Gaussian kernel will be your coverage radius (range). http://www.mathworks.ch/help/toolbox/images/ref/fspecial.html

How to draw a straight across the centroid points of the barcode using best fit points Matlab

This is the processed image and I can't increase the bwareaopen() as it won't work for my other image.
Anyway I'm trying to find the shortest points in the centre points of the barcode, to get the straight line across the centre points in the barcode.
Example:
After doing a centroid command, the points in the barcode are near to each other. Therefore, I just wanted to get the shortest points(which is the barcode) and draw a straight line across.
All the points need not be join, best fit points will do.
Step 1
Step 2
Step 3
If you dont have the x,y elements Andrey uses, you can find them by segmenting the image and using a naive threshold value on the area to avoid including the number below the bar code.
I've hacked out a solution in MATLAB doing the following:
Loading the image and making it binary
Extracting all connected components using bwlabel().
Getting useful information about each of them via regionprops() [.centroid will be a good approximation to the middel point for the lines].
Thresholded out small regions (noise and numbers)
Extracted x,y coordinates
Used Andreys linear fit solution
Code:
set(0,'DefaultFigureWindowStyle','docked');
close all;clear all;clc;
Im = imread('29ekeap.jpg');
Im=rgb2gray(Im);
%%
%Make binary
temp = zeros(size(Im));
temp(Im > mean(Im(:)))=1;
Im = temp;
%Visualize
f1 = figure(1);
imagesc(Im);colormap(gray);
%Find connected components
LabelIm = bwlabel(Im);
RegionInfo = regionprops(LabelIm);
%Remove background region
RegionInfo(1) = [];
%Get average area of regions
AvgArea = mean([RegionInfo(1:end).Area]);
%Vector to keep track of likely "bar elements"
Bar = zeros(length(RegionInfo),1);
%Iterate over regions, plot centroids if area is big enough
for i=1:length(RegionInfo)
if RegionInfo(i).Area > AvgArea
hold on;
plot(RegionInfo(i).Centroid(1),RegionInfo(i).Centroid(2),'r*')
Bar(i) = 1;
end
end
%Extract x,y points for interpolation
X = [RegionInfo(Bar==1).Centroid];
X = reshape(X,2,length(X)/2);
x = X(1,:);
y = X(2,:);
%Plot line according to Andrey
p = polyfit(x,y,1);
xMin = min(x(:));
xMax = max(x(:));
xRange = xMin:0.01:xMax;
yRange = p(1).*xRange + p(2);
plot(xRange,yRange,'LineWidth',2,'Color',[0.9 0.2 0.2]);
The result is a pretty good fitted line. You should be able to extend it to the ends by using the 'p' polynomal and evaluate when you dont encounter any more '1's if needed.
Result:
If you already found the x,y of the centers, you should use polyfit function:
You will then find the polynomial coefficients of the best line. In order to draw a segment, you can take the minimal and maximal x
p = polyfit(x,y,1);
xMin = min(x(:));
xMax = max(x(:));
xRange = xMin:0.01:xMax;
yRange = p(1).*xRange + p(2);
plot(xRange,yRange);
If your ultimate goal is to generate a line perpendicular to the bars in the bar code and passing roughly through the centroids of the bars, then I have another option for you to consider...
A simple solution would be to perform a Hough transform to detect the primary orientation of lines in the bar code. Once you find the angle of the lines in the bar code, all you have to do is rotate that by 90 degrees to get the slope of a perpendicular line. The centroid of the entire bar code can then be used as an intercept for this line. Using the functions HOUGH and HOUGHPEAKS from the Image Processing Toolbox, here's the code starting with a cropped version of your image from step 1:
img = imread('bar_code.jpg'); %# Load the image
img = im2bw(img); %# Convert from RGB to BW
[H, theta, rho] = hough(img); %# Perform the Hough transform
peak = houghpeaks(H); %# Find the peak pt in the Hough transform
barAngle = theta(peak(2)); %# Find the angle of the bars
slope = -tan(pi*(barAngle + 90)/180); %# Compute the perpendicular line slope
[y, x] = find(img); %# Find the coordinates of all the white image points
xMean = mean(x); %# Find the x centroid of the bar code
yMean = mean(y); %# Find the y centroid of the bar code
xLine = 1:size(img,2); %# X points of perpendicular line
yLine = slope.*(xLine - xMean) + yMean; %# Y points of perpendicular line
imshow(img); %# Plot bar code image
hold on; %# Add to the plot
plot(xMean, yMean, 'r*'); %# Plot the bar code centroid
plot(xLine, yLine, 'r'); %# Plot the perpendicular line
And here's the resulting image: