Find unique tuples inside a numpy array with np.where - arrays

I want to find unique color tuples inside a numpy array with np.where. My code so far is:
from __future__ import print_function
import numpy as np
a = range(10)
b = range(10,20)
c = range(20,30)
d = np.array(zip(a, b, c))
print(d)
e = np.array(zip(c, b, a))
print(e)
search = np.array((1,11,21))
search2 = np.array((0,11,21))
print(search, search2)
f = np.where(d == search, d, e)
g = np.where(d == search2, d, e)
print(f)
print(g)
When I run the code it finds correctly the tuple search on the second position. But the tuple search2 is also found on the first position although it is not contained as unique tuple inside the array. How can I define in numpy that only unique tuples are to be found inside the array so it gives some for g the value
[[20 10 0] [21 11 1] [22 12 2]
[23 13 3] [24 14 4] [25 15 5]
[26 16 6] [27 17 7] [28 18 8] [29 19 9]]
but still finds the unique tuple search and gives for f
[[20 10 0] [ 1 11 21] [22 12 2]
[23 13 3] [24 14 4] [25 15 5]
[26 16 6] [27 17 7] [28 18 8] [29 19 9]]
?
EDIT:
OK, so the current problem is to write a GIF decoder in python. I have a previous frame called image_a and a following frame called image_b. image_b contains pixels with a certain transparency color tuple, called transp_color in this specific case for the uploaded images it is (0, 16, 8). The routine is supposed to replace all these entries with that color tuple with pixel values from image_a but leaving other pixels unchanged. My code is:
from __future__ import print_function
import numpy as np
import cv2
image_a = cv2.imread("old_frame.png")
image_b = cv2.imread("new_frame.png")
cv2.imshow("image_a", image_a)
cv2.imshow("image_b", image_b)
transp_color = (0, 16, 8)
new_image = np.where(image_b == transp_color, image_a, image_b)
cv2.imshow("new_image", new_image)
cv2.waitKey()
Trying to solve this with np.where leads to wrong colors in the resulting image as seen above in the 3rd picture. So any idea how to solve this?

The expression image_b == transp_color will result in an NxMx3 array of booleans. That is what np.where will act upon as well. If I understand your question correctly, the simplest solution here is to turn that expression into np.all(image_b == transp_color, axis=-1, keepdims=True). This will return an NxMx1 array of booleans; which np.where will broadcast over the color channel, so that you pick a pixel from either image A or B.

OK, finally found the solution myself, here is the code for doing it:
import numpy as np
import cv2
image_a = cv2.imread("old_frame.png")
image_b = cv2.imread("new_frame.png")
cv2.imshow("image_a", image_a)
cv2.imshow("image_b", image_b)
transp_color = (0, 16, 8)[::-1]
channels = 3
f = np.all((image_b==transp_color), axis=-1)
flattened_image = np.reshape(image_b, (image_b.shape[0]*image_b.shape[1], channels))
old_flattened_image = np.reshape(image_a, (image_a.shape[0]*image_a.shape[1], channels))
f = np.reshape(f, (image_a.shape[0]*image_a.shape[1], 1))
np_image = np.array([old_flattened_image[i] if j else flattened_image[i] for i, j in enumerate(f)])
new_image = np.reshape(np_image, (image_a.shape[0], image_a.shape[1], channels))
# new_image = np.where(image_b == transp_color, image_a, image_b)
cv2.imshow("new_image", new_image)
cv2.waitKey()

Related

Sum of sparse vectors: bug or feature?

