I have raw image data stored in a text file, in a format like this and I would like to make it a 2D array and convert it to grayscale.
0
0
0
0
24
243
227
223
224
225
227
228
228
What I would like to do is take this data, convert it to grayscale, and display the image. My plan is to use numpy...I have this working in matlab, but I'm having difficulty implementing it in python
I have tried to do the following:
import numpy as np
from PIL import Image
from pylab import *
ROWS = 144
COLUMNS = 175
raw_image = []
lines = [line.strip().split(',') for line in open('CAMERA.txt')
for i in lines:
raw_image.append(i)
mat_image = np.zeros((ROWS, COLUMNS), dtype = int)
for i in rage(ROWS):
for j in range(COLUMNS):
mat_image.itemset(i, j, raw_image[(i-1)*COLUMNS + j])
plt.gray()
axes = app.image.add_subplot(111)
self.im = Image.fromarray(mat_image)
axes.imshow(self.im)
app.imageCanvas.draw()
I've also tried doing:
np.reshape(raw_image, ROWS, COLUMNS)
However neither of these approaches work. Does anyone have any suggestions?
Thanks in advance.
The program below could do what you want if I correctly interpreted what you want to do ;-)
import numpy as np
import matplotlib.pyplot as plt
if __name__=='__main__':
rows = 144
columns = 175
camera_image = np.loadtxt(r'path/to/filename')
if(not camera_image.size == rows * columns):
raise Exception('Size mismatch!')
my_image = np.reshape(camera_image, (rows, columns)) / 255.0
figure = plt.figure()
axes = figure.add_subplot(1, 1, 1)
axes.imshow(my_image)
plt.show()
Kind regards
Here's a pretty simple method of going from text integers to PIL image that works for me:
import numpy as np
from PIL import Image
ROWS = 50
COLUMNS = 50
# greyValues.txt is 2500 RGB values 0-255 one per line
arr = np.genfromtxt('greyValues.txt', dtype=np.int8)
arr.shape = (ROWS, COLUMNS)
img = Image.fromarray(arr, 'L')
img.show()
img.save("textimage.jpg")
Related
I'm trying to sort an image by luminosity using NumPy, which I'm new to. I've managed to create a random image and sort it.
def create_image(output, width, height, arr):
array = np.zeros([height, width, 3], dtype=np.uint8)
numOfSwatches = len(arr)
swatchWidth = int(width/ numOfSwatches)
for i in range (0, numOfSwatches):
m = i * swatchWidth
r = (i+1) * swatchWidth
array[:, m:r] = arr[i]
img = Image.fromarray(array)
img.save(output)
Which creates this image:
So far so good. Only now I want to switch from creating random images to loading them and then sorting them.
#!/usr/bin/python3
import numpy as np
from PIL import Image
# --------------------------------------------------------------
def load_image( infilename ) :
img = Image.open( infilename )
img.load()
data = np.asarray( img, dtype = "int32" )
return data
# --------------------------------------------------------------
def lum (r,g,b):
return math.sqrt( .241 * r + .691 * g + .068 * b )
myImageFile = "random_colours.png"
imageNP = load_image(myImageFile)
imageNP.sort(key=lambda rgb: lum(*rgb) )
The image should look like this:
The error I get is TypeError: 'key' is an invalid keyword argument for this function I may have created the NP array incorrectly as it worked when it was a random NP array.
Have not ever used PIL, but the following approach hopefully works (I'm not sure as I can't reproduce your exact examples), and of course there might be more efficient ways to do so.
I'm using your functions, having changed the math.sqrt function to np.sqrt in the lum function - as it is better for vector calculations. By the way, I believe this won't work with an int32 type array (as in your load_image function).
The key part is Numpy's argsort function (last line), which gives the indices that would sort the given array; this is applied to a row of the luminosity array (exploiting simmetry) and later used as indexer of img_array.
# Create random image
np.random.seed(4)
img = create_image('test.png', 75, 75, np.random.random((25,3))*255)
# Convert to Numpy array and calculate luminosity
img_array = np.array(img, dtype = np.uint8)
luminosity = lum(img_array[...,0], img_array[...,1], img_array[...,2])
# Sort by luminosity and convert to image again
img_sorted = Image.fromarray(img_array[:,luminosity[0].argsort()])
The original picture:
And the luminosity-sorted one:
I have an image of dimension 155 x 240. Like the following:
I want to extract certain shape of patchs (25 x 25).
I don't want to patch from the whole image.
I want to extract N number of patch from non-zero (not background) area of the image. How can I do that? Any idea or suggestion or implementation will be appreciated. You can try with either Matlab or Python.
Note:
I have generated a random image so that you can process it for patching. image_process variable is that image in this code.
import numpy as np
from scipy.ndimage.filters import convolve
import matplotlib.pyplot as plt
background = np.ones((155,240))
background[78,120] = 2
n_d = 50
y,x = np.ogrid[-n_d: n_d+1, -n_d: n_d+1]
mask = x**2+y**2 <= n_d**2
mask = 254*mask.astype(float)
image_process = convolve(background, mask)-sum(sum(mask))+1
image_process[image_process==1] = 0
image_process[image_process==255] = 1
plt.imshow(image_process)
Lets assume that the pixels values you want to omit is 0.
In this case what you could do, is first find the indices of the non-zero values, then slice the image in the min/max position to get only the desired area, and then simply apply extract_patches_2d with the desired window size and number of patches.
For example, given the dummy image you supplied:
import numpy as np
from scipy.ndimage.filters import convolve
import matplotlib.pyplot as plt
background = np.ones((155,240))
background[78,120] = 2
n_d = 50
y,x = np.ogrid[-n_d: n_d+1, -n_d: n_d+1]
mask = x**2+y**2 <= n_d**2
mask = 254*mask.astype(float)
image_process = convolve(background, mask)-sum(sum(mask))+1
image_process[image_process==1] = 0
image_process[image_process==255] = 1
plt.figure()
plt.imshow(image_process)
plt.show()
from sklearn.feature_extraction.image import extract_patches_2d
x, y = np.nonzero(image_process)
xl,xr = x.min(),x.max()
yl,yr = y.min(),y.max()
only_desired_area = image_process[xl:xr+1, yl:yr+1]
window_shape = (25, 25)
B = extract_patches_2d(only_desired_area, window_shape, max_patches=100) # B shape will be (100, 25, 25)
If you plot the only_desired_area you will get the following image:
This is the main logic if you wish an even tighter bound you should adjust the slicing properly.
i use this code to resize 3d nifti data but when i check the result i found it messy and the axes are changed
import numpy as np
import nibabel as nib
import itertools
initial_size_x = 560
initial_size_y = 560
initial_size_z = 240
new_size_x = 512
new_size_y = 512
new_size_z = 216
initial_data = nib.load("id001-512x512x216.nii.gz-pred.nii").get_data()
print('helooooooooooooooooooo')
delta_x = initial_size_x/new_size_x
delta_y = initial_size_y/new_size_y
delta_z = initial_size_z/new_size_z
new_data = np.zeros((new_size_x,new_size_y,new_size_z))
for x, y, z in itertools.product(range(new_size_x),
range(new_size_y),
range(new_size_z)):
new_data[x][y][z] = initial_data[int(x*delta_x)][int(y*delta_y)][int(z*delta_z)]
img = nib.Nifti1Image(new_data, np.eye(4))
img.to_filename("test_"+str(new_size_x)+""+str(new_size_y)+""+str(new_size_z)+".nii")
enter image description here
In this question, I believe you want to slightly change the resolution of 3D data. The solution I am presenting only works for enlarging or shrinking the data an integer number of times.
For enlarging the data, you can use np.repeat and for shrinking it you can use slicing. For example, here we can write:
import numpy as np
import nibabel as nib
import itertools
initial_size_x = 560
initial_size_y = 560
initial_size_z = 240
new_size_x = 1120
new_size_y = 1120
new_size_z = 720
initial_data = nib.load("id001-512x512x216.nii.gz-pred.nii").get_data()
rep_x = new_size_x/initial_size_x # 2
rep_y = new_size_y/initial_size_y # 2
rep_z = new_size_z/initial_size_z # 3
new_data = np.repeat(initial_data, rep_x, axis=0)
new_data = np.repeat(new_data, rep_y, axis=1)
new_data = np.repeat(new_data, rep_z, axis=2)
Possible improvements
I am sure this answer can be improved. However I am not sure what you have in mind from a floating point repetition.
For instance, should my_repeat(data, 0.9, axis=axis) skip every 10th element?
I’m trying to extract dicom PixelData from Siemens’ dose report but it contains only zeros. With GE dose report I read the data without a trouble with pydicom or simpleITK. Any ideas why siemens report contains only zeros?
Thanks!
Came this far, but characters are a mess, I don't know what else to do.
import dicom
import numpy as np
import matplotlib.pyplot as plt
f="patient-protocol.dcm"
ds=dicom.read(f)
overlay_px_data = ds[0x6000, 0x3000].value
rows = ds[0x6000, 0x0010].value
cols=ds[0x6000, 0x0011].value
arr=np.fromstring(overlay_px_data, dtype="uint8")
arr=np.unpackbits(arr)
arr=np.reshape(arr, (rows, cols))
plt.imshow(arr, cmap="gray")
plt.show()
dose-image
i_overlay = 1
n_bits = 8
# On (60xx,3000) are stored ovelays.
# First is (6000,3000), second (6002,3000), third (6004,3000),
# and so on.
dicom_tag1 = 0x6000 + 0*i_overlay
overlay_raw = data[0x6000,0x3000].value
# On (60xx,0010) and (60xx,0011) is stored overlay size
rows = data[0x6000,0x0010].value # rows = 512
cols = data[0x6000,0x0011].value # cols = 512
decoded_linear = np.zeros(len(overlay_raw)*n_bits)
# Decoding data. Each bit is stored as array element
for i in range(1,len(overlay_raw)):
for k in range (0,n_bits):
byte_as_int = overlay_raw[i]
decoded_linear[i*n_bits + k] = (byte_as_int >> k) & 0b1
overlay = np.reshape(decoded_linear,[rows,cols])
plt.imshow(overlay)
plt.show()
Found the solution for now. Edited a code a bit (removed ord()), a numpy decoding solution would be great/better.
code source link
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
data = pd.read_csv('fer2013.csv')
data.head()
face1 = np.fromstring(data['pixels'][0], dtype=int, sep=' ')
exp1 = np.zeros((48,48))
k = 0
for i in range(len(exp1)):
for j in range(len(exp1[0])):
exp1[i][j] = face1[k]
k = k + 1
imgplot = plt.imshow(exp1, cmap="Greys_r")
plt.show()
mpimg.imsave('save.png', exp1)
The images are 48 x 48 pixels represented as a string ("12 34 12 34 55 ... "). So the first value in the string corresponds to the first pixel value.
Hence, my question is: How do I convert the string of space separated pixel values to columns of features that I can use to train an SVM classifier with and why is the image not greyscale??? The training part I can do for myself.
There are 35887 training examples denoting 7 different expressions so i need an efficient way of doing this.
P.S. The problem originated from attempting Challenges in Representation Learning: Facial Expression Recognition Challenge (Kaggle.com)
You should show current attempts/ research you've done already to solve the problem when positing questions on SO.
You can load an image in Python easily using OpenCV, the result img is a numpy array, so you can just print it as a string e.g.
import numpy as np
import cv2
# Load image
img = cv2.imread('image.jpg',0)
print img
Update after question revision:
If you want to just convert the string of numbers to an image, you can use something like the following:
import numpy as np
image = '1 2 3 4 5 6'
image_width, image_height = 2, 3
result = np.fromstring(image, dtype=int, sep=" ").reshape((image_height, image_width))
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from sklearn import svm, metrics
#Read csv file
data = pd.read_csv('fer2013.csv')
#Number of samples
n_samples = len(data)
n_samples_train = 28709
n_samples_test = 3589
n_samples_validation = 3589
#Pixel width and height
w = 48
h = 48
#Separating labels and features respectively
y = data['emotion']
X = np.zeros((n_samples, w, h))
for i in range(n_samples):
X[i] = np.fromstring(data['pixels'][i], dtype=int, sep=' ').reshape(w, h)
#Training set
X_train = X[:n_samples_train].reshape(n_samples_train, -1)
y_train = y[:n_samples_train]
#Classifier
clf = svm.SVC(gamma=0.001, kernel='rbf', class_weight='balanced')
print('Training Classifier...')
clf.fit(X_train, y_train)
print('Done!!!')
#Testing set
X_test = X[n_samples_train : (n_samples_train + n_samples_test)].reshape(n_samples_test, -1)
y_test = y[n_samples_train : (n_samples_train + n_samples_test)]
#Prediction
expected = y_test
predicted = clf.predict(X_test)
#Results
print("Classification report for classifier %s:\n%s\n" % (clf, metrics.classification_report(expected, predicted)))
Here is my solution! Kindly let me know if certain things that can be done more efficiently. Thank you mark and tom for all your help.
import pandas as pd
dataset_path = './fer2013/fer2013.csv'
image_size=(48,48)
def load_fer2013():
data = pd.read_csv(dataset_path)
pixels = data['pixels'].tolist()
width, height = 48, 48
faces = []
for pixel_sequence in pixels:
face = [int(pixel) for pixel in pixel_sequence.split(' ')]
face = np.asarray(face).reshape(width, height)
face = cv2.resize(face.astype('uint8'),image_size)
faces.append(face.astype('float32'))
faces = np.asarray(faces)
faces = np.expand_dims(faces, -1)
emotions = pd.get_dummies(data['emotion']).as_matrix()
return faces, emotions
faces, emotions = load_fer2013()
xtrain, xtest,ytrain,ytest = train_test_split(faces, emotions,test_size=0.2,shuffle=True)
This code is very simple it loops over the the pixel rows in the csv file, return the int pixels separated by ' ' to face convert it to an np array then to an image with cv2 and stack all the faces in a list