Removing all full 0 rows in an 3d matrix in matlab - matlab

I have a large image matrix 125x200x3, the image has many large areas of black so there are many rows of all 0's. I want to remove all these black areas completely. I know that I should be using all(m==0,3) but it seems like I don't quite understand how to use it with 3d matrix.
m(all(m==0,3),:,:)=[]
exceeds matrix...
Any help is appreciated!

If you want to remove rows containing all black, do this:
m(all(all(m == 0,3),2),:,:) = [];
The inner call to ALL (what you were doing) will give you a 125-by-200 logical matrix with ones for every black pixel. The outer call to ALL operates across dimension 2 (the columns), giving you a logical vector with ones for rows that contain all black. This is what you then use as your index to remove rows.

Related

How do I group the pairs of pixels on MATLAB

I have an image that was read in using the imread function. My goal is to collect pairs of pixels in an image in MATLAB. Specifically, I have read a paper, and I am trying to recreate the following scenario:
First, the original image is grouped into pairs of pixel values. A pair consists of two neighboring pixel values or two with a small difference value. The pairing could be done horizontally by pairing the pixels on the same row and consecutive columns, or vertically, or by a key-based specific pattern. The pairing could be through all pixels of the image or just a portion of it.
I am looking to recreate the horizontal pairing scenario. I'm not quite sure how I would do this in MATLAB.
Assuming your image is grayscale, we can easily generate a 2D grid of co-ordinates using ndgrid. We can use these to create one grid, then shift the horizontal co-ordinates to the right to make another grid and then use sub2ind to convert the 2D grid into linear indices. We can finally use these linear indices to create our pixel pairings that you have described in your comments (you should really add that to your post BTW). What's important is that you need to skip over every other column in a row to ensure unique pixel pairings.
I'm also going to assume that your image is grayscale. If we go to colour, this will be slightly more complicated, and I'll leave that to you as a learning exercise. Therefore, assuming your image was read in through imread and is stored in im, do something like this:
[rows,cols] = size(im);
[X,Y] = ndgrid(1:rows,1:2:cols);
ind = sub2ind(size(im), X, Y);
ind_shift = sub2ind(size(im), X, Y+1);
pixels1 = im(ind);
pixels2 = im(ind_shift);
pixels = [pixels1(:) pixels2(:)];
pixels will be a 2D array, where each row gives you the pixel intensities of a particular pairing in the image. Bear in mind that I processed each row independently. As such, as soon as we are done with one row, we simply move on to the next row and continue the procedure. This also assumes that your image has an even number of columns. Should it not, you have a decision to make. You need to either pad the image with one column at the end, and this column can be anything you want, or you can remove this column from the image before processing. If you want to fill in this column, you can either make it all zeroes, or perhaps replicate the last column and place this beside the last column in the original image. Therefore, an appropriate pre-processing step may look something like this:
if mod(cols,2) ~= 0
im = im(:,1:end-1);
end
The above code simply removes the last column in the image if the number of columns is odd. Once you run through this code, you can run the first bit of code that I had above.
Good luck!

Image Pyramids - Dealing with Arbitrary Dimensions

Looking at the Image Pyramids tutorial I see the following note:
Notice that it is important that the input image can be divided by a factor of two (in both dimensions). Otherwise, an error will be shown.
I was wondering, How can Image Pyramid can be built for arbitrary image size and keep the "Reproduction" exact (Up to round off errors).
Taking image size of 101 x 101, After the first "Downsample" step using 1:2:101 an image size of 51 x 51 is yielded.
Yet after another iteration 26 x 26 image is yielded, so how can we handle both odd and even sizes.
I'd be happy for a MATLAB code dealing with the "Upsample" / "Downsample" procedure for any size.
I have seen some techniques where they resize the dimensions of the original image to be even, before they subsample the image. This odd and even stuff is unfortunately unavoidable as you have already seen, so you'd have to do some work by yourself before you pass it to an image decomposition routine. That way there is no ambiguity when constructing your image pyramid. When you're done, you can crop out those portions of the original image that you don't want. Another technique would be to eliminate the row and column to ensure that they're both even as well.
As such, all you'd have to do is extend your image's dimensions to ensure that each dimension is even. In other words, you'd do something like this:
im = imread('...'); %// Place image here
rows = size(im,1);
cols = size(im,2);
imResize = imresize(im, [rows + mod(rows,2), cols + mod(cols,2)], 'bilinear');
This basically reads in an image and the dimensions (rows and columns). After, it resizes the image to ensure that the dimensions (rows and columns) are even. This is done by checking to see if the values are odd by using mod. If any of the dimensions are odd, the output would be 1 and you would just tack this on as the output dimensions.
Also, you can simply crop out the last row or column if they're odd too by doing:
im = imread('...'); % // Place image here
rows = size(im,1);
cols = size(im,2);
imResize = im(1:rows-mod(rows,2), 1:cols-mod(cols,2), :);
The mod here is used in the same way to crop out what you don't need. If any of the dimensions are odd, simply subtract 1 so that we eliminate either the last row or last column if needed.
As CST-Link has already stated, upsampling from an image that has odd dimensions already would be impossible to reconstruct the original image dimensions as that precision in order to get those original rows and columns back if they were odd were already lost.
For downsampling the better approach would be to delete the last row & column from the image, thus a 101×101 generates 50×50. Though it may be a matter of taste, I think is better to ignore real information than to introduce bogus information.
For upsampling, I'm afraid what you ask is impossible. Let's say you have a 200×200 pixel image; can you tell from its size that is was downsampled from a 400×400 pixel image, or from 401×401 pixel image? Both would give the same result.

