How to iteratively load read_pixel and write to envi file; python3 - python

I want to load hyperspectral data per pixel into an array and write this pixel out again using Python 3.5. I want to calculate something with the spectral information of this Pixel.
I have tried two different ways and both don't work the way I want.
First of all I have updated spectral package since the last version was stated not to work with iteratively envi.save_image but still my approach does not work.
Second my approaches both are not very good with my double for loop - I know -
If anyone could please help me on my problem.
1st:
myfile=open_image('input.hdr')
for i in range(0,myfile.shape[0]):
for j in range(0,myfile.shape[1]):
mypixel = (myfile.read_pixel(i,j))
envi.save_image('output.hdr', mypixel, dtype=np.int16)
1st example does not save the image rather gives me the error code
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.5/site-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 699, in runfile
execfile(filename, namespace)
File "/usr/local/lib/python3.5/site-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 88, in execfile
exec(compile(open(filename, 'rb').read(), filename, 'exec'), namespace)
File "/dtc/Python/Masking.py", line 132, in <module>
envi.save_image('test.hdr', mypixel, dtype=np.int16)#, metadata=myfile.metadata)
File "/usr/local/lib/python3.5/site-packages/spectral/io/envi.py", line 415, in save_image
data, metadata = _prepared_data_and_metadata(hdr_file, image, **kwargs)
File "/usr/local/lib/python3.5/site-packages/spectral/io/envi.py", line 568, in _prepared_data_and_metadata
add_image_info_to_metadata(image, metadata)
File "/usr/local/lib/python3.5/site-packages/spectral/io/envi.py", line 613, in add_image_info_to_metadata
metadata['samples'] = image.shape[1]
IndexError: tuple index out of range
2nd:
myfile=open_image('input.hdr')
envi.create_image('test.hdr',ext='.bip', interleave='bip',dtype='h',force=True,metadata=myfile.metadata)
open('test.bip', 'w').close() # empties the created file
file = open('test.bip', 'ab')#ab #opens the created file for appending the new bands
for i in range(0,myfile.shape[0]):
for j in range(0,myfile.shape[1]):
mypixel = (myfile.read_pixel(i,j))
file.write(mypixel)
file.close()
myfile.close()
The second example saves the image but stores the Pixel in a different order and messes up my image.

So this is the very short, fast and easy solution thanks to a colleague.
myfile=envi.open('input.hdr') #opens image for calculating with it
imageArray = 10000*myfile[:,:,:] #do some math with it;
#10000* is needed because input data are thresholded between {0;10000}
#and during processing get thresholded between {0;1}.
#For preventing 0 in the output with datatype int the thresholding to {0;10000} is necessary again
envi.save_image('test.hdr',imageArray,dtype=np.int16,metadata=myfile.metadata,force=True)

I have to say in advance that I am not familiar with the spectral package and envi and therefore unfortunately cannot offer a ready-to-use solution. Besides, I am not sure if I correctly understood what you are trying to do with your image.
But just some thoughts: Could the write/save function inside the for loop cause your problem, because every pixel is treated in the exact same way and it gets overwritten? I can not relate to the IndexError though.
Maybe you need a function where you can rather write a certain pixel to an empty image passing also i and j. A second option could be to save each pixel in an array and save it to an image at once after the for loop.

Related

How to get seams of a color image in OpenCV2 in Python?

