MATLAB convert graythresh output into actual intensity - matlab

I am trying to find the threshold of a 3D image that is 258 x 318 x 801 double. I first reshaped the image into 1D array and then used graythresh
ROI = reshape(postImg,[],1);
thresh = graythresh(ROI);
But I was trying to find the actually intensity threshold instead of a value between 0 and 1. Is there a way to convert this other than using multithresh?

From MATLAB documentation:
The graythresh function converts multidimensional arrays to 2-D
arrays, using reshape, and ignores any nonzero imaginary part of I.
So, your reshape is probably redundant. I think this would do:
thresh = graythresh(postImg); % postIm can be 3D
BinIm = imbinarize(postIm,thresh); % creates a binary mask of your image

Related

MATLAB 3D matrix, max in different directions + rotation using MIP

I have a 3D image called img, let's say it is a 291x287x801 int16 array. I am using the MIP (Maximum intensity projection) to find the image with the maximum intensity in different directions. I know that I could use max to get the MIP:
MIPimg=max(img,[],3);
imagesc(MIPimg);
However, this is not giving me the right direction. I think it is along the z-direction, but what should I do if I want to find the MIP along the y or x direction?
I did try to change that 3 which indicates dimension to 1 or 2, but MATLAB tells me
Error using image
Color data must be an m-by-n-by-3 or m-by-n matrix.
when calling imagesc(MIPimg).
I also tried MIPimg=max(img,[ ],[2 3]); but that didn't help.
Your problem is that imagesc expects either a 2D array as input, or a 3D array where the 3rd dimension has exactly 3 values (this is the way MATLAB represents an RGB image). When you do max(img,[],1), you get an 1x287x801 array back, which has 801 elements along the 3rd dimension, not 3 as MATLAB expects.
What you need to do for display is to convert this 1x287x801 array into an 287x801 array. The function squeeze does this (it removes all dimensions with size 1):
MIPimg = squeeze(max(img,[],1));
I cannot reproduce your problem:
% create random 3D-unit8-matrix (to mimic an image)
img = uint8(randi(255,10,12,3)); % 10x12x3 matrix
% maximum over all rows (direction 1) of each of the 3 10x12 matrices => returns 3 1x12 arrays
[val,idx] = max(img,[],1); % default direction
% maximum over all columns (direction 2) of each of the 3 10x12 matrices => returns 3 10x1 vectors
[val,idx] = max(img,[],2);
% maximum over all slices (direction 3) of each of the 10x12 1x3 "depth" arrays => returns a 10x12 matrix
[val,idx] = max(img,[],3);
overall maximum
max(max(max(img))) % no useful information about the position
position of maximum:
[val_slc,idx_slc] = max(img,[],3); % I can better think in 2D
[val_row,idx_row] = max(val_slc);
[val_col,idx_col] = max(val_row);
idx_max = [idx_row(idx_col),idx_col,idx_slc(idx_row(idx_col),idx_col)];
check
assert( max(max(max(img))) == img(idx_max(1),idx_max(2),idx_max(3)) )

Wrong dimensions when normalizing an image

