Assigning unique colours to different value combinations Python - python

I have a pivot table array with factors and X and Y coordinates such as the one below, and I have a look up table with 64 colours that have RGB values. I am trying to assign a colour to each factor combination and I'm not too sure how to go about doing so. For example, I need all A(0) B(1) C(0) D(0) to be RGB value (1 0 103) so that I can then paint those colours onto an image at point XY.
A B C D Xpoint Ypoint
0 1 0 0 20 20
0 1 1 0 30 30
0 1 0 0 40 40
1 0 1 0 50 50
1 0 1 0 60 60
So far I only have code to open both my LUT and pivot table file and code to see the length of the pivot table.
import pandas as pd
from PIL import Image, ImageDraw
## load in LUT of 64 colours ##
with open('LUT64.csv') as d:
LUT64 = pd.read_table(d, sep=',')
print LUT64
## load in XY COordinates ##
with open('PivotTable_2017-07-13_001.txt') as e:
PivotTable = pd.read_table(e, sep='\t')
print PivotTable
## Bring in image ##
IM = Image.open("mothTest.tif")
IM.show()
#bring in number of factors
numFactors = 16
#assign colour vectors to each factor combo
numPTrows = len(PivotTable)
print numPTrows
#Apply colour dots to image at XY coordinates
Any help would be greatly appreciated!

You can use a dict for your colour values with the first four values of your table as key (cast into a tuple):
table = [
[0, 1, 0, 0, 20, 20],
[0, 1, 1, 0, 30, 30],
[0, 1, 0, 0, 40, 40],
[1, 0, 1, 0, 50, 50],
[1, 0, 1, 0, 60, 60],
]
##generating some colors
colors = [ (i,i,i) for i in range(0,256, 5)]
##defining iterator over color table
c_it = iter(colors)
##the dictionary for the color values
color_dict = dict()
##assigning one color for each unique (A,B,C,D) tuple:
for entry in table:
key = tuple(entry[0:4])
if key not in color_dict:
color_dict[key] = next(c_it)
print(color_dict)
The output of this is:
{
(1, 0, 1, 0): (10, 10, 10),
(0, 1, 1, 0): (5, 5, 5),
(0, 1, 0, 0): (0, 0, 0)
}
EDIT:
In correspondence the edit of the OP's question, here a rough sketch of how to manipulate your Pillow Image (untested):
##looping through table:
for entry in table:
key = tuple(entry[0:4])
coord = tuple(entry[4:6])
color = color_dict[key]
IM.putpixel(coord,color)

Related

How to create a circular frequency histogram

