Two dimensional array median filtering - c

I'm trying to write code that implements median filtering on a two-dimensional array.
Here's an image to illustrate:
The program starts at the beginning of the array. The maximum array size is 100. I know that I can use an array like:
int a[100][100];
to store the input, and that I can iterate over a part of this array using two for loops like this:
for(i=0;i<size_filter;i++)
for(j=0;j<size_filter;j++)
temp[i][j]=a[i][j] // not so sure
But how can I make this code loop over the neighbors of every element in the array, calculate their median, and replace the center element with the median?
For some examples of what I'm trying to do, let's say that the input is a 5x5 matrix, so the input size is 5. And I want to run a 3x3 median filter on it, i.e. each element should be replaced by the median of the 3x3 elements surrounding it.
The program starts at the corner index (0,0). For this index, it scans the 3x3 region surrounding it (of which only four indexes actually lie within the input array), which contains the values 0, 0, 1, and 0. The median of these values is 0, so that's what the code should output for this array index.
In the picture below, the number in bold italics is the center cell, and the plain bold numbers are its neighbors within the 3x3 region surrounding it:
0 0 0 0 0
1 0 0 1 0
1 1 0 0 0
0 1 1 0 0
0 0 0 0 0
Here's another example, this time with the center index (0,1):
0 0 0 0 0
1 0 0 1 0
1 1 0 0 0
0 1 1 0 0
0 0 0 0 0
This time, the elements in the 3x3 region (excluding those outside the input array) have the values 0, 0, 0, 1, 0, and 0, and again, their median is therefore 0.
Here's yet another example, this time from the middle of the input, at center index (3,2):
0 0 0 0 0
1 0 0 1 0
1 1 0 0 0
0 1 1 0 0
0 0 0 0 0
This time, the elements within the 3x3 region have the values 1, 0, 0, 1, 1, 0, 0, 1, and 1, and their median in therefore 1.
Final example:
<size of array><size filter> <data>
8
3
0 0 0 0 0 0 0 0
0 5 0 0 6 0 0 0
0 0 0 0 0 7 0 0
0 0 0 0 5 0 0 0
0 0 0 5 6 0 0 0
0 0 8 5 5 0 0 0
0 0 0 7 0 0 9 0
0 0 0 0 0 0 0 0
Output:
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 5 5 0 0 0
0 0 0 5 5 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

It looks like you're trying to implement a two-dimensional median filter. The straightforward way to implement such a filter is to have four nested loops: two outer loops over the x and y coordinates of the whole image, and two inner loops over the neighborhood of the center pixel.
It's perhaps easier to describe this in code than in text, so here's some Python-esque pseudocode to illustrate:
# assumptions:
# * image is a height x width array containing source pixel values
# * filtered is a height x width array to store result pixel values in
# * size is an odd number giving the diameter of the filter region
radius = (size - 1) / 2 # size = 3 -> radius = 1
for y from 0 to height-1:
top = max(y - radius, 0)
bottom = min(y + radius, height-1)
for x from 0 to width-1:
left = max(x - radius, 0)
right = min(x + radius, width-1)
values = new list
for v from top to bottom:
for u from left to right:
add image[v][u] to values
filtered[y][x] = median(values)
Translating this code into C is left as an exercise.
It's also possible to optimize this code by noting that the neighborhoods of adjacent array cells overlap significantly, so that the values of those neighboring cells can be reused across successive iterations of the outer loops. Since the performance of this algorithm on modern CPUs is essentially limited by RAM access latency, such reuse can provide a significant speedup, especially for large filter sizes.

