How to create a tuple with the same shape of another one - python

I'm trying to augment my data for a CCN problem.
I have a csv with 3 image (center, left, right) and a steering angle which is the same for all the three images. (I used the Udacity self driving car simulator).
I want to increase my data, so I'm trying to do augmentation on my image.
I need to create a tuple with a shape like this:
image_path = data[["center", "left", "right"]].values
But before, I have to augment my data.
That's my code:
steerings = data["steering"].values
steerings = list(steerings)
center = data["center"].values
left = data["left"].values
right = data["right"].values
center = list(center)
new_center = []
left = list(left)
new_left = []
right = list(right)
new_right = []
new_steerings = []
for index in range(len(center)):
new_center_img = augment_image(center[index], steerings[index])[0]
new_center.append(new_center_img)
new_left_img = augment_image(left[index], steerings[index])[0]
new_left.append(new_left_img)
new_right_img = augment_image(right[index], steerings[index])[0]
new_right.append(new_right_img)
new_steerings.append(steerings[index])
center.extend(new_center)
left.extend(new_left)
right.extend(new_right)
steerings.extend(new_steerings)
image_path = tuple(center), tuple(left), tuple(right)
steerings = tuple(steerings)
return train_test_split(image_path, steerings, test_size=0.2, random_state=1)
But:
image_path = tuple(center), tuple(left), tuple(right)
is not the same as:
image_path = data[["center", "left", "right"]].values
How can I obtain the same thing when I return image path, but with double images due to augmentation?

If I understand correctly, I think you just need to do:
image_path = np.stack([center, left, right], axis=1)
Where np is NumPy.

Related

Python + Image Processing: Efficiently Assign Pixel Values to Nearest Predefined Value

I implemented an algorithm that uses opencv kmeans to quantize the unique brightness values present in a greyscale image. Quantizing the unique values helped avoid biases towards image backgrounds which are typically all the same value.
However, I struggled to find a way to utilize this data to quantize a given input image.
I implemented a very naive solution, but it is unusably slow for the required input sizes (4000x4000):
for x in range(W):
for y in range(H):
center_id = np.argmin([(arr[y,x]-center)**2 for center in centers])
ret_labels2D[y,x] = sortorder.index(center_id)
ret_qimg[y,x] = centers[center_id]
Basically, I am simply adjusting each pixel to the predefined level with the minimum squared error.
Is there any way to do this faster? I was trying to process an image of size 4000x4000 and this implementation was completely unusable.
Full code:
def unique_quantize(arr, K, eps = 0.05, max_iter = 100, max_tries = 20):
"""#param arr: 2D numpy array of floats"""
H, W = arr.shape
unique_values = np.squeeze(np.unique(arr.copy()))
unique_values = np.array(unique_values, float)
if unique_values.ndim == 0:
unique_values = np.array([unique_values],float)
unique_values = np.ravel(unique_values)
unique_values = np.expand_dims(unique_values,1)
Z = unique_values.astype(np.float32)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,max_iter,eps)
compactness, labels, centers = cv2.kmeans(Z,K,None,criteria,max_tries,cv2.KMEANS_RANDOM_CENTERS)
labels = np.ravel(np.squeeze(labels))
centers = np.ravel(np.squeeze(centers))
sortorder = list(np.argsort(centers)) # old index --> index to sortorder
ret_center = centers[sortorder]
ret_labels2D = np.zeros((H,W),int)
ret_qimg = np.zeros((H,W),float)
for x in range(W):
for y in range(H):
center_id = np.argmin([(arr[y,x]-center)**2 for center in centers])
ret_labels2D[y,x] = sortorder.index(center_id)
ret_qimg[y,x] = centers[center_id]
return ret_center, ret_labels2D, ret_qimg
EDIT: I looked at the input file again. The size was actually 12000x12000.
As your image is grayscale (presumably 8 bits), a lookup-table will be an efficient solution. It suffices to map all 256 gray-levels to the nearest center once for all, then use this as a conversion table. Even a 16 bits range (65536 entries) would be significantly accelerated.
I recently thought of a much better answer. This code is not extensively tested, but it worked for the use case in my project.
I made use of obscure fancy-indexing techniques in order to keep the entire algorithm contained within numpy functions.
def unique_quantize(arr, K, eps = 0.05, max_iter = 100, max_tries = 20):
"""#param arr: 2D numpy array of floats"""
H, W = arr.shape
unique_values = np.squeeze(np.unique(arr.copy()))
unique_values = np.array(unique_values, float)
if unique_values.ndim == 0:
unique_values = np.array([unique_values],float)
unique_values = np.ravel(unique_values)
unique_values = np.expand_dims(unique_values,1)
Z = unique_values.astype(np.float32)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,max_iter,eps)
compactness, labels, centers = cv2.kmeans(Z,K,None,criteria,max_tries,cv2.KMEANS_RANDOM_CENTERS)
labels = np.ravel(np.squeeze(labels))
centers = np.ravel(np.squeeze(centers))
sortorder = np.argsort(centers) # old index --> index to sortorder
inverse_sortorder = np.array([list(sortorder).index(i) for i in range(len(centers))],int)
ret_center = centers[sortorder]
ret_labels2D = np.zeros((H,W),int)
ret_qimg = np.zeros((H,W),float)
errors = [np.power((arr-center),2) for center in centers]
errors = np.array(errors,float)
classification = np.squeeze(np.argmin(errors,axis=0))
ret_labels2D = inverse_sortorder[classification]
ret_qimg = centers[classification]
return np.array(ret_center,float), np.array(ret_labels2D,int), np.array(ret_qimg,float)