Dear members of stackoverflow,
I want to create a circular frequency histogram (rose diagram) using the the frequencies for each bin listed as a single column in a text file. How could I do this using matplotlib.pyplot and numpy in python3?
I did an initial attempt with a code I found on the internet, but when I get the rose diagram the bins are overlapped when they should be beside each other. Other detail: the radius of the circle for each bin should be the frequency, but this also changes and does not match my frequencies.
I want my bins to go from 0 to 360 degrees with width of 10 degrees; example: 0-10, 10-20 etc.
This is a sample of the txt file with the frequencies(frequencies.txt):
0
0
0
0
0
2
0
1
1
0
1
0
0
1
2
29
108
262
290
184
81
25
7
2
3
1
1
0
0
0
0
0
0
0
0
0
You could create a polar bar plot. The angles need to be converted from degrees to radians.
frequencies = np.loadtxt('filename.txt') would read the values from file (docs).
import numpy as np
import matplotlib.pyplot as plt
frequencies = [0, 0, 0, 0, 0, 2, 0, 1, 1, 0, 1, 0, 0, 1, 2, 29, 108, 262, 290,
184, 81, 25, 7, 2, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
fig = plt.figure()
ax = plt.axes(polar=True)
theta = np.radians(np.arange(0, 360, 10))
width = np.radians(10)
ax.bar(theta, frequencies, width=width,
facecolor='lightblue', edgecolor='red', alpha=0.5, align='edge')
ax.set_xticks(theta)
plt.show()

Python: How to compare values of a row with a threshold to determine cycles

I have the following code I made that gets data from a machine in CSV format:
import pandas as pd
import numpy as np
header_list = ['Time']
df = pd.read_csv('S8-1.csv' , skiprows=6 , names = header_list)
#splits the data into proper columns
df[['Date/Time','Pressure']] = df.Time.str.split(",,", expand=True)
#deletes orginal messy column
df.pop('Time')
#convert Pressure from object to numeric
df['Pressure'] = pd.to_numeric(df['Pressure'], errors = 'coerce')
#converts to a time
df['Date/Time'] = pd.to_datetime(df['Date/Time'], format = '%m/%d/%y %H:%M:%S.%f' , errors = 'coerce')
#calculates rolling and rolling center of pressure values
df['Moving Average'] = df['Pressure'].rolling(window=5).mean()
df['Rolling Average Center']= df['Pressure'].rolling(window=5, center=True).mean()
#sets threshold for machine being on or off, if rolling center average is greater than 115 psi, machine is considered on
df['Machine On/Off'] = ['1' if x >= 115 else '0' for x in df['Rolling Average Center'] ]
df
The following DF is created:
Throughout the rows in column "Machine On/Off" there will be values of 1 or 0 based on the threshold i set. I need to write a code that will go through these rows and indicate if a cycle has started. The problem is due to the data being slightly off, during a "on" cycle, there will be around 20 rows saying (1) with a couple of rows saying 0 due to poor data recieved.
I need to have a code that compares the values through the data in order to determine the amount of cycles the machine is on or off for. I was thinking that setting a threshold of around would work, so that if the value is (1) for more than 6 rows then it will indicate a cycle and ignore the incorrect 0's that are scattered throughout the column.
What would be the best way program this so I can get a total count of cycles the machine is on or off for throughout the 20,000 rows of data I have.
Edit: Here is a example Df that is similar, in this example we can see there are 3 cycles of the machine (1 values) and mixed into the on cycles is 0 values (bad data). I need a code that will count the total number of cycles and ignore the bad data that may be in the middle of a 'on cycle'.
import pandas as pd
Machine = [0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0]
df2 = pd.DataFrame(Machine)
You can create groups of consecutive rows of on/off using cumsum:
machine = [0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0]
df = pd.DataFrame(machine, columns=['Machine On/Off'])
df['group'] = df['Machine On/Off'].ne(df['Machine On/Off'].shift()).cumsum()
df['group_size'] = df.groupby('group')['group'].transform('size')
# Output
Machine On/Off group group_size
0 0 1 6
1 0 1 6
2 0 1 6
3 0 1 6
4 0 1 6
5 0 1 6
6 1 2 5
7 1 2 5
8 1 2 5
9 1 2 5
10 1 2 5
I'm not sure I got your intention on how you would like to filter/alter the values, but probably this can serve as a guide:
threshold = 6
# Replace 0 for 1 if group_size < threshold. This will make the groupings invalid.
df.loc[(df['Machine On/Off'].eq(0)) & (df.group_size.lt(threshold)), 'Machine On/Off'] = 1
# Output df['Machine On/Off'].values
array([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], dtype=int64)

Pythonic way to transform a 2d array into a RGB image, using dictionaries

Say I have a 2d Matrix like
[[80 80 80]
[ 0 50 0]
[ 0 0 50]
[ 0 50 0]
[ 30 30 30]]
and I have a dictionary like
color_dict = {
80: (255,255,0),
50: (255,0,0),
30: (0,0,255)
}
I would like to get an BGR image (very small in this case, but image anyway) that is the reflection of the matrix based on the color assigned to each value by the dictionary.
I can do it using a loop which is my first instinct. But is there a more pythonic way to do this?
I see two options in this case:
Option 1: Numpy indexing
# First of all you need to map your random values to a continuous discrete range:
# 0 -> 0, 30 -> 1, 50 -> 2, 80 -> 3, for this you can use basic indexing.
# Now we have an array containing the position of each pixel and his corresponding value
img = np.array([[0,1,2],
[2,1,0]])
# And another array containing the colormap for each value
val = np.array([[255,255,0], # -> 0
[255,0,100], # -> 1
[100,0,0]]) # -> 2
# If we index the second array with the first one we obtain a new 3D array, the final image:
res = val.T[:,img]
Which looks like this:
array([[[250, 255, 100],
[100, 255, 250]],
[[250, 0, 0],
[ 0, 0, 250]],
[[ 0, 100, 0],
[ 0, 100, 0]]])
Options 2: Indexed color
Some image formats support indexed color:
Where a colormap associate each value with a specific color. So using one of those format will directly solve your problem.

How to convert the following trigonometric function into a python function for boundary curvature calculation?

I am trying to understand a few slides from this source
Specifically, this example at slide 59:
The part I do not understand is how to go from the chain-code to the curvature.
I believe the formula is given in slide 56:
But if I try to implement this in python I get different results.
For example:
import matplotlib.pyplot as plt
# Dataset
x = [0, 1, 2, 2, 3, 4, 5, 6, 6, 7, 8]
y = [0, 0, 0, 1, 1, 2, 2, 1, 0, 0, 0]
# Show data
plt.scatter(x, y)
plt.plot(x, y)
plt.axis('equal')
plt.show()
import math
i = 4 # Taking the 5th point, at index 4, with supposed curvature of 1 from the slide
k = 1
a = math.atan((y[i+k]-y[i])/(x[i+k]-x[i]))
b = math.atan((y[i]-y[i-k])/(x[i]-x[i-k]))
result = (a - b) % (2 * math.pi) # = 0.7853981633974483
So clearly I a missing something, but what?
The "curvature" in the first image is the difference between two subsequent "chain-codes" modulo 8. So for example for chain codes 0 0 2 0 1 0 7 6 0 0 the 4th entry in curvature is 1-0 = 1 while the sixth is 7-0 = 7 = -1 (mod 8). In Python you can calculate it like this:
>>> def mod8(x):
... m = x % 8
... return m if m < 4 else m - 8
...
>>> cc = [0, 0, 2, 0, 1, 0, 7, 6, 0, 0]
>>> [mod8(a - b) for (a, b) in zip(cc[1:], cc[:-1])]
[0, 2, -2, 1, -1, -1, -1, 2, 0]
If you compare this with the formula that uses atan, what the formula is missing is the conversion of the angles from radians to the units where 1 is 45 degrees (pi/4). Your result 0.7853981633974483 is correct according to the formula, but if you expected to get 1.0 you would have to divide the result by math.pi/4.

How to slice a multidimensional array in python/numpy in a way to select specific row, column and depth?

I'm trying to convert my MATLAB code to python but I'm having some issues. This code is supposed to segment letters from a picture.
Here's the whole code in MATLAB:
he = imread('r.jpg');
imshow(he);
%C = makecform(type) creates the color transformation structure C that defines the color space conversion specified by type.
cform = makecform('srgb2lab');
%To perform the transformation, pass the color transformation structure as an argument to the applycform function.
lab_he = applycform(he,cform);
%convert to double precision
ab = double(lab_he(:,:,2:3));
%size of dimension in 2D array
nrows = size(ab,1);
ncols = size(ab,2);
%B = reshape(A,sz1,...,szN) reshapes A into a sz1-by-...-by-szN array where
%sz1,...,szN indicates the size of each dimension. You can specify a single
% dimension size of [] to have the dimension size automatically calculated,
% such that the number of elements in B matches the number of elements in A.
% For example, if A is a 10-by-10 matrix, then reshape(A,2,2,[]) reshapes
% the 100 elements of A into a 2-by-2-by-25 array.
ab = reshape(ab,nrows*ncols,2);
% repeat the clustering 3 times to avoid local minima
nColors = 3;
[cluster_idx, cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', ...
'Replicates',3);
pixel_labels = reshape(cluster_idx,nrows,ncols);
imshow(pixel_labels,[]), title('image labeled by cluster index');
segmented_images = cell(1,3);
rgb_label = repmat(pixel_labels,[1 1 3]);
for k = 1:nColors
color = he;
color(rgb_label ~= k) = 0;
segmented_images{k} = color;
end
figure,imshow(segmented_images{1}), title('objects in cluster 1');
figure,imshow(segmented_images{2}), title('objects in cluster 2');
figure,imshow(segmented_images{3}), title('objects in cluster 3');
mean_cluster_value = mean(cluster_center,2);
[tmp, idx] = sort(mean_cluster_value);
blue_cluster_num = idx(1);
L = lab_he(:,:,1);
blue_idx = find(pixel_labels == blue_cluster_num);
L_blue = L(blue_idx);
is_light_blue = im2bw(L_blue,graythresh(L_blue));
% target_labels = repmat(uint8(0),[nrows ncols]);
% target_labels(blue_idx(is_light_blue==false)) = 1;
% target_labels = repmat(target_labels,[1 1 3]);
% blue_target = he;
% blue_target(target_labels ~= 1) = 0;
% figure,imshow(blue_target), title('blue');
Here's what I have in Python so far:
import cv2
import numpy as np
from matplotlib import pyplot as plt
import sys
img = cv2.imread('r.jpg',1)
print "original image: ", img.shape
cv2.imshow('BGR', img)
img1 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img2 = cv2.cvtColor(img1, cv2.COLOR_RGB2LAB)
cv2.imshow('RGB', img1)
cv2.imshow('LAB', img2) #differs from the LAB color space in MATLAB (need to patch maybe?)
print "LAB converted image: ", img2.shape
print "LAB converted image dimension", img2.ndim #says the image is a 3 dimensional array
img2a = img2.shape[2][1:2]
print "Slicing the LAB converted image", img2a
#we need to convert that to double precision
print img2.dtype
img2a = img2.astype(np.uint64) #convert to double precision
print img2a.dtype
#print img2a
row = img2a.shape[0] #returns number of rows of img2a
column = img2a.shape[1] #returns number of columns of img2a
print "row: ", row #matches the MATLAB version
print "column: ", column #matchees the MATLAB version
rowcol = row * column
k = cv2.waitKey(0)
if k == 27: # wait for ESC key to exit
cv2.destroyAllWindows()
elif k == ord('s'): # wait for 's' key to save and exit
cv2.imwrite('final image',final_image)
cv2.destroyAllWindows()
Now the part i'm currently stuck in is that here in Matlab code, I have lab_he(:,:,2:3) which means all the rows and all the columns from depth 2 and 3. However when I try to replicate that in Python img2a = img2.shape[2][1:2] but it doesn't work or makes sense. Please help.
In Octave/MATLAB
octave:29> x=reshape(1:(2*3*4),3,2,4);
octave:30> x(:,:,2:3)
ans =
ans(:,:,1) =
7 10
8 11
9 12
ans(:,:,2) =
13 16
14 17
15 18
octave:31> size(x(:,:,2:3))
ans =
3 2 2
octave:33> x(:,:,2:3)(2,2,:)
ans(:,:,1) = 11
ans(:,:,2) = 17
In numpy:
In [13]: x=np.arange(1,1+2*3*4).reshape(3,2,4,order='F')
In [14]: x[:,:,1:3]
Out[14]:
array([[[ 7, 13],
[10, 16]],
[[ 8, 14],
[11, 17]],
[[ 9, 15],
[12, 18]]])
In [15]: _.shape
Out[15]: (3, 2, 2)
In [17]: x[:,:,1:3][1,1,:]
Out[17]: array([11, 17])
Or with numpy normal 'C' ordering, and indexing on the 1st dimension
In [18]: y=np.arange(1,1+2*3*4).reshape(4,2,3)
In [19]: y[1:3,:,:]
Out[19]:
array([[[ 7, 8, 9],
[10, 11, 12]],
[[13, 14, 15],
[16, 17, 18]]])
In [20]: y[1:3,:,:][:,1,1]
Out[20]: array([11, 17])
Same indexing ideas, though matching numbers and shapes requires some care, not only with the 0 v 1 index base. A 3d array is displayed in a different arangement. Octave divides it into blocks on the last index (its primary iterator), numpy iterates on the first index.
In 3d it makes more sense to talk about first, 2nd, 3rd dimensions rather than row,col,depth. In 4d you run out of names. :)
I had to reshape array at specific depth, and I programmed a little recursive function to do so:
def recursive_array_cutting(tab, depth, i, min, max):
if(i==depth):
tab = tab[min:max]
return tab
temp_list = []
nb_subtab = len(tab)
for index in range(nb_subtab):
temp_list.append(recursive_array_cutting(tab[index], depth, i+1, min, max))
return np.asanyarray(temp_list)
It allow to get all array/values between the min and the max of a specific depth, for instance, if you have a (3, 4) tab = [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]] and only want the last two values of the deepest array, you call like this : tab = recursive_array_cutting(tab, 1, 0, 0, 2) to get the output : [[0 1][0 1][0 1]].
If you have a more complexe array like this tab = [[[0, 1, 2, 3], [1, 1, 2, 3], [2, 1, 2, 3]], [[0, 1, 2, 3], [1, 1, 2, 3], [2, 1, 2, 3]], [[0, 1, 2, 3], [1, 1, 2, 3], [2, 1, 2, 3]]] (3, 3, 4) and want a (3, 2, 4) array, you can call like this : tab = recursive_array_cutting(tab, 1, 0, 0, 2) to get this output, and get rid of the last dimension in depth 1.
Function like this surely exist in numpy, but I did not found it.

Categories

Resources