Convert image in list of coordinates in Julia - arrays

I have this short code img_lab = rand(Lab, 10, 10) where I just have created an image of random colored pixels. Probably this question is trivial but how do I convert the output of this (which is Matrix{Lab{Float64}} (alias for Array{Lab{Float64}, 2}) to an organized list of coordinates.
For example [[0,0,0.44,0.33,0.45],[0,1, ...] , ... , [10,10,0.54,0.32,0.87]]
where the first two entries are the coordinates and the last three values for RGB.

First, please make sure that you have good reasons to do this. Converting to such a format makes it harder to use the rest of Colors functionality, could have a (potentially large) performance cost, and is usually unnecessary.
Now, assuming it's necessary, here's one way to do it:
julia> using Random; Random.seed!(42)
TaskLocalRNG()
julia> img_lab = rand(Lab, 10, 10)
10×10 Matrix{Lab{Float64}}:
Lab(17.3575, -26.8628, -55.5385) Lab(9.1585, 86.3359, 71.5105) … Lab(14.4465, 87.7468, 12.1242)
Lab(16.6439, 11.0078, -10.1264) Lab(54.2929, -24.2044, -55.6044) Lab(5.5968, 79.2197, -6.69094)
Lab(39.0663, 61.8604, 90.5844) Lab(50.2836, -78.3482, -26.4757) Lab(6.6672, 21.7418, -100.172)
.
.
.
julia> map(keys(img_lab)) do cindex
rgbval = RGB(img_lab[cindex])
[cindex[1], cindex[2], red(rgbval), green(rgbval), blue(rgbval)]
end
10×10 Matrix{Vector{Float64}}:
[1.0, 1.0, 0.0, 0.223779, 0.488699] [1.0, 2.0, 0.468242, 0.0, 0.0] … [1.0, 10.0, 0.513226, 0.0, 0.101153]
[2.0, 1.0, 0.196137, 0.141577, 0.218233] [2.0, 2.0, 0.0, 0.573977, 0.885473] [2.0, 10.0, 0.366805, 0.0, 0.118275]
[3.0, 1.0, 0.737804, 0.0333098, 0.0] [3.0, 2.0, 0.0, 0.583897, 0.639801] [3.0, 10.0, 0.0, 0.136071, 0.65593]
[4.0, 1.0, 0.117582, 0.0803492, 0.209829] [4.0, 2.0, 0.833069, 0.433512, 1.0] [4.0, 10.0, 0.818553, 0.673722, 0.202751]
[5.0, 1.0, 0.0, 0.267613, 0.416236] [5.0, 2.0, 0.0, 1.0, 1.0] [5.0, 10.0, 0.26368, 0.0, 0.0]
[6.0, 1.0, 0.0, 0.703393, 0.0] [6.0, 2.0, 0.89057, 0.980158, 1.0] … [6.0, 10.0, 0.491448, 0.47962, 0.891735]
[7.0, 1.0, 0.0, 1.0, 0.819822] [7.0, 2.0, 1.0, 0.773939, 1.0] [7.0, 10.0, 0.0, 1.0, 1.0]
[8.0, 1.0, 1.0, 0.707005, 0.402694] [8.0, 2.0, 0.0, 0.820631, 1.0] [8.0, 10.0, 0.0, 0.3219, 0.91962]
[9.0, 1.0, 1.0, 0.830982, 0.928663] [9.0, 2.0, 0.0, 0.279664, 0.0] [9.0, 10.0, 0.937227, 0.650945, 0.442197]
[10.0, 1.0, 0.291409, 0.0, 0.28529] [10.0, 2.0, 1.0, 0.682411, 1.0] [10.0, 10.0, 0.0, 0.475448, 0.941526]
(From my limited understanding, Lab-to-RGB conversion is a lossy one - and the number of 0.0s and 1.0s in the color values above seems to indicate that too, values outside the RGB gamut getting clamped to be within its limits.)

Related

Arranging a list based on the distance of its elements from a given value

Let's assume we have a list like the following
[2.3, 1.02, 1.99, 0.99, 0.089, 0, 1.1, -1.1, -2.1]
We want to arrange the elements of this list based on their distance from target value equal to 1 in the following manner:
[0.99, 1.02, 1.1, 0.089, 1.99, 0, 2.3, -1.1, -2.1]
How to do that in python in one or two lines?
python solution
Use sorted with the absolute distance to target as key:
L = [2.3, 1.02, 1.99, 0.99, 0.089, 0, 1.1, -1.1, -2.1]
target = 1
out = sorted(L, key=lambda x: abs(x-target))
output: [0.99, 1.02, 1.1, 0.089, 1.99, 0.0, 2.3, -1.1, -2.1]
numpy solution
Compute the absolute distance and use numpy.argsort:
L = [2.3, 1.02, 1.99, 0.99, 0.089, 0, 1.1, -1.1, -2.1]
target = 1
import numpy as np
a = np.array(L)
out = a[np.argsort(abs(a-target))].tolist()
output: [0.99, 1.02, 1.1, 0.089, 1.99, 0.0, 2.3, -1.1, -2.1]

Find minimal set of operations that modify array to meet condition

I have an array of sorted numbers:
arr = [-0.1, 0.0, 0.5, 0.8, 1.2]
I want the difference (dist below) between consecutive numbers for that array to be above a given threshold. For example, if threshold is 0.25:
dist = [0.1, 0.5, 0.3, 0.4] # must be >0.25 for all elements
arr[0] and arr[1] are too close to each other, so one of them must be modified. In this case the desired array would be:
good_array = [-0.25, 0.0, 0.5, 0.8, 1.2] # all elements distance > threshold
In order to obtain good_array, I want to modify the minimum amount of elements in arr. So I substract 0.15 from arr[0] rather than, say, substract 0.1 from arr[0] and add 0.05 to arr[1]:
[-0.2, 0.05, 0.5, 0.8, 1.2]
Previous array is also valid, but we have modified 2 elements rather than one.
Also, in case it is possible to generate good_array by modifying different elements in arr, by default modify the element closer to the edge of the array. But keep in mind the main goal is to generate good_array by modifying the minimum number of elemtns in arr.
[-0.1, 0.15, 0.5, 0.8, 1.2]
Previous array is also valid, but we have modified arr[1] rather than the element closer to the edge (arr[0]). In case 2 elements have equal distance from edges, modify the one closer to begining of array:
[-0.3, 0.15, 0.2, 0.7] # modify arr[1] rather than arr[2]
So far I have been doing this manually for small arrays, but I would like a general solution for larger arrays.
Here is brute force python solution, where we try to fix elements to the right or elements to the left when there is a conflict:
def solve(arr, thereshold):
original = list(arr)
def solve(idx):
if idx + 1 >= len(arr):
return [sum(1 for x in range(len(arr)) if arr[x] != original[x]), list(arr)];
if arr[idx + 1] - arr[idx] < thereshold:
copy = list(arr)
leftCost = 0
while idx - leftCost >= 0 and arr[idx + 1] - arr[idx - leftCost] < thereshold * (leftCost + 1):
arr[idx - leftCost] = arr[idx - leftCost + 1] - thereshold
leftCost += 1
left = solve(idx + 1)
for cost in range(leftCost):
arr[idx - cost] = copy[idx - cost]
rightCost = 0
while idx + rightCost + 1 < len(arr) and arr[idx + rightCost + 1] - arr[idx] < thereshold * (rightCost + 1):
arr[idx + rightCost + 1] = arr[idx + rightCost ] + thereshold
rightCost += 1
right = solve(idx + 1)
for cost in range(rightCost):
arr[idx + cost + 1] = copy[idx + cost + 1]
if right[0] < left[0]:
return right
elif left[0] < right[0]:
return left
else:
return left if idx - left[0] <= len(arr) - idx - right[0] else right
else:
return solve(idx + 1)
return solve(0)
print(solve([0,0.26,0.63,0.7,1.2], 0.25))
Edit: I just realized that my original solution was stupid and overcomplicated. Now presenting simple and better solution
First approach
If I understand your problem correctly, your input array can have some regions, where your condition is not met. For instance:
array = [0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.5, 0.75, 1.0] (first 4 elements)
or:
array = [0.25, 0.5, 0.75, 1.0, 1.0, 1.0, 1.0, 1.0, 1.25, 1.5, 1.75] (elements arr[4], arr[5] and arr[6])
To fix that, you have to add (or subtract) some pattern like:
fixup = [0.0, 0.25, 0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0] (for the first case)
or:
fixup = [0.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.25, 0.0, 0.0, 0.0, 0.0] (for the second example)
Second approach
But our current solution has got some problem. Consider a bad area with an "elevation":
array = [0.0, 0.25, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.35, 1.6] (broken area is within values: 0.6-1.0)
In that case our correct "solution" will be:
fixup = [0.0, 0.0, 0.0, 0.25+0.1, 0.0, 0.25+0.1, 0.0, 0.25+0.1, 0.0, 0.0, 0.0]
which produce:
good_array = [0.0, 0.25, 0.5, 0.95, 0.7, 1.15, 0.9, 1.0, 1.1, 1.35, 1.6]
So to summarize, you have to apply the "patch":
fixup[i] = threshold+max(difference[i], difference[i-1]) (for i when i-start_index is even)
(please note that it will be -threshold+min(difference[i], difference[i-1]) for negative values)
and:
fixup[i] = 0 (for i when i-start_index is odd)
start_index is a beginning of the bad region.
Third approach
Previously mentioned formula doesn't work well for some cases (like [0.1, 0.3, 0.4] that it would increment 0.3 up to 0.75 when only 0.65 is sufficient)
Lets try to improve that:
good_array[i] = max(threshold+array[i-1], threshold+array[i+1]) (for abs(array[i-1]-array[i+1]) < threshold*2)
and:
good_array[i] = (array[i-1]+array[i+1])/2 otherwise.
(you can also choose formula: good_array[i] = min(-threshold+array[i-1], -threshold+array[i+1]) when it would produce a result closer to original array value, if minimizing difference is also your optimization goal)
4th approach
Bad regions of even length are also a threat. I can think about 2 ways to solve it:
Solution based on a pattern like [0.0, 0.25, 0.5, 0.0]
Or based on a pattern like [0.0, 0.25, -0.25, 0.0] (We are simply using "the second formula")
Or [0.0, 0.25, 0.0, 0.25] (just including additional element to make bad region length odd -I don't recommend this approach as it would require handling lot of corner cases)
Corner cases
Please consider also some corner cases (bad region starts or ends at an "edge" of the array):
good_array[0] = threshold+array[1]
and:
good_array[array_size-1] = threshold+array[array_size-2]
Final hints
I would suggest to implement lot of unit tests during implementation in order to easily verify correctness of derived formulas and handle some combinations of corner cases. Bad areas that consist of only one element can be one of them.

How to extract just floats from list

I want to get arrays with floats from A,B,C list.
page = requests.get("http://www.arso.gov.si/potresi/obvestila%20o%20potresih/aip/")
soup = BeautifulSoup(page.content, 'html.parser')
all_tables=soup.find_all('table')
right_table=soup.find('table',class_='online')
A=[]
B=[]
C=[]
for row in right_table.findAll("tr"):
cells = row.findAll('td')
if len(cells)==6:
A.append(cells[1].find(text=True))
B.append(cells[2].find(text=True))
C.append(cells[3].find(text=True))
For now I have variables like this:
A=[u'45.50',u'46.00',...]
and I want just floats from list:
A=[45.50,46.00,...]
Just convert the element's text to float type:
...
if len(cells) == 6:
A.append(float(cells[1].text))
B.append(float(cells[2].text))
C.append(float(cells[3].text))
print(A)
print(B)
print(C)
The output:
[45.5, 46.0, 46.07, 45.89, 45.83, 46.1, 46.53, 45.88, 45.84, 45.9, 46.09, 46.39, 45.3, 45.34, 46.7, 45.25, 46.39, 45.5, 46.39]
[14.41, 14.76, 14.22, 14.59, 15.12, 14.42, 14.57, 15.19, 15.18, 14.57, 14.19, 13.39, 14.62, 14.59, 15.23, 14.58, 15.03, 14.4, 15.03]
[1.2, 1.2, 1.0, 0.8, 1.2, 1.0, 1.1, 1.3, 0.8, 0.9, 0.5, 1.0, 1.3, 2.3, 1.4, 1.9, 0.7, 0.8, 0.4]
You could use python2.7 map function to convert each list of strings to a list of floats:
A = map(float, A)
B = map(float, B)
C = map(float, C)
print A # [45.5, 46.0, 46.07, 45.89, 45.83, 46.1, 46.53, 45.88, 45.84, 45.9, 46.09, 46.39, 45.3, 45.34, 46.7, 45.25, 46.39, 45.5, 46.39]
print B # [14.41, 14.76, 14.22, 14.59, 15.12, 14.42, 14.57, 15.19, 15.18, 14.57, 14.19, 13.39, 14.62, 14.59, 15.23, 14.58, 15.03, 14.4, 15.03]
print C # [1.2, 1.2, 1.0, 0.8, 1.2, 1.0, 1.1, 1.3, 0.8, 0.9, 0.5, 1.0, 1.3, 2.3, 1.4, 1.9, 0.7, 0.8, 0.4]

How to find correspondent elements of two linearly transformed arrays in Ruby?

I have two arrays of floats (x,y) with unique elements, one of them is a linear transform of the other y=a*x+b, for example:
a=0.95;
b1=3.33;
b2=5.55;
x=[1,3,4,6,9,13,20,22,31,35,37,40];
y=t1.collect.with_index{|z,i| i>6 ? z*a+b1 : z*a+b2}
=> [6.5, 8.4, 9.35, 11.25, 14.1, 17.9, 24.55, 24.23, 32.78, 36.58, 38.48, 41.33]
The linear transformation is applied with two different b values to the x array. Let's suppose I don't know the rule of the b values aplied, here the function of the index i.
My goal is that if I know the value of a and I also know the possible values of b in the form of a two element array bs=[b1,b2], then I would like to find out the correspondent b value for every element of y even if the two arrays (x,y) are scrambled. My idea (doesn't work correctly, I need help here):
def ybs(x,y,bs,a)
difference=0.0
xelem=0.0
return y.map do |z|
cb=bs.min_by do |b|
xelem=x.min_by do |q|
(q-(z-b)*1/a).abs
end
difference=(xelem-(z-b)*1/a).abs
end
difference=(xelem-(z-cb)*1/a).abs
[z,xelem,(z-cb)*1/a,cb,difference]
end
end
It would return 4 values for every elements of the y array in the form:
[<value from y>,<correspondent value from x>,<inverse transformed value of y, should be equal to xelem>,<correspondent b value of the linear transformation>,<difference, error, usually 0.0>]
My output when I call ybs(x,y,bs,a):
[[1, 6.5, -2.4526315789473685, 3.33, 8.952631578947368],
[3, 6.5, -0.34736842105263166, 3.33, 6.847368421052631],
[4, 6.5, 0.7052631578947368, 3.33, 5.794736842105263],
[6, 6.5, 2.8105263157894735, 3.33, 3.6894736842105265],
[9, 6.5, 5.968421052631579, 3.33, 0.5315789473684207],
[13, 8.4, 7.842105263157896, 5.55, 0.5578947368421048],
[20, 14.1, 17.547368421052635, 3.33, 3.4473684210526354],
[22, 17.9, 17.31578947368421, 5.55, 0.5842105263157897],
[31, 24.55, 26.789473684210527, 5.55, 2.2394736842105267],
[35, 32.78, 33.33684210526316, 3.33, 0.5568421052631578],
[37, 32.78, 33.10526315789474, 5.55, 0.3252631578947387],
[40, 36.58, 38.6, 3.33, 2.020000000000003]]
I need this method for my subtitle syncing program, where different parts of the subtitles' time codes can be shifted by different amount, for example when a scene is missing from a different version of the movie.
The problem was that you weren't keeping your ordered pairs together. For each y value, your code 'thinks' that the x associated with it is the one for which (q-(z-b)*1/a).abs is the least. However, it could be that taking the "wrong" b value for the y value being considered, together with the wrong x value would lead to a value of (q-(z-b)*1/a).abs that was slightly (or much) less than that which you get by taking the "right" b and x values.
I ran your code (rounding off the values for clarity) and got:
[6.5, 1.0, 1.0, 5.55, 0.0]
[8.4, 3.0, 3.0, 5.55, 0.0]
[9.35, 4.0, 4.0, 5.55, 0.0]
[11.25, 6.0, 6.0, 5.55, 0.0]
[14.1, 9.0, 9.0, 5.55, 0.0]
[17.9, 13.0, 13.0, 5.55, 0.0]
[24.55, 20.0, 20.0, 5.55, 0.0]
[24.23, 20.0, 22.0, 3.33, 2.0]
[32.78, 31.0, 31.0, 3.33, 0.0]
[36.58, 31.0, 35.0, 3.33, 4.0]
[38.48, 35.0, 37.0, 3.33, 2.0]
[41.33, 37.0, 40.0, 3.33, 3.0]
You can see that the x values do not follow the original sequence. Since there's no need to take a chance letting 'y's get associated with the wrong 'x's, lets just force them to stay together.
Here is how I modified your code to keep the ys and xs together.
def ybs(pairs,bs,a)
difference=0.0
xelem=0.0
return pairs.map do |pair|
x,y = pair[0], pair[1]
cb = bs.min_by do |b|
(x-(y-b)*1/a).abs
end
difference = (x-(y-cb)*1/a).abs
[y,x,(y-cb)*1/a,cb,difference]
end
end
a=0.95;
b1=3.33;
b2=5.55;
bs = [b1, b2]
x=[1,3,4,6,9,13,20,22,31,35,37,40];
y=x.collect.with_index{|z,i| i>6 ? z*a+b1 : z*a+b2}
c = x.count-1
pairs = (0..c).collect do |i|
[x[i],y[i]]
end
r = ybs(pairs,bs,a)
r.each do |q|
(0..4).each do |p|
q[p] = q[p].round(2)
end
p q
end
and here is my output:
[6.5, 1.0, 1.0, 5.55, 0.0]
[8.4, 3.0, 3.0, 5.55, 0.0]
[9.35, 4.0, 4.0, 5.55, 0.0]
[11.25, 6.0, 6.0, 5.55, 0.0]
[14.1, 9.0, 9.0, 5.55, 0.0]
[17.9, 13.0, 13.0, 5.55, 0.0]
[24.55, 20.0, 20.0, 5.55, 0.0]
[24.23, 22.0, 22.0, 3.33, 0.0]
[32.78, 31.0, 31.0, 3.33, 0.0]
[36.58, 35.0, 35.0, 3.33, 0.0]
[38.48, 37.0, 37.0, 3.33, 0.0]
[41.33, 40.0, 40.0, 3.33, 0.0]
All of the errors are small, and the bs are correct... they are 5.55 until the 7th row, where they switch to 3.33, as your rule prescribes.

How do I append one matrix to another in Scala?

If I have the following code:
var A = Array[Array[Double]]() // where A becomes an MxP matrix
var B = Array[Array[Double]]() // where B becomes an NxP matrix
What are some efficient ways to append one matrix to the other, resulting in a single matrix, as the following pseudocode would suggest?
val C = A append B // where C is a (M+N)xP matrix
Obviously, one of the dimensions (in this case P) is held constant.
EDIT: So far, both of the provided solutions are growing in the second dimension. I am trying to hold the second dimension fixed.
Functional, but not as performant as the imperative alternative would be:
scala> val a = Array.tabulate(2, 3)((_, _) => (math.random * 100).toInt)
a: Array[Array[Int]] = Array(Array(52, 61, 58), Array(35, 69, 39))
scala> val b = Array.tabulate(2, 4)((_, _) => (math.random * 100).toInt)
b: Array[Array[Int]] = Array(Array(51, 54, 87, 10), Array(52, 76, 18, 85))
scala> (a, b).zipped.map(_ ++ _)
res0: Array[Array[Int]] = Array(Array(52, 61, 58, 51, 54, 87, 10), Array(35, 69, 39, 52, 76, 18, 85))
(In reply to the comment...)
Holding the second dimension fixed:
scala> val x = Array.tabulate(3, 2)((_, _) => (math.random * 100).toInt)
x: Array[Array[Int]] = Array(Array(13, 26), Array(96, 6), Array(68, 58))
scala> val y = Array.tabulate(2, 2)((_, _) => (math.random * 100).toInt)
y: Array[Array[Int]] = Array(Array(82, 5), Array(0, 76))
scala> x ++ y
res1: Array[Array[Int]] = Array(Array(13, 26), Array(96, 6), Array(68, 58), Array(82, 5), Array(0, 76))
scala> val a = Array.fill(4,3) { 1. };
a: Array[Array[Double]] = Array(Array(1.0, 1.0, 1.0), Array(1.0, 1.0, 1.0), Array(1.0, 1.0, 1.0), Array(1.0, 1.0, 1.0))
scala> val b = Array.fill(4,6) { 2. };
b: Array[Array[Double]] = Array(Array(2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(2.0, 2.0, 2.0, 2.0, 2.0, 2.0))
scala> for((aa,bb) <- a zip b) yield (aa ++ bb)
res0: Array[Array[Double]] = Array(Array(1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0))

Resources