How to speed up matplotlib animation made from database results?

I'm using matplotlib to make contourplots over some maps I have stored in a database but the process is taking several hours to produce each movie. The code I'm using to make this movie is:
def load_img(option, obs_id, columnshape):
'''
This function will load the image
from the database and make the
conversion from string to nparray
'''
#starting a db session
session = makesession()
#defining the cases to query the db
case = {'Bz': Observations.mean_bz,
'Es': Observations.poyn_Es,
'En': Observations.poyn_En,
'Et': Observations.poyn_Et}
#checking if the option selected was
#a valid one
while option not in case.keys():
#feedback
print('Invalid option. Select a valid one: ', case.keys())
option = str(input())
#querying the db
s = sql.select([case[option]]).where(Observations.id == obs_id)
#fetching the result
rp = session.execute(s)
result = rp.fetchone()
#restoring the image
img = ajuste(result[0],columnshape)
return(img)
def db_animation(ar_id, option):
'''
Description
'''
vmin = -1e17
vmax = 1e17
levels = [vmin, 0.8*vmin, 0.6*vmin, 0.4*vmin, 0.2*vmin,
0.2*vmax, 0.4*vmax, 0.6*vmax,0.8*vmax,vmax]
#getting the observation ids
obs_ids = scout_obs_ids(ar_id)
#obs_ids = [x for x in range(400,450)]
#getting the columnshape
columnshape = scout_colshape(obs_ids[0])
#creating the figure objects
fig, ax = plt.subplots(figsize = (12,8))
#loading the first data
data_bz = load_img('Bz', obs_ids[0], columnshape)
data_E = load_img(option, obs_ids[0], columnshape)
#making the image objects
img1 = ax.imshow(data_bz, origin = 'lower', cmap = plt.cm.gray,
animated = True)
img2 = [ax.contourf(data_E, alpha = 0.35,
#vmax = 1e17, vmin = -1e17,
levels = levels,
origin = 'lower',
cmap = 'PiYG')]
#adding a colorbar
fig.colorbar(img2[0], shrink = 0.75, label = 'W')
def refresher(frame_number, img1,img2):
'''
description
'''
#taking the new data
new_data_bz = load_img('Bz', obs_id = obs_ids[frame_number+1],
columnshape = columnshape)
new_data_E = load_img(option, obs_id = obs_ids[frame_number+1],
columnshape = columnshape)
#setting the new data
img1.set_data(new_data_bz)
#removing the contours to start anew
for tp in img2[0].collections:
tp.remove()
img2[0] = ax.contourf(new_data_E, alpha = 0.35,
levels = levels,
origin = 'lower', cmap = 'PiYG')
return(img1, img2[0].collections,)
#using the animation function
ani = FuncAnimation(fig, refresher,
frames=range(len(obs_ids)-1),
interval = 100,
#blit = True,
fargs = [img1,img2])
#saving
ani.save("test.mp4")
return
On average those movies take 1200 images for each img object (a total around 2400) from the database. Each pair of images are individually loaded and restored to make the background image and the contour plot.
I was wondering about reasons why the processing time was escalating quickly as I increase the number of images to make the movie but could not get to a conclusion on my own. I find it particularly intriguing that when I set blit to True (which according to the documentation should help improve performance) I get the following error:
AttributeError: 'silent_list' object has no attribute 'set_animated'
I imagine that either my queries or the way I constructed my animation function are then highly inefficient. But I suspect more on the latter since when I'm normally using the DB the results are loaded in what I imagine is a reasonable time.
Can someone cast some light at this struggle for me?

