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.
Related
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.
I cannot figure out how to do what Ben Eater did.
I have the exact same code (different file name) but the error I get is that I cannot use the argument pixels[x,y] for chr() to write to a binary file
The video I linked has all the information of what I am trying to accomplish. If you have a specific question for me, ask away.
btw...I have literally been trying to make this work about a year and have not figured out how to do it so...yeah.
'''
from PIL import Image
image = Image.open("Margarita3.png")
pixels = image.load()
out_file = open("Margarita3.bin", "wb")
for y in range(150):
for x in range(200):
try:
out_file.write(chr(pixels[x, y]))
except IndexError:
out_file.write(chr(0))
'''
here is the error message
Traceback (most recent call last):
File "C:\Users\Nicky\Desktop\tolaptop\wincupl_vga_timings\convert.py", line
11, in <module>
out_file.write(chr(pixels[x,y]))
TypeError: an integer is required
Make sure the image is in the correct location. According to your current code, it should be in the same directory as the python script. If you want to specify otherwise, you should do it like so:
image = Image.open("C:\Users\Nicky\Desktop\tolaptop\...Margarita3.png")
pixels = image.load()
out_file = open("C:\Users\Nicky\Desktop\tolaptop\...Margarita3.bin", "wb")
Ok, I asked a similar question that revolved around vrep but it was a little specific when in fact a simpler python-based question would be more useful. I will, however, leave the question there should anyone be able to provide useful information.
Here is the question; How does one take a 1 dimensional list containing image data, convert it into a numpy array and then display it?
This is what I have so far:
im = np.array(image, dtype=np.uint8)
im.resize(128,128,3) #reshape this array into an image form (e.g. rather than 49152)
mlp.imshow(im)
pylab.show(im)
Here, image is returned from a simxGetVisionSensorImage (not important if you don't know vrep stuff) and is a list. I then try to create a numpy array and read the data in, turning it from a signed 8 bit integer into an unsigned 8 bit integer. I then resize it (it is a 49152 length list corresponding to a resolution of 128x128) and attempt to display it using either matplotlib or pylab.
Here are the includes should you need them:
import numpy as np
import matplotlib.pyplot as mlp
import pylab
the matplotlib.show command does not even show a window for the image. the pylab.show command throws this error:
Traceback (most recent call last):
File "vrep_epuck.py", line 59, in <module>
pylab.show(im)
File "/usr/lib/python2.7/dist-packages/matplotlib/pyplot.py", line 244, in show
return _show(*args, **kw)
File "/usr/lib/python2.7/dist-packages/matplotlib/backend_bases.py", line 165, in __call__
if block:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Here is the link to the original vrep question should you want to see the whole code or see the vrep stuff:
vrep question
It would help to stay within the usual naming conventions.
Because then it would be more obvious that pyplot.show() does not take an image as argument. Thus, don't use pyplot.show(some_image_as_argument) but simply pyplot.show().
import matplotlib.pyplot as plt
image = ...
im = np.array(image, dtype=np.uint8)
im.resize(128,128,3)
plt.imshow(im)
plt.show()
I'm using skimage to convert RGB images to Lab colorspace but it seems that skimage uses float64 datatype while Tensorflow uses float32.
Is there any way to convert the 64-bit Lab image to 32-bit datatype? The documentation doesn't cover anything specific about this and I'm not sure if using image.astype(np.float32) is the way to go since it might damage the data precision (or not).
Here's a part of the code:
from skimage import color, io
import numpy as np
rgb = io.imread('Test.jpg') # Could be any shape
lab = color.rgb2lab(rgb)
converted = np.array(lab).astype(np.float32)
rgb = color.lab2rgb(converted)
The last line gives an error:
ValueError: Images of type float must be between -1 and 1.
and here's the Stack Trace:
File "C:\Anaconda3\lib\site-packages\skimage\color\colorconv.py", line 928, in lab2rgb
return xyz2rgb(lab2xyz(lab))
File "C:\Anaconda3\lib\site-packages\skimage\color\colorconv.py", line 855, in lab2xyz
arr = _prepare_colorarray(lab).copy()
File "C:\Anaconda3\lib\site-packages\skimage\color\colorconv.py", line 153, in _prepare_colorarray
return dtype.img_as_float(arr)
File "C:\Anaconda3\lib\site-packages\skimage\util\dtype.py", line 291, in img_as_float
return convert(image, np.float64, force_copy)
File "C:\Anaconda3\lib\site-packages\skimage\util\dtype.py", line 195, in convert
raise ValueError("Images of type float must be between -1 and 1.")
ValueError: Images of type float must be between -1 and 1.
Using x.astype(np.float32) is perfectly acceptable. You'll seldom if ever need that level of accuracy.
If you are not careful, however, you may accidentally cast an integer image (e.g., unsigned bytes, going from 0 to 255) into float. So the safest approach, that will rescale as necessary, is
from skimage import img_as_float
image = img_as_float(image).astype(np.float32)
This was a difficult bug to track down.
If you're using float32 then you get your error as described; however, the error will go away if you use float64 values instead.
Hope that helps! :)
Known bug source:
Scikit-image Issue
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.