this:
for(i=0;i<size_filter;i++)
for(j=0;j<size_filter;j++)
temp[i][j]=a[i][j];
is a good starting point.
You just iterating over every pixel of your input array, determine the median of the neighborhood and write it to an output array.
So instead of temp[i][j]=a[i][j]; you need some WhatEverType calcMedianAt(const WhatEverType a[100][100], int r, int c, int size); function.
So you can call temp[i][j]=calcMedianAt(a, i,j, 3);
the function itself has to extract the value to a list (do proper border handling) and find the median in that list (for example by calling some median function WhatEverType calcMedian(const WhatEverType* data, int len); and return it.

Related

How to copy and paste a small matrix into a bigger matrix without for-loop

For example, we have a small matrix
B = [5 2,
3 4]
and the bigger one
A = [1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1]
Now I want paste B into A so that A looks like
A = [1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 5 2
0 0 0 3 4]
That means the values of A of the bottom right has been replaced. I would like to do this without using a for-loop. How is that possible?
PS:
A is always an eye(n) matrix (n is a constant).
B is a square matrix and has a variable size but is always less or equal to A
Find the relevant row and column subscripts of A and put B there.
A(end-size(B,1)+1:end, end-size(B,2)+1:end)=B
It works even if B is not a square matrix.

Vectorisation of code for insertion of n x n matrices in a 3D array along the diagonal of a large matrix

As in my earlier question I am trying to insert small square matrices along the diagonal of a large matrix. However, these matrices are now contained in a 3D array, and have different values. As before, overlapping values are to be added, and the small matrices are only inserted where they can fit fully inside the large matrix. The step dimension will always be equal to 1.
I have achieved an answer through the use of for-loops, but am attempting to vectorise this code for efficiency. How would I do this? The current, unvectorised code is shown below.
function M = TestDiagonal2()
N = 10;
n = 2;
maxRand = 3;
deepMiniM = randi(maxRand,n,n,N+1-n);
M = zeros(N);
for i = 1:N+1-n
M(i:i+n-1,i:i+n-1) = M(i:i+n-1,i:i+n-1) + deepMiniM(:,:,i);
end
end
The desired result is an NxN matrix with n+1 diagonals populated:
3 1 0 0 0 0 0 0 0 0
4 5 3 0 0 0 0 0 0 0
0 3 3 3 0 0 0 0 0 0
0 0 1 6 3 0 0 0 0 0
0 0 0 4 4 4 0 0 0 0
0 0 0 0 2 3 2 0 0 0
0 0 0 0 0 2 6 2 0 0
0 0 0 0 0 0 4 2 2 0
0 0 0 0 0 0 0 3 3 1
0 0 0 0 0 0 0 0 3 3
This makes use of implicit expansion, as well as sparse to add values at coincident indices, and (:) indexing to linearize a matrix in the usual column-major order.
ind1 = repmat((1:n).', n, 1) + (0:N-n); % column indices for the sum
ind2 = repelem((1:n).', n) + (0:N-n); % row indices for the sum
M = full(sparse(ind1(:), ind2(:), deepMiniM(:), N, N)); % sum over those indices

Array block splitting in MATLAB

Say we have a vector containing zeros interspersed blocks of ones of varying length, such as:
0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0
I would like to transform this into a 2D array as follows. Each row contains zeros only and one of the blocks. I.e. the number of rows of the 2D array would be the number of blocks at the end. The above array would transform to:
0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0
I.e the first block ends up in the first row, the second block in the second row etc.
Question
This exercise is rather trivial using loops. My question is if there is a neat way using MATLAB matrix operations, MATLAB functions and array indexing to do this?
Off the top of my head you could use bwlabel (from the Image Processing Toolbox) to assign each cluster of 1's a unique value. You could then use bsxfun to check equality between the labeled version and the unique labels which will automatically expand it out into a matrix.
a = [0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0];
b = bwlabel(a);
out = bsxfun(#eq, (1:max(b))', b);
Without the image processing toolbox you could do effectively the same thing with:
C = cumsum(~a);
out = bsxfun(#eq, unique(C(logical(a))).', C);
I tried this one
N = 100; % set array size
A = randi(2,N,1)-1; % generate random array filled with 0 and 1
d = diff([0;A]); % if 1 : starting point of block
% if -1 : end point of block
ir = find(A); % Find A==1 which will be row index
ic = cumsum(d(ir)>0); % Set col index
% assemble array
% if you want output as full array
A_new = accumarray([ir,ic],ones(size(ir)),[length(A),ic(end)]);
% if you want output as sparse array
A_new = sparse(ir,ic,ones(size(ir)),length(A),ic(end),length(ir));
% display routine
figure;spy(A,'r');hold on;spy([zeros(size(A)),A_new]);
Turns out it is faster than #Suever 's solution (Compared tic toc time with size 10000, 1000 trial). Also, if you use sparse instead of accumarray, then it is much faster
Suever_time = 7~8 sec
Accumarray = 2~3 sec
Sparse = 0.2~0.3 sec
However, his one is much shorter and neat!

Efficient way to "fill" a binary matrix to create smooth, connected zones

I have a large matrix of 1's and 0's, and am looking for a way to "fill" up areas that are locally dense with 1's.
I first did this task for an array, and counted the number of 1's within a certain radius of the element in questions. If the radius was 5, for example, and my threshold was 4, then a point that had 4 elements marked "1" within 5 elements to the left or right would be changed to a 1.
Basically I would like to generalized this to a two - dimensional array and have a resulting matrix that has "smooth" and "connected" regions of 1's and no "patchy" spots.
As an example, the matrix
1 0 0 1 0 0 0
0 0 1 0 1 0 0
0 1 0 1 0 0 0
0 0 1 1 1 0 0
would ideally be changed to
1 0 0 1 1 0 0
0 0 1 1 1 0 0
0 1 1 1 1 0 0
0 0 1 1 1 0 0
or something similar
For binary images, the morphologial operations that are implemented in MATLAB are perfect for manipulating the shape and size of connected regions. Specifically, the process of image closing is designed to fill holes in connected regions. In MATLAB, the function is imclose, which takes the image and a structuring element, similar to a filter kernel, for how neighboring pixels effect the filling of holes and gaps. A simple invocation of imclose is,
IM2 = imclose(IM,strel(ones(3)));
Larger gaps can be filled by increasing the area of the influence of of neighboring pixes, via larger structuring elements. For example, we an use a disk of radius 10 pixels:
IM2 = imclose(IM,strel('disk',10));
While, imclose supports grayscale and binary (0 and 1) images, the function bwmorph is designed for operation on binary images only but provides a generic interface to all of the morphological operations and various neat combinations of operations (e.g. 'bothat', 'tophat', etc.). The syntax for closing is simplified with bwmorph:
BW2 = bwmorph(BW,'close');
Here the structuring element is the standard ones(3).
A simple filter such as the following might do the trick:
h = [ 0 1 0
1 0 1
0 1 0];
img2=(imfilter(img,h)>2) | img;
For instance:
img =
1 0 0 1 0 0 0
0 0 1 0 1 0 0
0 1 0 1 0 0 0
0 0 1 1 1 0 0
img2 =
1 0 0 1 0 0 0
0 0 1 1 1 0 0
0 1 1 1 1 0 0
0 0 1 1 1 0 0
You can try different filters to modify the output img2.
This uses the image processing toolbox. If you don't have that, you may want to look up equivalent routines from the matlab exchange.

Gaussian elimation - Linear equation matrices, algorithm

Let's assume that we have a simple matrix 3rows x 7cols.
The matrix includes only zeros (0) and (1) like:
1 0 1 1 1 0 0
0 0 1 1 0 0 0
0 0 1 0 1 1 0
Senario:
If we know the sum of non-zeros in each row,
(in first row is 4, in second row is 2, in third row is 3.) (blue line)
additional, if we know the sum of each col (1 , 0, 3, 2, 2, 1, 0) (green line)
also if we know the sum of each diagonal from the top-left to bottom-right (1,0,1,2,3,0,1,1,0)(red lines) anti-clockwise
and finally we know the sum of each diagonal from the bottom-left to top-right (0,0,2,1,3,2,1,0,0) (yellow lines)
My question is:
With these values as input (and the lenght of matrix 3x7),
4, 2, 3
1, 0, 3, 2, 2, 1, 0
1, 0, 1, 2, 3, 0, 1, 1, 0
0, 0, 2, 1, 3, 2, 1, 0, 0
How we can draw the first matrix?
After a lot of thoughts I came to the conclusion that this is a linear equation system with 3x7 unknown values and some equations.
Right?
How can I make an algorithm in C, or whatever, to solve these equations?
Should I use a method like gausian equation?
Any help would be greatly appreciated!
Start with the first column. You know the top and bottom values (from the first values of the red & yellow lists). Subtract the sum of these two from the first in the green list, and now you have the middle value as well.
Now just work to the right.
Subtract the first column's middle value from the next value in the red list, and you have the second column's top value. Subtract that same middle value from the next value in the yellow list, and you have the second column's bottom value. Subtract the sum of these two from the next value in the green list, and now you have the middle value for the second column.
et cetera
If you're going to code this up, you can see that the first two columns are a special case, and that'll make the code ugly. I'd suggest using two "ghost" columns of all zeros to the left so that you can use a single method for determining the top, bottom, and middle values for each column.
This is also easily generalizable. You'll just have to use (#rows)-1 ghost columns.
Enjoy.
You can use singular value decomposition to compute a non zero least squares solution to a system of linear homogeneous (and non homogeneous) equations in matrix form.
For a quick overview see:
http://campar.in.tum.de/twiki/pub/Chair/TeachingWs05ComputerVision/3DCV_svd_000.pdf
You should first write out your systems as a matrix equation in the form Ax = b, where x is the 21 unknowns as a column vector, and A is the 28 x 21 matrix that forms the linear system when multiplied out. You essentially need to a compute the matrix A of linear equations, compute the singular value decomposition of A and plug the results into the equation as shown in equation 9.17
There are plenty of libraries that will compute the SVD for you in C, so you only need to formulate the matrix and perform the computations in 9.17. The most difficult part is probably understanding how it all works, with a library SVD function there is relatively little code needed.
To get you started on how to form the equation of linear systems, consider a simple 3 x 3 case.
Suppose that our system is a matrix of the form
1 0 1
0 1 0
1 0 1
We would have the following inputs to the linear system:
2 1 2 (sum of rows - row)
2 1 2 (sum of colums - col)
1 0 3 0 1 (sum of first diagonal sets - t2b)
1 0 3 0 1 (sum of second diagonal sets - b2t)
so now we create a matrix for the linear system
A a1 a2 a3 b1 b2 b3 c1 c2 c3 unknowns (x) = result (b)
sum of row 1 [ 1 1 1 0 0 0 0 0 0 ] [a1] [2]
sum of row 2 [ 0 0 0 1 1 1 0 0 0 ] [a2] [1]
sum of row 3 [ 0 0 0 0 0 0 1 1 1 ] [a3] [2]
sum of col 1 [ 1 0 0 1 0 0 1 0 0 ] [b1] [2]
sum of col 2 [ 0 1 0 0 1 0 0 1 0 ] [b2] [1]
sum of col 3 [ 0 0 1 0 0 1 0 0 1 ] [b3] [2]
sum of t2b 1 [ 1 0 0 0 0 0 0 0 0 ] [c1] [1]
sum of t2b 2 [ 0 1 0 1 0 0 0 0 0 ] [c2] [0]
sum or t2b 3 [ 0 0 1 0 1 0 1 0 0 ] [c3] [3]
sum of t2b 4 [ 0 0 0 0 0 1 0 1 0 ] [0]
sum of t2b 5 [ 0 0 0 0 0 0 0 0 1 ] [1]
sum of b2t 1 [ 0 0 0 0 0 0 1 0 0 ] [1]
sum of b2t 2 [ 0 0 0 1 0 0 0 1 0 ] [0]
sum of b2t 3 [ 1 0 0 0 1 0 0 0 1 ] [3]
sum of b2t 4 [ 0 1 0 0 0 1 0 0 0 ] [0]
sum of b2t 5 [ 0 0 1 0 0 0 0 0 0 ] [1]
When you multiply out Ax, you see that you get the linear system of equations. For example if you multiply out the first row by the unkown column, you get
a1 + a2 + a3 = 2
All you have to do is put a 1 in any of the colums that appear in the equation and 0 elsewhere.
Now all you have to do is compute the SVD of A and plug the result into equation 9.17 to compute the unknowns.
I recommend SVD because it can be computed efficiently. If you would prefer, you can augment the matrix A with the result vector b (A|b) and put A in reduced row echelon form to obtain the result.
For an array of 10x15 ones and zeros, you would be trying to find 150 unknowns and have 10+15+2*(10+15-1) = 73 equations if you ignore that the values are limited to being either one or zero. Obviously you can't create a linear system on that basis which has a unique solution.
So is that constraint enough to give a unique solution?
For a 4x4 matrix with the following sums there are two solutions:
- 1 1 1 1
| 1 1 1 1
\ 0 1 1 0 1 1 0
/ 0 1 1 0 1 1 0
0 0 1 0
1 0 0 0
0 0 0 1
0 1 0 0
0 1 0 0
0 0 0 1
1 0 0 0
0 0 1 0
So I wouldn't expect there to be a unique solution for larger matrices - the same symmetry would exist in many places:
- 1 1 0 0 1 1
| 1 1 0 0 1 1
\ 0 1 0 0 1 0 1 0 0 1 0
/ 0 1 0 0 1 0 1 0 0 1 0
0 0 0 0 1 0
1 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 1
0 1 0 0 0 0
0 1 0 0 0 0
0 0 0 0 0 1
0 0 0 0 0 0
0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 1 0
How about this as another variation
Count the amount of unknown squares each sum passes through
While there are unsolved cells
Solve all the cells which are passed through by a sum with only one unknown square
Cells are solved by simply subtracting off all the known cells from the sum
Update the amount of unknown squares each sum passes through
No boundary cases but very similar to the previous answer. This would first solve all the corners, then those adjacent to the corners, then those one step more interior from that, and so on...
Edit: Also zero out any paths that have a sum of zero, that should solve any that are solvable (I think)

Resources