Pandas data layout issue

Trying to put an images pixel data into a pandas data frame to tun PCA across. I think I got it working but for some reason the layout is off. When I run the following code I get this result :
#read in image
img = cv2.imread('/Volumes/EXTERNAL/Stitched-Photos-for-Chris/p7_0015_20161005-949am-75m-pass-1.jpg.png',1)
row,col = img.shape[:2]
#print(row , col)
#get a unique pixel ID for each pixel
pixel = ['pixel-' + str(i) for i in range(0,row*col)]
bBand = ['bBand']
gBand = ['gBand']
rBand = ['rBand']
data = pd.DataFrame(columns=[bBand,gBand,rBand],index = pixel)
#populate data for each band
b,g,r = cv2.split(img)
data.loc[pixel,'bBand'] = b.flat[:]
data.loc[pixel,'gBand'] = g.flat[:]
data.loc[pixel,'rBand'] = r.flat[:]
print(data.head())
However, when I run the tutorial code I am basing this off I get the proper format:
genes = ['gene' + str(i) for i in range(1,101)]
wt = ['wt' + str(i) for i in range(1,6)]
ko = ['ko' + str(i) for i in range(1,6)]
data = pd.DataFrame(columns=[*wt,*ko],index = genes)
#create random data
for gene in genes:
data.loc[gene,'wt1':'wt5'] = np.random.poisson(lam=rd.randrange(10,10000),size=5)
data.loc[gene,'ko1':'ko5'] = np.random.poisson(lam=rd.randrange(10,10000),size=5)
print(data.head())
Trying to figure out if the extra gBand and rBand in the columns is an issuer or error that I have somewhere. Thanks for your help.
it looks like you are creating your columns incorrectly by making them a list
try:
pixel = ['pixel-' + str(i) for i in range(0,row*col)]
data = pd.DataFrame(columns=['bBand','gBand','rBand'],index = pixel)
#populate data for each band
b,g,r = cv2.split(img)
data.loc[pixel,'bBand'] = b.flat[:]
data.loc[pixel,'gBand'] = g.flat[:]
data.loc[pixel,'rBand'] = r.flat[:]
print(data.head())

How to vectorize a code with python numpy.bincount, using apply along axis