I am getting some error in this code section
X=imread ('Lighthouse.jpg'); %reads picture as int8 matrix
figure, imagesc(X), colormap gray, title('original picture'), % display picture
filter=[-1 0 1; -2 0 2; -1 0 1]; % builds Sobel filter matrix
filter=single(filter); %convert double to single
x=single(X); % convert int8 to single
x=x/max(max(x)); %normalisation to [0,1]
The error I get:
Error using /
Inputs must be 2-D, or at least one input must be scalar.
To compute elementwise RDIVIDE, use RDIVIDE (./) instead.
Error in sobel (line 10)
x=x/max(max(x)); %normalisation to [0,1]
Also when I am using ./ as suggested, I get new error:
Array dimensions must match for binary array op.
Error in sobel (line 10)
x=x./max(max(x)); %normalisation to [0,1]
I am doing something wrong in the normalization step.
How do I resolve this issue?
Why do you call max twice. If I run the code with
x=x/max(x(:))
I do not get an error. This runs the matrix in 1D.
Whilst Caduceus' answer is correct; it normalises over all three colours in one go. What's probably better for your case is rgb2gray, to get a single colour channel and then normalise that instead (using x/max(x(:))).
X=imread ('lighthouse.png'); %reads picture as int8 matrix
filter=[-1 0 1; -2 0 2; -1 0 1]; % builds Sobel filter matrix
filter=single(filter); %convert double to single
x = single(rgb2gray(X)); % rgb2gray gives a uint8, you want single
% x=x/max(x(:)); %normalisation to [0,1] , not needed here as x can directly be used
% for Sobel purposes as it's a grey scale image.
figure;
subplot(1,2,1)
imagesc(X)
colormap(gray)
title('original picture'), % display picture
subplot(1,2,2)
imagesc(x)
colormap(gray)
title 'Grey scale'
The reason for the first error is is that max gives a column-wise maximum, and that this is a 3D matrix. max(max()) thus gives a 1D one, instead of the desired scalar.
Then the second error occurs because max(max()) gives an array, which doesn't have the same amount of entries as the full matrix (obviously).
Basically if size(x) = [row, column channels], size(max(x)) = [row channels]
and size(max(max(x)) = [row]. Using the colon operator actually makes the entire 3D matrix a single column vector, and max(x(:)) thus gives a single value, which is the maximum across all rows, columns and channels.
When I run your code the error message says "Use RDIVIDE (./)".
implement it like this:
x=x./max(max(x));
This divides each RGB layer by its maximum. You may have to replicate the max values (I guess this depends on matlab version), use this line instead
x=x./repmat(max(max(x)),size(X,1),size(X,2),1);

Histogram equalization for non-images in MATLAB

I have a vector of values and I want to change the values somehow that its histogram is closer to the uniform distribution using MATLAB. I am aware of histeq in MATLAB that takes an image as input and assumes the densities are in 0-255 range. I am looking for a more general version of histeq.
You are looking to do a full scale contrast stretch, correct? If so this function will work. You can change K to be the largest value in your vector if you are not using 8 bit integers.
function [result] = myfscs(image)
K=255;
A= min(image(:));
B= max(image(:));
P=K/(B-A);
L=A*K/(B-A);
J = (P .* image - L);
result = uint8(J); % doesn't have to be a uint8 returned

2D convolution of slices of 3D matrix

I'm trying to do a bunch of rolling sums over matrices in MATLAB. In order to avoid loops I've used repmat to layer my 2D matrices into a 3D structure. However, now the fast convolution function conv2 can no longer be used for the accumulator. However, the N-dimensional convolution function (convn) is not what I'm looking for either as it literally convolves all 3 dimensions. I want something that will do a 2D convolution on each slice and return a 3D matrix.
Tiling the matrices in 2D instead of layering them in 3D won't work because it will corrupt the convolution edge cases. I could pad with zeros in between but then it starts getting kind of messy.
In other words, without a for-loop, how can I perform the following:
A = ones(5,5,5);
B = zeros(size(A));
for i = 1 : size(A, 3)
B(:,:,i) = conv2(A(:,:,i), ones(2), 'same');
end
Thanks in advance for the help!
convn will work with an n-dimensional matrix and a 2-dimensional filter. Simply:
A = ones(5,5,5);
B = convn(A, ones(2), 'same');
You can use some padding with zeros and reshaping like so -
%// Store size parameters
[m,n,r] = size(A)
[m1,n1] = size(kernel)
%// Create a zeros padded version of the input array. We need to pad zeros at the end
%// rows and columns to replicate the convolutionoperation around those boundaries
Ap = zeros(m+m1-1,n+n1-1,r);
Ap(1:m,1:n,:) = A;
%// Reshape the padded version into a 3D array and apply conv2 on it and
%// reshape back to the original 3D array size
B_vect = reshape(conv2(reshape(Ap,size(Ap,1),[]),kernel,'same'),size(Ap))
%// Get rid of the padded rows and columns for the final output
B_vect = B_vect(1:m,1:n,:);
The basic idea is to reshape the input 3D array into a 2D array and then apply the 2D convolution on it. Extra step is needed with padding so as to have the same behavior as you would see with conv2 around the boundaries.

matlab image processing 3d

i have 100 b&w image of smthing.the probllem is i want to scan each image in 0&1 formatin mby n format and then place each image to one over one and again scan and save them in mbynby100 form.
how i do this and from where i should start
_jaysean
Your question is vague and hard to understand, but my guess is that you want to take 100 M-by-N grayscale intensity images, threshold them to create logical matrices (i.e. containing zeroes and ones), then put them together into one M-by-N-by-100 matrix. You can do the thresholding by simply picking a threshold value yourself, like 0.5, and applying it to an image A as follows:
B = A > 0.5;
The matrix B will now be an M-by-N logical matrix with ones where A is greater than 0.5 and zeroes where A is less than or equal to 0.5.
If you have the Image Processing Toolbox, you could instead use the function GRAYTHRESH to pick a threshold and the function IM2BW to apply it:
B = im2bw(A,graythresh(A));
Once you do this, you can easily put the images into an M-by-N-by-100 logical matrix. Here's an example of how you could do this in a loop, assuming the variables M and N are defined:
allImages = false(M,N,100); %# Initialize the matrix to store all the images
for k = 1:100
%# Here, you would load your image into variable A
allImages(:,:,k) = im2bw(A,graythresh(A)); %# Threshold A and add it to
%# the matrix allImages
end