Related
I am attempting to make a movie from a 3d matrix, which is made multiple 2d matrices and the third dimension is time.
I have read the following question witch is pretty much the same and I have attempted to do the same.
How to make a video from a 3d matrix in matlab
The 3d matrix I want to play is stored in a object instanced A.
a.movie; % 3D matrix
X = permute(a.movie,[1 2 4 3]); % 4D matrix
movie = immovie(X,map); % map is the colormap you want to use
implay(movie);
I would like to know why should a.movie be permuted? And what is the map referred?
How can I define 0 as blue and 100 as red?
The post you linked us to exactly answers that. immovie expects a m x n x 1 x k matrix where m and n are the rows and columns of 1 slice from your 3D matrix, and k is the number of slices. You currently have your 3D matrix set up to be m x n x k. Therefore, by permuting, you are artificially creating a 4D matrix from your 3D original matrix. Simply put, you can think of your 3D matrix as having a singleton 4D dimension: m x n x k x 1. The job of permute here is to swap the 3rd and 4th dimension - that's why you see the [1 2 4 3] vector in the permute call. The first and second dimensions represent the rows and columns, and you leave those empty.
Now that answers the permute question. The map is defined as a colour map. This maps each value in your 3D matrix to a unique colour. Basically, the colour map is a M x 3 matrix where row in this matrix corresponds to a unique colour. Each column represents a colour channel. Therefore, the first column represents the proportion of red you want, the second channel is the proportion of green and the last is the proportion of blue. Keep in mind that these colours should be normalized between [0,1].
The goal of the colour map is to take each value in your 3D matrix, and figure out which colour that value maps to. The way to do this is to use each value in your 3D matrix exactly as it is and use this to access the row of the colour map. This row gives you the colours you want. Now, I'm assuming that your values in the 3D matrix span from 0 to 100.
If you want the colours to span between blue and red. The blue colour has an exact colour of RGB = (0,0,1) assuming normalized coordinates and similarly, the red represents the exact colour of RGB = (1,0,0). Therefore, start off with RGB = (0,0,1), then start linearly increasing the red component while linearly decreasing the blue component until the red is 1 and the blue is 0.
What we can do is figure out how many unique values there are in your matrix, then we can create our colour map that way so we can ensure that each value in your matrix gets assigned to one colour. However, this will require that a.movie be redefined to ensure that we can assign a value to a colour.
Therefore, I'd create your colour map like this:
[unq,~,id] = unique(a.movie);
movie_IDs = reshape(id, size(a.movie));
M = numel(unq);
map = [linspace(1,0,M).', zeros(M,1), linspace(0,1,M).'];
Now, go ahead and use map with the above code to create your movie.
X = permute(movie_IDs,[1 2 4 3]); % 4D matrix
movie = immovie(X,map); % map is the colormap you want to use
implay(movie);
However, the colour map you're looking at is the jet colour map. Therefore, you can simply just create a jet colour map:
map = jet(M);
However, you must make sure you run through each value in a.movie and assign a unique integer to each value to ensure that there are no gaps in your data and every value gets assigned to a new value that goes up from 1 to M in order for the movie to properly access the right colour.
MATLAB has a bunch of built-in colour maps for you to use if you don't feel like designing your own colour map. http://www.mathworks.com/help/matlab/ref/colormap.html#inputarg_map - However, from what I see in your post, making the colour map is what you want to do.
I want to shift an image (represented by a 2D matrix) using the multiplication of its fft by exp(-j*2*pi*x*F), where x is the displacement. I have:
input=peaks(200);
H=fftshift(fft2(fftshift(input)));
x=19;
H=H*exp(-1i*x*2*pi*F);
IF_image=fftshift(ifft2(fftshift(H)));
imshow(IF_image)
But I'm having troubles identifying/representing the F in H[F] since my input is a 2 dimensional array. How could I do this?
The desired output will be my original image shifted in the horizontal axis (by x units) in the same frame so it would start at x+1. As an example:
If input=
1 2 3 4 5
6 7 8 9 0
and x=2, I want:
4 5 1 2 3
9 0 6 7 8
You identified the property for translation / shifting in 1D. For 2D, it's slightly different but based on the same principle. To achieve the translation in 2D, this is the translation / shift property, which is defined as:
x0,y0 would be the shift you want to introduce. As such, positive value of x0 would shift your 2D signal to the right, while a negative value would shift to the left. Similarly, a positive value of y0 would shift your 2D image downwards, while a negative value would shift upwards.
Therefore, given your Fourier Transform in 2D, you would need to add an additional term to the exponent. In addition, you must normalize by N or the size of your 2D signal. This is assuming that your 2D signal has the same number of rows and columns. If this isn't the case, then you would have to take u*x0 and you would divide by the number of columns and v*y0 would be divided by the number of rows.
Now, the reason why you're confused about F in your above code is because you aren't sure how to define this in 2D. You must define a frequency value for every point in the 2D grid. Because of your fftshift call, we would define the x and y values between -100 and 99, as your 2D signal is of size 200 x 200 and this would centre our 2D signal to be in the middle. This is actually what fftshift is doing. Similarly, ifftshift undoes the centering done by fftshift. To define these points in 2D, I use meshgrid. Once you define these points, you would take each pair of (x,y) co-ordinates, then create the complex exponential as you see in the above property.
As such, your code would have to be modified in this fashion. Bear in mind that I got rid of redundant fftshift and ifftshift calls in your original code. You would call the fft, then do fftshift to centre the spectrum. I also changed your variable input to in, as input is a function in MATLAB, and we don't want to unintentionally shadow the function with a variable.
I've also defined the x shift to be -35, and the y shift to be -50. This will mean that the resultant signal will shift to the left by 35, and up by 50.
Therefore:
in=peaks(200); %// Define input signal
H=fftshift(fft2(in)); %// Compute 2D Fourier Transform
x0=-35; %// Define shifts
y0=-50;
%// Define shift in frequency domain
[xF,yF] = meshgrid(-100:99,-100:99);
%// Perform the shift
H=H.*exp(-1i*2*pi.*(xF*x0+yF*y0)/200);
%// Find the inverse Fourier Transform
IF_image=ifft2(ifftshift(H));
%// Show the images
figure;
subplot(1,2,1);
imshow(in);
subplot(1,2,2);
imshow(real(IF_image));
Take note that I displayed the real component of the resultant image. This is due to the fact that once you take the inverse Fourier Transform, there may be some numerical imprecision and the complex part of the signal is actually quite small. We can ignore this by just using the real component of the signal.
This is the image I get:
As you can see, the image did shift properly, as verified by the property seen above. If you want to specify different shifts, you just need to change x0 and y0 to suit your tastes. In your case, you would specify y0 = 0, then x0 can be whatever you wish as you want a horizontal translation.
I'm trying to create a mozaic image in Matlab. The database consists of mostly RGB images but also some gray scale images.
I need to calculate the histograms - like in the example of the Wikipedia article about color histograms - for the RGB images and thought about using the bitshift operator in Matlab to combine the R,G and B channels.
nbins = 4;
nbits = 8;
index = bitshift(bitshift(image(:,:,1), log2(nbins)-nbits), 2*log2(nbins)) + ...
+ bitshift(bitshift(image(:,:,2), log2(nbins)-nbits), log2(nbins)) + ...
+ bitshift(image(:,:,3), log2(nbins)-nbits) + 1;
index is now a matrix of the same size as image with the index to the corresponding bin for the pixel value.
How can I sum the occurences of all unique values in this matrix to get the histogram of the RGB image?
Is there a better approach than bitshift to calculate the histogram of an RGB image?
Calculating Indices
The bitshift operator seems OK to do. Me what I would personally do is create a lookup relationship that relates RGB value to bin value. You first have to figure out how many bins in each dimension that you want. For example, let's say we wanted 8 bins in each channel. This means that we would have a total of 512 bins all together. Assuming we have 8 bits per channel, you would produce a relationship that creates an index like so:
% // Figure out where to split our bins
accessRed = floor(256 / NUM_RED_BINS);
accessGreen = floor(256 / NUM_GREEN_BINS);
accessBlue = floor(256 / NUM_BLUE_BINS);
%// Figures out where to index the histogram
redChan = floor(red / accessRed);
greenChan = floor(green / accessGreen);
blueChan = floor(blue / accessBlue);
%// Find single index
out = 1 + redChan + (NUM_RED_BINS)*greenChan + (NUM_RED_BINS*NUM_GREEN_BINS)*blueChan;
This assumes we have split our channels into red, green and blue. We also offset our indices by 1 as MATLAB indexes arrays starting at 1. This makes more sense to me, but the bitshift operator looks more efficient.
Onto your histogram question
Now, supposing you have the indices stored in index, you can use the accumarray function that will help you do that. accumarray takes in a set of locations in your array, as well as "weights" for each location. accumarray will find the corresponding locations as well as the weights and aggregate them together. In your case, you can use sum. accumarray isn't just limited to sum. You can use any operation that provides a 1-to-1 relationship. As an example, suppose we had the following variables:
index =
1
2
3
4
5
1
1
2
2
3
3
weights =
1
1
1
2
2
2
3
3
3
4
4
What accumarray will do is for each value of weights, take a look at the corresponding value in index, and accumulate this value into its corresponding slot.
As such, by doing this you would get (make sure that index and weights are column vectors):
out = accumarray(index, weights);
out =
6
7
9
2
2
If you take a look, all indices that have a value of 1, any values in weights that share the same index of 1 get summed into the first slot of out. We have three values: 1, 2 and 3. Similarly, with the index 2 we have values of 1, 3 and 3, which give us 7.
Now, to apply this to your application, given your code, your indices look like they start at 1. To calculate the histogram of your image, all we have to do is set all of the weights to 1 and use accumarray to accumulate the entries. Therefore:
%// Make sure these are column vectors
index = index(:);
weights = ones(numel(index), 1);
%// Calculate histogram
h = accumarray(index, weights);
%// You can also do:
%// h = accumarray(index, 1); - This is a special case if every value
%// in weights is the same number
accumarray's behaviour by default invokes sum. This should hopefully give you what you need. Also, should there be any indices that are missing values, (for example, suppose the index of 2 is missing from your index matrix), accumarray will conveniently place a zero in this location when you aggregate. Makes sense right?
Good luck!
I have two black and white images and I need to calculate the mutual information.
Image 1 = X
Image 2 = Y
I know that the mutual information can be defined as:
MI = entropy(X) + entropy(Y) - JointEntropy(X,Y)
MATLAB already has built-in functions to calculate the entropy but not to calculate the joint entropy. I guess the true question is: How do I calculate the joint entropy of two images?
Here is an example of the images I'd like to find the joint entropy of:
X =
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
Y =
0 0 0 0 0 0
0 0 0.38 0.82 0.38 0.04
0 0 0.32 0.82 0.68 0.17
0 0 0.04 0.14 0.11 0
0 0 0 0 0 0
To calculate the joint entropy, you need to calculate the joint histogram between two images. The joint histogram is essentially the same as a normal 1D histogram but the first dimension logs intensities for the first image and the second dimension logs intensities for the second image. This is very similar to what is commonly referred to as a co-occurrence matrix. At location (i,j) in the joint histogram, it tells you how many intensity values we have encountered that have intensity i in the first image and intensity j in the second image.
What is important is that this logs how many times we have seen this pair of intensities at the same corresponding locations. For example, if we have a joint histogram count of (7,3) = 2, this means that when we were scanning both images, when we encountered the intensity of 7, at the same corresponding location in the second image, we encountered the intensity of 3 for a total of 2 times.
Constructing a joint histogram is very simple to do.
First, create a 256 x 256 matrix (assuming your image is unsigned 8-bit integer) and initialize them to all zeroes. Also, you need to make sure that both of your images are the same size (width and height).
Once you do that, take a look at the first pixel of each image, which we will denote as the top left corner. Specifically, take a look at the intensities for the first and second image at this location. The intensity of the first image will serve as the row while the intensity of the second image will serve as the column.
Find this location in the matrix and increment this spot in the matrix by 1.
Repeat this for the rest of the locations in your image.
After you're done, divide all entries by the total number of elements in either image (remember they should be the same size). This will give us the joint probability distribution between both images.
One would be inclined to do this with for loops, but as it is commonly known, for loops are notoriously slow and should be avoided if at all possible. However, you can easily do this in MATLAB in the following way without loops. Let's assume that im1 and im2 are the first and second images you want to compare to. What we can do is convert im1 and im2 into vectors. We can then use accumarray to help us compute the joint histogram. accumarray is one of the most powerful functions in MATLAB. You can think of it as a miniature MapReduce paradigm. Simply put, each data input has a key and an associated value. The goal of accumarray is to bin all of the values that belong to the same key and do some operation on all of these values. In our case, the "key" would be the intensity values, and the values themselves are the value of 1 for every intensity value. We would then want to add up all of the values of 1 that map to the same bin, which is exactly how we'd compute a histogram. The default behaviour for accumarray is to add all of these values. Specifically, the output of accumarray would be an array where each position computes the sum of all values that mapped to that key. For example, the first position would be the summation of all values that mapped to the key of 1, the second position would be the summation of all values that mapped to the key of 2 and so on.
However, for the joint histogram, you want to figure out which values map to the same intensity pair of (i,j), and so the keys here would be a pair of 2D coordinates. As such, any intensities that have an intensity of i in the first image and j in the second image in the same spatial location shared between the two images go to the same key. Therefore in the 2D case, the output of accumarray would be a 2D matrix where each element (i,j) contains the summation of all values that mapped to key (i,j), similar to the 1D case that was mentioned previously which is exactly what we are after.
In other words:
indrow = double(im1(:)) + 1;
indcol = double(im2(:)) + 1; %// Should be the same size as indrow
jointHistogram = accumarray([indrow indcol], 1);
jointProb = jointHistogram / numel(indrow);
With accumarray, the first input are the keys and the second input are the values. A note with accumarray is that if each key has the same value, you can simply assign a constant to the second input, which is what I've done and it's 1. In general, this is an array with the same number of rows as the first input. Also, take special note of the first two lines. There will inevitably be an intensity of 0 in your image, but because MATLAB starts indexing at 1, we need to offset both arrays by 1.
Now that we have the joint histogram, it's really simple to calculate the joint entropy. It is similar to the entropy in 1D, except now we are just summing over the entire joint probability matrix. Bear in mind that it will be very likely that your joint histogram will have many 0 entries. We need to make sure that we skip those or the log2 operation will be undefined. Let's get rid of any zero entries now:
indNoZero = jointHistogram ~= 0;
jointProb1DNoZero = jointProb(indNoZero);
Take notice that I searched the joint histogram instead of the joint probability matrix. This is because the joint histogram consists of whole numbers while the joint probability matrix will lie between 0 and 1. Because of the division, I want to avoid comparing any entries in this matrix with 0 due to numerical roundoff and instability. The above will also convert our joint probability matrix into a stacked 1D vector, which is fine.
As such, the joint entropy can be calculated as:
jointEntropy = -sum(jointProb1DNoZero.*log2(jointProb1DNoZero));
If my understanding of calculating entropy for an image in MATLAB is correct, it should calculate the histogram / probability distribution over 256 bins, so you can certainly use that function here with the joint entropy that was just calculated.
What if we have floating-point data instead?
So far, we have assumed that the images that you have dealt with have intensities that are integer-valued. What if we have floating point data? accumarray assumes that you are trying to index into the output array using integers, but we can still certainly accomplish what we want with this small bump in the road. What you would do is simply assign each floating point value in both images to have a unique ID. You would thus use accumarray with these IDs instead. To facilitate this ID assigning, use unique - specifically the third output from the function. You would take each of the images, put them into unique and make these the indices to be input into accumarray. In other words, do this instead:
[~,~,indrow] = unique(im1(:)); %// Change here
[~,~,indcol] = unique(im2(:)); %// Change here
%// Same code
jointHistogram = accumarray([indrow indcol], 1);
jointProb = jointHistogram / numel(indrow);
indNoZero = jointHistogram ~= 0;
jointProb1DNoZero = jointProb(indNoZero);
jointEntropy = -sum(jointProb1DNoZero.*log2(jointProb1DNoZero));
Note that with indrow and indcol, we are directly assigning the third output of unique to these variables and then using the same joint entropy code that we computed earlier. We also don't have to offset the variables by 1 as we did previously because unique will assign IDs starting at 1.
Aside
You can actually calculate the histograms or probability distributions for each image individually using the joint probability matrix. If you wanted to calculate the histograms / probability distributions for the first image, you would simply accumulate all of the columns for each row. To do it for the second image, you would simply accumulate all of the rows for each column. As such, you can do:
histogramImage1 = sum(jointHistogram, 1);
histogramImage2 = sum(jointHistogram, 2);
After, you can calculate the entropy of both of these by yourself. To double check, make sure you turn both of these into PDFs, then compute the entropy using the standard equation (like above).
How do I finally compute Mutual Information?
To finally compute Mutual Information, you're going to need the entropy of the two images. You can use MATLAB's built-in entropy function, but this assumes that there are 256 unique levels. You probably want to apply this for the case of there being N distinct levels instead of 256, and so you can use what we did above with the joint histogram, then computing the histograms for each image in the aside code above, and then computing the entropy for each image. You would simply repeat the entropy calculation that was used jointly, but apply it to each image individually:
%// Find non-zero elements for first image's histogram
indNoZero = histogramImage1 ~= 0;
%// Extract them out and get the probabilities
prob1NoZero = histogramImage1(indNoZero);
prob1NoZero = prob1NoZero / sum(prob1NoZero);
%// Compute the entropy
entropy1 = -sum(prob1NoZero.*log2(prob1NoZero));
%// Repeat for the second image
indNoZero = histogramImage2 ~= 0;
prob2NoZero = histogramImage2(indNoZero);
prob2NoZero = prob2NoZero / sum(prob2NoZero);
entropy2 = -sum(prob2NoZero.*log2(prob2NoZero));
%// Now compute mutual information
mutualInformation = entropy1 + entropy2 - jointEntropy;
Hope this helps!
Context
I'm creating a labyrinth generator (actually, more like a map generator) based on "chambers" want to connect to each other. I read these from text files and then convert to an internal format composed with LocatedNodes which are basically a node type and x-y coordinates. I regrouped them in NodeList where I put all functions to rotate/mirror/normalize these nodes.
A Map is a aggregation of chambers so it has a single NodeList containing these.
To sum up the hierarchy : Map <- NodeList <- LocatedNodes
Problem
To connect chambers, I compare the shapes of an opening of the 1st map and the shape of the area around the opening of the 2nd map. Let's begin with a example:
>>> print map6.nodes # nodes of the entire map
1 1
0 5 0 2
o⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
0 |#############
|#...........#
|#...........#
|#...........#
|#............
5 |#............
|#........
|#........
|#........
|#........
10 |#########
>>> print map6.openings() # just the nodes placed on the opening
1
8 2
o⎯⎯⎯⎯⎯
4 | .
|.....
|.
|.
|.
9 |.
>>> print map7.nodes # map we want to connect with the other
1 1
0 5 0 4
o⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
0 | ###########
| ..........#
| ..........#
|..............#
|..............#
5 |..............#
|..............#
7 |###############
>>> print map7.joinable_on() # area around the map7.openings()
-
1 3
o⎯⎯⎯⎯⎯
1 | .
|.....
|.
|.
|.
6 |.
>>> map7.joinable_on().normalized(x=0,y=0) == map6.openings().normalized(x=0, y=0)
True
It is not hard to compare map6.openings() et map7.joinable_on() because when the positions of the nodes are normalized, I can do a one-to-one comparison.
BUT, the hard part comes now:
I want to be able to compare these shapes independently of their position, rotation or mirroring.
What I tried
When searching for ideas, I found the pairing function (this function links two int to a unique int, so each coordinate x-y becomes a unique int). With that I could identify a shape uniquely by applying recursively this function on (x,y) coordinates. First problem, the unique int is really unique, so even with a 90° rotation the int changes, so I can't compare two shapes this way.
Question
Do you have an idea or a solution to help me get a unique id of a shape that doesn't change when this shape get mirrored, translated or rotated ?
There is a general scheme for creating ids that don't change when a shape is mirrored, translated, or rotated. Start with an id that does care about mirroring, translating, and rotating. When you get a shape, consider every possible mirroring, rotation, and translation, and compute an id for each case. This gives you a large number of ids, so just pick the numerically smallest one.
For the case of translation, another idea might be more practical - before (and/or after) doing all this, translate the shape so that its centre of gravity is at the origin, or as near to the origin as you can make it.
Seems like you should have your list of shapes with no translation, rotation, or mirroring. Then, to create a map you index a shape and provide a transformation matrix. So your input file would look something like:
Shapes
shape1
shape2
shape3
etc.
Those shapes all are built at the origin and have no translation.
Then, your map becomes:
Map
0 (index to shape1), transformation matrix (scaling, rotation, translation, mirroring)
2 (index to shape3), transformation matrix
0 (index to shape1), different transformation matrix
Then all you have to do to determine if two shapes in the map are the same is compare their indexes.