I'm trying to vectorize a code with numpy, to run it using multiprocessing, but i can't understand how numpy.apply_along_axis works. This is an example of the code, vectorized using map
import numpy
from scipy import sparse
import multiprocessing
from matplotlib import pyplot
#first i build a matrix of some x positions vs time datas in a sparse format
matrix = numpy.random.randint(2, size = 100).astype(float).reshape(10,10)
x = numpy.nonzero(matrix)[0]
times = numpy.nonzero(matrix)[1]
weights = numpy.random.rand(x.size)
#then i define an array of y positions
nStepsY = 5
y = numpy.arange(1,nStepsY+1)
#now i build an image using x-y-times coordinates and x-times weights
def mapIt(ithStep):
ncolumns = 80
image = numpy.zeros(ncolumns)
yTimed = y[ithStep]*times
positions = (numpy.round(x-yTimed)+50).astype(int)
values = numpy.bincount(positions,weights)
values = values[numpy.nonzero(values)]
positions = numpy.unique(positions)
image[positions] = values
return image
image = list(map(mapIt, range(nStepsY)))
image = numpy.array(image)
a = pyplot.imshow(image, aspect = 10)
Here the output plot
I tried to use numpy.apply_along_axis, but this function allows me to iterate only along the rows of image, while i need to iterate along the ithStep index too. E.g.:
#now i build an image using x-y-times coordinates and x-times weights
nrows = nStepsY
ncolumns = 80
matrix = numpy.zeros(nrows*ncolumns).reshape(nrows,ncolumns)
def applyIt(image):
image = numpy.zeros(ncolumns)
yTimed = y[ithStep]*times
positions = (numpy.round(x-yTimed)+50).astype(int)
values = numpy.bincount(positions,weights)
values = values[numpy.nonzero(values)]
positions = numpy.unique(positions)
image[positions] = values
return image
imageApplied = numpy.apply_along_axis(applyIt,1,matrix)
a = pyplot.imshow(imageApplied, aspect = 10)
It obviously return only the firs row nrows times, since nothing iterates ithStep:
And here the wrong plot
There is a way to iterate an index, or to use an index while numpy.apply_along_axis iterates?
Here the code with only matricial operations: it's quite faster than map or apply_along_axis but uses so much memory.
(in this function i use a trick with scipy.sparse, which works more intuitively than numpy arrays when you try to sum numbers on a same element)
def fullmatrix(nRows, nColumns):
y = numpy.arange(1,nStepsY+1)
image = numpy.zeros((nRows, nColumns))
yTimed = numpy.outer(y,times)
x3d = numpy.outer(numpy.ones(nStepsY),x)
weights3d = numpy.outer(numpy.ones(nStepsY),weights)
y3d = numpy.outer(y,numpy.ones(x.size))
positions = (numpy.round(x3d-yTimed)+50).astype(int)
matrix = sparse.coo_matrix((numpy.ravel(weights3d), (numpy.ravel(y3d), numpy.ravel(positions)))).todense()
return matrix
image = fullmatrix(nStepsY, 80)
a = pyplot.imshow(image, aspect = 10)
This way is simplier and very fast! Thank you so much.
nStepsY = 5
nRows = nStepsY
nColumns = 80
y = numpy.arange(1,nStepsY+1)
image = numpy.zeros((nRows, nColumns))
fakeRow = numpy.zeros(positions.size)
def itermatrix(ithStep):
yTimed = y[ithStep]*times
positions = (numpy.round(x-yTimed)+50).astype(int)
matrix = sparse.coo_matrix((weights, (fakeRow, positions))).todense()
matrix = numpy.ravel(matrix)
missColumns = (nColumns-matrix.size)
zeros = numpy.zeros(missColumns)
matrix = numpy.concatenate((matrix, zeros))
return matrix
for i in numpy.arange(nStepsY):
image[i] = itermatrix(i)
#or, without initialization of image:
imageMapped = list(map(itermatrix, range(nStepsY)))
imageMapped = numpy.array(imageMapped)
It feels like attempting to use map or apply_along_axis is obscuring the essentially iteration of the problem.
I rewrote your code as an explicit loop on y:
nStepsY = 5
y = numpy.arange(1,nStepsY+1)
image = numpy.zeros((nStepsY, 80))
for i, yi in enumerate(y):
yTimed = yi*times
positions = (numpy.round(x-yTimed)+50).astype(int)
values = numpy.bincount(positions,weights)
values = values[numpy.nonzero(values)]
positions = numpy.unique(positions)
image[i, positions] = values
a = pyplot.imshow(image, aspect = 10)
pyplot.show()
Looking at the code, I think I could calculate positions for all y values making a (y.shape[0],times.shape[0]) array. But the rest, the bincount and unique still have to work row by row.
apply_along_axis when working with a 2d array, and axis=1 essentially does:
res = np.zeros_like(arr)
for i in range....:
res[i,:] = func1d(arr[i,:])
If the input array has more dimensions it constructs a more elaborate indexing object [i,j,k,:]. And it can handle cases where func1d returns a different size array than the input. But in any case it is just a generalized iteration tool.
Moving the initial positions creation outside the loop:
yTimed = y[:,None]*times
positions = (numpy.round(x-yTimed)+50).astype(int)
image = numpy.zeros((positions.shape[0], 80))
for i, pos in enumerate(positions):
values = numpy.bincount(pos,weights)
values = values[numpy.nonzero(values)]
pos = numpy.unique(pos)
image[i, pos] = values
Now I can cast this as an apply_along_axis problem, with an applyIt that takes a positions vector (with all the yTimed information) rather than blank image vector.
def applyIt(pos, size, weights):
acolumn = numpy.zeros(size)
values = numpy.bincount(pos,weights)
values = values[numpy.nonzero(values)]
pos = numpy.unique(pos)
acolumn[pos] = values
return acolumn
image = numpy.apply_along_axis(applyIt, 1, positions, 80, weights)
Timing wise I expect it's a bit slower than my explicit iteration. It has to do more setup work, including a test call applyIt(positions[0,:],...) to determine the size of its return array (i.e image has different shape than positions.)
def csrmatrix(y, times, x, weights):
yTimed = numpy.outer(y,times)
n=y.shape[0]
x3d = numpy.outer(numpy.ones(n),x)
weights3d = numpy.outer(numpy.ones(n),weights)
y3d = numpy.outer(y,numpy.ones(x.size))
positions = (numpy.round(x3d-yTimed)+50).astype(int)
#print(y.shape, weights3d.shape, y3d.shape, positions.shape)
matrix = sparse.csr_matrix((numpy.ravel(weights3d), (numpy.ravel(y3d), numpy.ravel(positions))))
#print(repr(matrix))
return matrix
# one call
image = csrmatrix(y, times, x, weights)
# iterative call
alist = []
for yi in numpy.arange(1,nStepsY+1):
alist.append(csrmatrix(numpy.array([yi]), times, x, weights))
def mystack(alist):
# concatenate without offset
row, col, data = [],[],[]
for A in alist:
A = A.tocoo()
row.extend(A.row)
col.extend(A.col)
data.extend(A.data)
print(len(row),len(col),len(data))
return sparse.csr_matrix((data, (row, col)))
vimage = mystack(alist)