I am writing a bit of code to allow me to remove seams from an image. Currently, my code allows me to find, highlight, and remove seams from a greyscale image. I am needing to remove seams from colored images and my code will not allow me to do that. Can anyone help me modify my code to allow me to do this?
My code:
import numpy as np
import cv2
import math
import time
def getEdgeImage(img,margin=10):
kernel=np.float64([[-1,0,1]])
Ix=cv2.filter2D(img,cv2.CV_64F,kernel)
Iy=cv2.filter2D(img,cv2.CV_64F,kernel)
I=np.hypot(Ix,Iy)
m=I.max()
I[:,:margin]=m
I[:,-margin:]=m
return I
def getEnergyMap(img,repulseMask=None,attractMask=None):
edges=getEdgeImage(img)
if attractMask is not None:
edges[attractMask==1]=-10
if repulseMask is not None:
edges[repulseMask==1]=235
kernel=np.ones(3,np.float64)
for i in range(1,len(edges)):
minAbove=cv2.erode(edges[i-1],kernel).T[0]
edges[i]+=minAbove
return edges
def getSeam(img,repulseMask=None,attractMask=None):
energyMap=getEnergyMap(img,repulseMask,attractMask)
y=len(energyMap)-1
x=np.argmin(energyMap[y])
seam=[(x,y)]
while len(seam)<len(energyMap):
x,y=seam[-1]
newY=y-1
newX=x+np.argmin(energyMap[newY,x-1:x+2])-1
seam.append((newX,newY))
return seam
img1=cv2.imread("image.jpg") #[::2,::2]
# attractMask=img1*0
# repulseMask=img1*0
seam=getSeam(img1)
The attract and repulse masks are unimportant to the code currently, they are just used so I can manually plug in pixel coordinates to increase or decrease the amount of seams going in that coordinate plane.
The error I get when I run this code:
Traceback (most recent call last):
File "Program.py", line 110, in <module>
seam=getSeam(img1)
File "Program.py", line 62, in getSeam
energyMap=getEnergyMap(img,repulseMask,attractMask)
File "Program.py", line 58, in getEnergyMap
edges[i]+=minAbove
ValueError: operands could not be broadcast together with shapes (960,3) (960,) (960,3)
Is there anyway that I can get this to work with my code? I'll modify the functions if that is what I need to do.
Then try this, these are separate channels given to functions individually.
r=img1[:,:,0]
seam_r=getSeam(r)
g=img1[:,:,1]
seam_g=getSeam(g)
b=img1[:,:,2]
seam_b=getSeam(b)
After this, pass the results to your post function individually.

pytorch object too deep for array when saving image

I am trying to run the code from the following github rep:
https://github.com/iamkrut/image_inpainting_resnet_unet
I havent changed anything in the code and it is causing a ValueError, that the object is too deep, when the code tries to save the image. The error seems to come from these two lines.
images = img_tensor.cpu().detach().permute(0,2,3,1)
plt.imsave(join(data_dir, 'samples', image), images[index,:,:,:3])
Here is the error statement
File "train.py", line 205, in <module>
data_dir=args.data_dir)
File "train.py", line 94, in train_net
plt.imsave(join(data_dir, 'samples', image), images[index,:,:,:]);
File "C:\ProgramData\Anaconda3\envs\torch2\lib\site-packages\matplotlib\pyplot.py", line 2140, in imsave
return matplotlib.image.imsave(fname, arr, **kwargs)
File "C:\ProgramData\Anaconda3\envs\torch2\lib\site-packages\matplotlib\image.py", line 1498, in imsave
_png.write_png(rgba, fname, dpi=dpi)
ValueError: object too deep for desired array
Anyone know what could be causing this or how to fix it?
Thank you
matplotlib package does not understand the pytorch datatype (tensor). you should convert tensor array to numpy array and then use matplotlib functions.
a = torch.rand(10, 3, 20, 20)
plt.imsave("test.jpg", a.cpu().detach().permute(0, 2, 3, 1)[0, ...]) # Error
plt.imsave("test.jpg", a.cpu().detach().permute(0, 2, 3, 1).numpy()[0, ...])
I managed to fix the code by changing the lines to
images=img_tensor.cpu().numpy()[0]
images = np.transpose(images, (1,2,0))
plt.imsave(join(data_dir, 'samples', image), images)
Still not sure what was wrong with the previous version. So if anyone knows please tell me.

Python code for basic fft of grid image