I recently stumbled upon the following behavior in MATLAB R2022a:
>> a = sparse(1,2,1)
a =
(1,2) 1
>> b = sparse(2,1,18)
b =
(2,1) 18
>> a+b
ans =
(2,1) 18
(1,2) 1
(2,2) 19
The presence of the (2,2) element with value 19 is quite puzzling. Intuitively, I would have expected to get either a zero (no element) or an error indicating that the vectors' sizes are not compatible. I couldn't find an explanation for this behavior in the documentation.
So, is this a bug or a feature?
This is due to implicit broadcasting and expected behaviour, also for full() arrays. Compare:
bsxfun(#plus, [0 1], [0; 18])
ans =
0 1
18 19
(I'm running R2007b, so need bsxfun() instead of implicit broadcasting).
What happens with unequal-sized vectors is that they are broadcast ("extended") into the appropriate size for addition, see e.g. this blog post on an in-depth explanation.
Verbosely writing our toy example
a = [0 1]
b = [ 0
18]
a + b = [0 1] + [ 0
18]
% Is broadcast to
= [0 1 [ 0 0
0 1] + 18 18]
% element wise addition
= [ 0 1
18 19]
This is in fact similarly happening with full arrays, i.e. not restricted to sparse vectors, and this is normal behavior according to the documentation (see the Add Row and Column Vector section).

How do I retrieve an array of arrays of arrays in Julia?

I am new in Julia, so don't judge me please (ha ha)
This is my situation: I needed to save several 2x2x2 matrices whose elements were vectors of 4 elements, but now when I try to retrieve them from a file, I can't !!!
This is what I did:
To create these matrices I made this function
function InitialConf(L_=2,S_=2,T_=2,Dim_=4)
Conf_=Array{Array{Float64,1}}(L_,S_,T_)
for i_ = 1:L_, j_=1:S_,k_=1:T_
Conf_[i_,j_,k_]=RanUniVec(Dim_)
end
return Conf_
end
Where RanUniVec(Dim_) is the function that creates these vectors of 4 dimentions with special characteristics that are not important for this discussion:
function RanUniVec(Dim_)
vector_=Array{Float64}(Dim_)
while true
for i_ in 1:Dim_
vector_[i_]=UniformRand(-1,1)
end
if norm(vector_)<1 && norm(vector_)>0.5
break
end
end
vector_=normalize(vector_) # 2-norm
return vector_
end
function UniformRand(a_,b_)
rand_=(b_-a_)*rand()+a_
return rand_
end
I needed two of these matrices (for example) so I did the next:
States=[]
Conf1=InitialConf()
Conf2=InitialConf()
push!(States,Conf1)
push!(States,Conf2)
f=open("Info.txt","w") do f
write(f,"$States")
end
This made the Info.txt file where is my information, but when I try to get the States array again from this file, Julia tells me that it can't
f=readlines("Info.txt")
States=parse(f)
ERROR: MethodError: no method matching parse(::Array{String,1})
Closest candidates are:
parse(::Type{IPv4}, ::AbstractString) at socket.jl:167
parse(::Type{IPv6}, ::AbstractString) at socket.jl:218
parse(::Type{DateTime}, ::AbstractString, ::DateFormat{Symbol("yyyy-mm-dd\\THH:MM:SS.s"),Tuple{Base.Dates.DatePart{'y'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'m'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'d'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'H'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'M'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'S'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'s'}}}) at dates/parse.jl:202
...
Do you know how I can get again my State array?
In general you should use Colin's recommendation from the comment in the long run. Here is what you can do if you actually have those text files already generated. I will use a smaller example.
Assume your original array is consisting of two 2x2x2 arrays. Here is an example I will use:
julia> z
2-element Array{Array{Int64,3},1}:
[1 2; 3 4]
[10 20; 30 40]
[1 2; 3 4]
[10 20; 30 40]
julia> z[1]
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 2
3 4
[:, :, 2] =
10 20
30 40
julia> z[2]
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 2
3 4
[:, :, 2] =
10 20
30 40
Now it will get saved to a file as the following string:
julia> repr(z)
"Array{Int64,3}[[1 2; 3 4]\n\n[10 20; 30 40], [1 2; 3 4]\n\n[10 20; 30 40]]"
And parsing this string will clearly fail. What you have to do is to edit your files to add cat method invocation on each entry of a big array and pass dimension 3 as the one on which you want to cat them.
This means that from the original contents of the save file:
Array{Int64,3}[[1 2; 3 4]
[10 20; 30 40], [1 2; 3 4]
[10 20; 30 40]]
You have to make this file contain:
Array{Int64,3}[cat(3, [1 2; 3 4], [10 20; 30 40]),
cat(3, [1 2; 3 4], [10 20; 30 40])]
Those changes can be done either by hand or you could write a program to perform the transformation (you have to replace , by ), cat(3,; \n\n by ,; make sure that first cat and last ) are added as they will not be caught by the first two rules).
Now if you read it in it as a string you can evaluate result of parsing it:
julia> s = """Array{Int64,3}[cat(3, [1 2; 3 4], [10 20; 30 40]),
cat(3, [1 2; 3 4], [10 20; 30 40])]"""
"Array{Int64,3}[cat(3, [1 2; 3 4], [10 20; 30 40]),\ncat(3, [1 2; 3 4], [10 20; 30 40])]"
julia> eval(parse(s))[2]
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 2
3 4
[:, :, 2] =
10 20
30 40
Note, however, that all this is not recommended - it is better to use the packages that Colin recommended to do this.
Not directly an answer to your specific question, but a general recommendation for future development. To save data to disk, and reload later, give preference to formats such as JLD2.jl.
You save with
#save "filename.jld2" ARRAY
and load with
#load "filename.jld2" ARRAY
without having to figure out what was the format you chose in the past. Saves a lot of headache with complex data structures.

How to find a particular array matching certain pattern in cell array?

I want to know the index of row of cell consisting of particular array in particular column...
Example:
C{1,1} = [1 2 3];
C{1,2} = [4 5 6];
C{2,1} = [11 12 13];
C{2,2} = [14 15 16];
I want to get index as 1 when I search for [1 2 3] in column 1 (or) 2 when I search for [14 15 16] in column 2. I tried using
index = find([C{:,1}] == [1 2 3])
But didn't get. Please help
Use cellfun in combination with strfind and isempty or isequal directly.
pattern = [1 2 3];
out = cellfun(#(x) ~isempty(strfind(x,pattern)),C)
%// or as suggested by Luis Mendo
out = cellfun(#(x) isequal(x,pattern),C)
ind = find(out)
if the order within the arrays does not matter, also the following using
ismember and all is possible:
out = cellfun(#(x) all(ismember(x,pattern)),C)
out =
1 0
0 0
ind =
1
Do all the arrays have the same length n? Then you could use a more vectorized approach with an optional if-condition to see if your result is valid. It may is not necessary, depending how sure you are about your pattern input.
n = 3;
pos = strfind([C{:}],pattern)
ind = [];
if mod(pos,n) == 1, ind = (pos - 1)/n + 1, end
Both variants give you the linear index, means for pattern = [14 15 16]; it would return 4. To get the row indices you need an additional step:
[~,row_ind] = ind2sub(size(C),ind)
Another approach Using pdist2 instead of ismember and all from the other answer
pattern = [1 2 3];
out = cellfun(#(x) pdist2(x,pattern)==0,C);
ind = find(out)
Gives the same result as the other answer.

Saving vectors into a matrix matlab

I have a bunch of arrays that I have generated from a loop
Peaks [1, 2, 3, 4, 5]
Latency [23,24,25,26,27] etc.
I want to put all of those in a matrix that will look like that:
Peaks Latency
1 23
2 24
3 25
4 26
5 27
Then I'll want to save this as a text file.
It seems like it would be fairly simple but can't seem to find anything that closely speaks to me right now.
Concatentate:
>> Peaks = [1 2 3 4 5];
>> Latency = [23 24 25 26 27];
>> T = [Peaks(:) Latency(:)]
T =
1 23
2 24
3 25
4 26
5 27
Write:
fileName = 'PeaksLatency.txt';
hdr = {'Peaks','Latency'}
txt = sprintf('%s\t',hdr{:}); txt(end) = [];
dlmwrite(fileName,txt,''); % write header
dlmwrite(fileName,T,'-append','delimiter','\t'); % append data
Here is the code
Peaks = [1, 2, 3, 4, 5].';
Latency = [23,24,25,26,27].';
T = table(Peaks, Latency);
writetable(T,'table.txt', 'Delimiter', '\t');
Note that you need to make Peaks and Latency into column vectors (use .' operator).
Ref: http://www.mathworks.com/help/matlab/ref/writetable.html

Matlab, matrix of arrays

There are 3 matrices A,B,C:
A=[0 1;2 3]
B=[4 5;6 7]
C=[8 9;10 11]
How to create a new matrix D(2,2) so as its elements are arrays of a type
D = [{A(1,1), B(1,1), C(1,1)} {{A(1,2), B(1,2), C(1,12};
{A(2,1), B(2,1), C(2,1)} {A(2,2), B(2,2), C(2,2)}]
For example: Using an operator D(1,1) gives the result
0, 4, 8
The bracket {} are only illustrative and do not represent a matlab syntax...
You could stack the matrices along the third dimension:
D = cat(3,A,B,C);
Then you could access as:
>> D(1,1,:)
ans(:,:,1) =
0
ans(:,:,2) =
4
ans(:,:,3) =
8
if you want to get a 1D-vector:
>> squeeze(D(1,1,:)) %# or: permute(D(1,1,:),[1 3 2])
ans =
0
4
8
If you prefer to use cell arrays, here is an easier way to build it:
D = cellfun(#squeeze, num2cell(cat(3,A,B,C),3), 'UniformOutput',false);
which can be accessed as:
>> D{1,1}
ans =
0
4
8
You are almost there:
D = [{[A(1,1), B(1,1), C(1,1)]} {[A(1,2), B(1,2), C(1,2)]};
{[A(2,1), B(2,1), C(2,1)]} {[A(2,2), B(2,2), C(2,2)]}]
(you see the additional branches?)
D is now a cell array, with each cell containing a 1x3 matrix.
To access the cell array use this syntax:
D{1,1}

Resources