SVM with openCV & Python

I'm tryint to build an application that classifies different objects. I have a training folder with a bunch of images i want to use as training for my SVM.
Up untill now I have followed this (GREAT) answer:
using OpenCV and SVM with images
here is a sample of my code:
def getTrainingData():
address = "..//data//training"
labels = []
trainingData = []
for items in os.listdir(address):
## extracts labels
name = address + "//" + items
for it in os.listdir(name):
path = name + "//" + it
print path
img = cv.imread(path, cv.CV_LOAD_IMAGE_GRAYSCALE)
d = np.array(img, dtype = np.float32)
q = d.flatten()
trainingData.append(q)
labels.append(items)
######DEBUG######
#cv.namedWindow(path,cv.WINDOW_NORMAL)
#cv.imshow(path,img)
return trainingData, labels
svm_params = dict( kernel_type = cv.SVM_LINEAR,
svm_type = cv.SVM_C_SVC,
C=2.67, gamma=3 )
training, labels = getTrainingData()
train = np.asarray(training)
svm = cv.SVM()
svm.train(train, labels, params=svm_params)
svm.save('svm_data.dat')
But when i try to run i recieve the following error:
svm.train(train, labels, params=svm_params)
TypeError: trainData data type = 17 is not supported
What am i doing wrong?
Thanks A lot!
You should resize your input images. like this:
img = cv2.resize(img, (64,64))
Size is up to you.

Categories