crop an image into several rectangles

I need to automatically process grayscale images like this and crop them into rectangular tiles. I used contour() to find the edges but how can I crop the image using the result of contour ?
Thanks a lot !
Assuming your image is already double grayscale (otherwise use im2double or rgb2gray), you can create a simple binary mask using:
IM %your image
M=IM>.5
Which means the mask contains a true for all values larger than .5. To select these pixels, use:
IM(M)
To select the opposite set, use:
IM(~M)
I think the basic algorithm would go somewhat like this:
1) recognize all horizontal lines
2) recognize all vertical lines
3) create a grid using all the lines from (1) and (2) - this will create more rectangles than you ultimately want, but each rectangle will be a single color
4) combine rectangles that are the same color and adjacent in one direction
5) combine the results of (4) in the other direction, possibly splitting some of the earlier combinations to come up with more a more optimal solution (e.g. in your example the two white rectangles in the first row and the three in the second row could be combined into a group of 2x2 rectangles by splitting the three into 1+2, giving you a 2x2 and a 1x1 rectangle, rather than a 2x1 and a 3x1).

in matlab, find 3D neighbourhood

I have a volume (3D matrix) that has undergone a segmentation process. Most of the volume consist of NaNs (or zeros), except regions that have passed some criteria (see picture). I need to know how large each remaining segment is in number of voxels and how is their distribution on the 2D planes (xy, xz, yz). Is there anything in matlab that can help me do this in an efficient way rather than direct search? The volume can be rather large. For ex. in the attached picture there is one segment in yellowish/brownish colour of 7 voxels and extends more vertically than in xy.
Thanks in advance.
The most convenient solution is to use REGIONPROPS. In your example:
stats = regionprops(image, 'area', 'centroid')
For every feature, there is an entry in the structure stats with the area (i.e. # of voxels) and the centroid.
I think that what you are looking for is called bwlabeln. It allows you to find blobs in 3D space, just like bwlabel does in 2D. Afterwards, you can use regionprops to find out the properties of the data.
Taken directly from help:
bwlabeln Label connected components in binary image.
L = bwlabeln(BW) returns a label matrix, L, containing labels for the
connected components in BW. BW can have any dimension; L is the same
size as BW. The elements of L are integer values greater than or equal
to 0. The pixels labeled 0 are the background. The pixels labeled 1
make up one object, the pixels labeled 2 make up a second object, and
so on. The default connectivity is 8 for two dimensions, 26 for three
dimensions, and CONNDEF(NDIMS(BW),'maximal') for higher dimensions.

Inpainting pixels between regions with nearest color in MATLAB

Is there an efficient way to fill in pixels with a value of zero between pixels with non-zero values with the nearest non-zero value, while leaving the rest of pixels at zero untouched?
To clarify, I am looking to inpaint those pixels whose closest distance to a non-zero pixel is lower than a given value (e.g. 4 pixels).
The image is initially represented as a matrix of uint32 integers.
In the example above, all the thin cracks between the colored regions should be filled with the surrounding color, while large black regions should remain the same (i.e. the routine should inpaint the pixels between the colored regions).
I imagine there is a way to do this via interpolation. In either case, I am looking for a relatively efficient solution.
Given an input matrix A:
b = imclose(A==0,ones(3,3)) %only the big zero regions
c = imdilate(A,ones(3,3)) %inpainting all neighboring pixels
d = zeros(size(A));
d(b==0) = c(b==0); %copy the inpainting only in places where there are no big regions
I haven't tested it, so there may be some problems with the code. (if you made changes to the code to make it work please edit my answer)