I'm trying to take an fft of an image in python, alter the transformed image and take a reverse fft. Specifically, I have a picture of a grid that I'd like to transform, then black out all but a central, narrow vertical slit of the transform, then take a reverse fft.
The code I'm working with now, for no alteration to transform plane:
import os
os.chdir('/Users/terra/Desktop')
import Image, numpy
i = Image.open('grid.png')
i = i.convert('L') #convert to grayscale
a = numpy.asarray(i) # a is readonly
b = abs(numpy.fft.rfft2(a))
j = Image.fromarray(b)
j.save('grid2.png')
As of now, I'm getting an error message:
Traceback (most recent call last):
File "/Users/terra/Documents/pic2.py", line 11, in
j.save('grid2.png')
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/PIL/Image.py", line 1439, in save
save_handler(self, fp, filename)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/PIL/PngImagePlugin.py", line 506, in _save
raise IOError, "cannot write mode %s as PNG" % mode
IOError: cannot write mode F as PNG
I'm very new to programming and Fourier transforms, so most related threads I've found online are over my head. Very specific help is greatly appreciated. Thanks!
The main problem is that the array contains floats after the FFT, but for it to be useful for PNG output, you need to have uint8s.
The simplest thing is to convert it to uint8 directly:
b = abs(numpy.fft.rfft2(a)).astype(numpy.uint8)
This probably will not produce the image you want, so you'll have to normalize the values in the array somehow before converting them to integers.

Factors Analysis using MDP in Python

Excuse my ignorance, I'm very new to Python. I'm trying to perform factor analysis in Python using MDP (though I can use another library if there's a better solution).
I have an m by n matrix (called matrix) and I tried to do:
import mdp
mdp.nodes.FANode()(matrix)
but I get back an error. I'm guessing maybe my matrix isn't formed properly? My goal is find out how many components are in the data and find out which rows load onto which components.
Here is the traceback:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "mdp/signal_node.py", line 630, in __call__
return self.execute(x, *args, **kwargs)
File "mdp/signal_node.py", line 611, in execute
self._pre_execution_checks(x)
File "mdp/signal_node.py", line 480, in _pre_execution_checks
self.train(x)
File "mdp/signal_node.py", line 571, in train
self._check_input(x)
File "mdp/signal_node.py", line 429, in _check_input
if not x.ndim == 2:
AttributeError: 'list' object has no attribute 'ndim'
Does anyone have any idea what's going on, and feel like explaining it to a Python newbie?
I have absolutely no experience with mdp, but it looks like it expects your matrices to be passed as a Numpy array instead of a list. Numpy is a package for high performance scientific computing. You can go to the Numpy home page and install it. After doing so, try altering your code to this:
import mdp, numpy
mdp.nodes.FANode()(numpy.array(matrix))
As Stephen said, the data must be a numpy array. More precisely it must be a 2D array, with the first index representing the different sampes and the second index representing the data dimensions (using the wrong order here can lead to the "singular matrix" error).
You should also take a look at the MDP documentation, which should answer all your questions. If that doesn't help there is the MDP user mailing list.

MPI4Py Scatter sendbuf Argument Type?

I'm having trouble with the Scatter function in the MPI4Py Python module.
My assumption is that I should be able to pass it a single list for the sendbuffer. However, I'm getting a consistent error message when I do that, or indeed add the other two arguments, recvbuf and root:
File "code/step3.py", line 682, in subbox_grid
i = mpi_communicator.Scatter(station_range, station_data)
File "Comm.pyx", line 427, in mpi4py.MPI.Comm.Scatter (src/
mpi4py_MPI.c:44993)
File "message.pxi", line 321, in mpi4py.MPI._p_msg_cco.for_scatter
(src/mpi4py_MPI.c:14497)
File "message.pxi", line 232, in mpi4py.MPI._p_msg_cco.for_cco_send
(src/mpi4py_MPI.c:13630)
File "message.pxi", line 36, in mpi4py.MPI.message_simple (src/
mpi4py_MPI.c:11904)
ValueError: message: expecting 2 or 3 items
Here is the relevant code snipped, starting a few lines above 682
mentioned above.
for station in stations
#snip--do some stuff with station
station_data = []
station_range = range(1,len(station))
mpi_communicator = MPI.COMM_WORLD
i = mpi_communicator.Scatter(station_range, nsm)
#snip--do some stuff with station[i]
nsm = combine(avg, wt, dnew, nf1, nl1, wti[i], wtm, station[i].id)
station_data = mpi_communicator.Gather(station_range, nsm)
I've tried a number of combinations initializing station_range, but I
must not be understanding the Scatter argument types properly.
Does a Python/MPI guru have a clarification this?
If you want to move raw buffers (as with Gather), you provide a triplet [buffer, size, type]. Look at the demos for examples of this. If you want to send Python objects, you should use the higher level interface and call gather (note the lowercase) which uses pickle internally.

Categories