How to optimize conditional statement in for loop over image? - arrays

I'm wondering if there's an indexable way of doing the following code on Octave, as it's iterative and thus really slow compared to working with indexation.
for i = [1:size(A, 1)]
for j = [1:size(A, 2)]
if (max(A(i, j, :)) == 0)
A(i, j, :) = B(i, j, :);
endif
endfor
endfor
A and B are two RGB images that overlaps and I want A(i,j) to have B(i,j) value if A(i,j) is 0 on all of the three channels. It is very slow in this form but I'm not experimented enough with this language to vectorize it.

Your code can be vectorized as follows:
I = max(A,[],3) == 0;
I = repmat(I,1,1,3);
A(I) = B(I);
The first line is a direct copy of your max conditional statement within the loop, but vectorized across all of A. This returns a 2D array, which we cannot directly use to index into the 3D arrays A and B, so we apply repmat to replicate it along the 3rd dimension (the 3 here is the number of repetitions, we're assuming A and B are RGB images with 3 elements along the 3rd dimension). Finally, an indexed assignment copies the relevant values over from B to A.
To generalize this to any array size, replace the "3" in the repmat statement with size(A,3).

Not adding much here, but perhaps this will give you a better understanding so worth adding another solution.
% example data
A = randi( 255, [2,4,3] ); A(2,2,:) = [0,0,0];
B = randi( 255, [2,4,3] );
% Logical array with size [Dim1, Dim2], such that Dim3 is 'squashed' into a
% single logical value at each position, indicating whether the third dimension
% at that position does 'not' have 'any' true (i.e. nonzero) values.
I = ~any(A, 3);
% Use this to index A and B for assignment.
A([I,I,I]) = B([I,I,I])
This approach may be more efficient than the repmat one, which is a slightly more expensive operation, but may be slightly less obvious to understand why it works. But. Understanding how this works teaches you something about matlab/octave, so it's a nice learning point.
Matlab and Octave store arrays in column major order (as opposed to, say, Python). This is also the reason that doing A(:) will return A as a vector, constructed in a column-by-column basis. It is also the reason that you can index a 3-dimensional array using a single index (called a "linear index"), which will correspond to the element you reach when you count that number of elements going down columns.
When performing logical indexing, matlab/octave effectively takes a logical vector, matches each linear index of that vector to the equivalent linear index of A and decides whether to return it or not, based on whether the boolean value of the logical index at that linear index is true or false. If you provide a logical array I that is of a smaller size than A, the indexing will simply stop at the last linear index of I. Specifically, note that the shape of I is irrelevant, since it will be interpreted in a linear indexing manner anyway.
In other words, logical indexing with I is the same as logical indexing with I(:), and logical indexing with [I,I,I] is the same as logical indexing with [ I(:); I(:); I(:) ].
And if I is of size A(:,:,1) then [I,I,I] is of size A(:,:,:), such that in a linear indexing sense it can be used as a valid logical index matching each linear index of I to the equivalent linear index of A.

The max() function can take a single matrix and return the maximum value along a dimension
There's also the all() function that tells you if all values along a dimension are nonzero, and the any() function that tells you if any of the values along a dimension are nonzero
A = reshape(1:75, 5, 5, 3)
A(2, 3, :) = 0;
B = ones(size(A)) * 1000
use_pixel_from_A = any(A, 3)
use_pixel_from_B = ~use_pixel_from_A
Now for each element of the 3rd axis, you know which pixels to take from A and which to take from B. Since our use_pixel... matrices contain 0 and 1, we can element-wise multiply them to A and B to filter out elements of A and B as required.
C = zeros(size(A));
for kk = 1:size(A, 3)
C(:, :, kk) = A(:, :, kk) .* use_pixel_from_A + B(:, :, kk) .* use_pixel_from_B
end

Related

Better algorithm to construct a matrix using vcat() or hcat() in a loop in Julia?

To use vcat(a,b) and hcat(a,b), one must match the number of columns or number of rows in the matrices a and b.
When constructing a matrix using vact(a, b) or hcat(a, b) in a loop, one needs an initial matrix a (like a starting statement). Although all the sub-matrices are created in the same manner, I might need to construct this initial matrix a outside of the loop.
For example, if the loop condition is for i in 1:w, then I would need to pre-create a using i = 1, then start the loop with for i in 2:w.
If there is a nested loop, then my method is very awkward. I have thought the following methods, but it seems they don't really work:
Use a dummy a, delete a after the loop. From this question, we cannot delete row in a matrix. If we use another variable to refer to the useful rows and columns, we might waste some memory allocation.
Use reshape() to make an empty dummy a. It works for 1 dimension, but not multiple dimensions.
julia> a = reshape([], 2, 0)
2×0 Array{Any,2}
julia> b = hcat(a, [3, 3])
2×1 Array{Any,2}:
3
3
julia> a = reshape([], 2, 2)
ERROR: DimensionMismatch("new dimensions (2,2) must be consistent with array size 0")
in reshape(::Array{Any,1}, ::Tuple{Int64,Int64}) at ./array.jl:113
in reshape(::Array{Any,1}, ::Int64, ::Int64, ::Vararg{Int64,N}) at ./reshapedarray.jl:39
So my question is how to work around with vcat() and hcat() in a loop?
Edit:
Here is the problem I got stuck in:
There are many gray pixel images. Each one is represented as a 20 by 20 Float64 array. One function foo(n) randomly picks n of those matrices, and combine them to a big square.
If n has integer square root, then foo(n) returns a sqrt(n) * 20 by sqrt(n) * 20 matrix.
If n does not have integer square root, then foo(n) returns a ceil(sqrt(n)) * 20 by ceil(sqrt(n)) * 20 matrix. On the last row of the big square image (a row of 20 by 20 matrices), foo(n) fills ceil(sqrt(n)) ^ 2 - n extra black images (each one is represented as zeros(20,20)).
My current algorithm for foo(n) is to use a nested loop. In the inner loop, hcat() builds a layer (consisting ceil(sqrt(n)) images). In the outer loop, vcat() combines those layers.
Then dealing with hcat() and vcat() in a loop becomes complicated.
So would:
pickimage() = randn(20,20)
n = 16
m = ceil(Int, sqrt(n))
out = Matrix{Float64}(20m, 20m)
k = 0
for i in (1:m)-1
for j in (1:m)-1
out[20i + (1:20), 20j + (1:20)] .= ((k += 1) <= n) ? pickimage() : zeros(20,20)
end
end
be a relevant solution?

Find all possible distances from two arrays

Given two sorted array A and B length N. Each elements may contain natural number less than M. Determine all possible distances for all combinations elements A and B. In this case, if A[i] - B[j] < 0, then the distance is M + (A[i] - B[j]).
Example :
A = {0,2,3}
B = {1,2}
M = 5
Distances = {0,1,2,3,4}
Note: I know O(N^2) solution, but I need faster solution than O(N^2) and O(N x M).
Edit: Array A, B, and Distances contain distinct elements.
You can get a O(MlogM) complexity solution in the following way.
Prepare an array Ax of length M with Ax[i] = 1 if i belongs to A (and 0 otherwise)
Prepare an array Bx of length M with Bx[M-1-i] = 1 if i belongs to B (and 0 otherwise)
Use the Fast Fourier Transform to convolve these 2 sequences together
Inspect the output array, non-zero values correspond to possible distances
Note that the FFT is normally done with floating point numbers, so in step 4 you probably want to test if the output is greater than 0.5 to avoid potential rounding noise issues.
I possible done with optimized N*N.
If convert A to 0 and 1 array where 1 on positions which present in A (in range [0..M].
After convert this array into bitmasks, size of A array will be decreased into 64 times.
This will allow insert results by blocks of size 64.
Complexity still will be N*N but working time will be greatly decreased. As limitation mentioned by author 50000 for A and B sizes and M.
Expected operations count will be N*N/64 ~= 4*10^7. It will passed in 1 sec.
You can use bitvectors to accomplish this. Bitvector operations on large bitvectors is linear in the size of the bitvector, but is fast, easy to implement, and may work well given your 50k size limit.
Initialize two bitvectors of length M. Call these vectA and vectAnswer. Set the bits of vectA that correspond to the elements in A. Leave vectAnswer with all zeroes.
Define a method to rotate a bitvector by k elements (rotate down). I'll call this rotate(vect,k).
Then, for every element b of B, vectAnswer = vectAnswer | rotate(vectA,b).

Minimum Complexity of two lists element summation comparison

I have a question in algorithm design about arrays, which should be implement in C language.
Suppose that we have an array which has n elements. For simplicity n is power of '2' like 1, 2, 4, 8, 16 , etc. I want to separate this to 2 parts with (n/2) elements. Condition of separating is lowest absolute difference between sum of all elements in two arrays for example if I have this array (9,2,5,3,6,1,4,7) it will be separate to these arrays (9,5,1,3) and (6,7,4,2) . summation of first array's elements is 18 and the summation of second array's elements is 19 and the difference is 1 and these two arrays are the answer but two arrays like (9,5,4,2) and (7,6,3,1) isn't the answer because the difference of element summation is 4 and we have found 1 . so 4 isn't the minimum difference. How to solve this?
Thank you.
This is the Partition Problem, which is unfortunately NP-Hard.
However, since your numbers are integers, if they are relatively low, there is a pseudo polynomial O(W*n^2) solution using Dynamic Programming (where W is sum of all elements).
The idea is to create the DP matrix of size (W/2+1)*(n+1)*(n/2+1), based on the following recursive formula:
D(0,i,0) = true
D(0,i,k) = false k != 0
D(x,i,k) = false x < 0
D(x,0,k) = false x > 0
D(x,i,0) = false x > 0
D(x,i,k) = D(x,i-1,k) OR D(x-arr[i], i-1,k-1)
The above gives a 3d matrix, where each entry D(x,i,k) says if there is a subset containing exactly k elements, that sums to x, and uses the first i elements as candidates.
Once you have this matrix, you just need to find the highest x (that is smaller than SUM/2) such that D(x,n,n/2) = true
Later, you can get the relevant subset by going back on the table and "retracing" your choices at each step. This thread deals with how it is done on a very similar problem.
For small sets, there is also the alternative of a naive brute force solution, which basically splits the array to all possible halves ((2n)!/(n!*n!) of those), and picks the best one out of them.

Trimming vals in a matrix of arbitrary dimensions in a specified dimension

I'm writing a function that requires some values in a matrix of arbitrary dimansions to be dropped in a specified dimension.
For example, say I have a 3x3 matrix:
a=[1,2,3;4,5,6;7,8,9];
I might want to drop the third element in each row, in which case I could do
a = a(:,1:2)
But what if the dimensions of a are arbitrary, and the dimension to trim is defined as an argument in the function?
Using linear indexing, and some carefully considered maths is an option but I was wondering if there is a neater soltion?
For those interested, this is my current code:
...
% Find length in each dimension
sz = size(dat);
% Get the proportion to trim in each dimension
k = sz(d)*abs(p);
% Get the decimal part and integer parts of k
int_part = fix(k);
dec_part = abs(k - int_part);
% Sort the array
dat = sort(dat,d);
% Trim the array in dimension d
if (int_part ~=0)
switch d
case 1
dat = dat(int_part + 1 : sz(1) - int_part,:);
case 2
dat = dat(:,int_part + 1 : sz(2) - int_part);
end
end
...
It doesn't get any neater than this:
function A = trim(A, n, d)
%// Remove n-th slice of A in dimension d
%// n can be vector of indices. d needs to be scalar
sub = repmat({':'}, 1, ndims(A));
sub{d} = n;
A(sub{:}) = [];
This makes use of the not very well known fact that the string ':' can be used as an index. With due credit to this answer by #AndrewJanke, and to #chappjc for bringing it to my attention.
a = a(:, 1:end-1)
end, used as a matrix index, always refers to the index of the last element of that matrix
if you want to trim different dimensions, the simplest way is using and if/else block - as MatLab only supports 7 dimensions at most, you wont need an infinite number of these to cover all bases
The permute function allows to permute the dimension of an array of any dimension.
You can place the dimension you want to trim in a prescribed position (the first, I guess), trim, and finally restore the original ordering. In this way you can avoid running loops and do what you want compactly.

How to store vector coordinates in Matlab

what's the best way to store vector coordinates in Matlab?
For example, h is the height of the image, w is the width, how can I do this (pseudocode):
vectors = [];
for i=1:h
for j=1:w
vectors += p(i,j);
end
end
To get the kth p object from vectors, I can use vector(k).
Thank you very much.
Array growth in MATLAB works by indexing past the last element:
vectors(end+1) = p(i,j);
Conventional wisdom is that it is better to pre-allocate your array and use indexing, but automatic array growth has become much more efficient, especially for cells and arrays of non-builtin objects.
However, you can just get what you want out of p directly via [ii,jj] = ind2sub(size(p),k); p(jj,ii). Note the order jj,ii to match your loop semantics, which would create a vector that indexes the elements of p in a row-major order vs. MATLAB's native column-major ordering. That is, p(2) refers to row 2, column 1 of p, but your vectors(2) would contain to row 1, column 2 of p using your loop order.
You can use p(k) directly. It is equivalent to p(i,j) where [i,j] = ind2sub([h w], k).
Documentation for ind2sub
Unless I didn't understand your question…

Resources