I'm exploring SimpleCV as an imaging library in Python, and it seems pretty good. However, I'm stumped at how to perform an FFT on an image within SimpleCV. It seems I'd have to convert to an numpy array first, and then use the numpy facilities:
import SimpleCV as SV
im = Image('image.png')
img = im.getGrayNumpy()
imf = np.fft.fftshift(np.fft.fft2(img))
plt.imshow(log(abs(imf)+1),cmap=cm.gray)
Or maybe this is the best way? And of course if I want to convert the log of the fft spectrum into a SimpleCV image for later use, that's another issue...
You can bring numpy matrices back to SimpleCV using the Image() constructor:
import scipy
import numpy as np
import SimpleCV as scv
cam = scv.Camera()
disp = scv.Display()
while disp.isNotDone():
current = cam.getImage().resize(w=768)
matrix = current.getGrayNumpy()
spectrum = np.abs(np.log(np.fft.fftshift(np.fft.fft2(matrix))))
spectrum *= 255 / spectrum.max()
scv.Image(spectrum).show()
if disp.mouseLeft:
break
Related
I get that in Python OpenCV images are numpy arrays, that correspond to cv::Mat in c++.
This question is about what type-hint to put into python functions to properly restrict for OpenCV images (maybe even for a specific kind of OpenCV image).
What I do now is:
import numpy as np
import cv2
Mat = np.ndarray
def my_fun(image: Mat):
cv2.imshow('display', image)
cv2.waitKey()
Is there any better way to add typing information for OpenCV images in python?
You can specify it as numpy.typing.NDArray with an entry type. For example,
import numpy as np
Mat = np.typing.NDArray[np.uint8]
def my_fun(img: Mat):
pass
I am experimenting with Fourier transformations and the built-in NumPy.fft library. I was trying to see the difference between computing just fft2 of an image and fftshift on fft2 of an image. But for some reason, I am not getting the results that I was expecting. I have tried changing images as well but regardless of what I use, I get the same results as below. If someone could help me out here, it would be awesome. This is the code I used:
import numpy as np
import cv2
import matplotlib.pyplot as plt
from scipy import ndimage, fftpack
light = cv2.imread("go_light.jpeg")
dark = cv2.imread("go_dark.jpeg")
g_img = cv2.cvtColor(dark, cv2.COLOR_BGR2GRAY)
di = (np.abs((np.fft.fft2(g_img))))
dm = np.abs(np.fft.fftshift(np.fft.fft2(g_img)))
plt.figure(figsize=(6.4*5, 4.8*5), constrained_layout=False)
plt.subplot(151), plt.imshow(di, "gray"), plt.title("fft");
plt.subplot(152), plt.imshow(dm, "gray"), plt.title("fftshift");
plt.show()
di and dm are floating point values. Matplotlib can't do that. First, try di.astype(np.int8). However, many of the values are out of range. You may need to scale the array.
I'm using pi3d to display an ImageSprite on the screen the texture of which comes form an image I'm loading.
displayTexture = pi3d.Texture("display/display.jpg", blend=True, mipmap=True)
displaySlide = pi3d.ImageSprite(texture=displayTexture, shader=shader, w=800, h=600)
This texture image is actually something I'm creating in-program. It's an openCV2 image and therefore just a numpy array. At the moment I'm saving it just to load it again as a texture, but is there a way to just constantly update the texture of the sprite with the changing numpy array values?
I looked into the openCV OpenGL support but from what I could see it only supports Windows at this stage and is therefore not suitable for this use.
Edit: Should have mentioned I'm happy for a lower level solution too. I'm currently trying to use .toString() on the image array and use the resulting byte list with glTexImage2D to produce a texture but no dice so far.
Yes you can pass a PIL.Image to pi3d.Texture and it will create a new Texture using that. There is a bit of work involved there so it will impact on frame rate if it's a big Texture. Also you need to update the pointer in the Buffer that holds the Texture array so the new Texture gets used.
There is a method to load a numpy array to a PIL.Image (Image.fromarray()) so this would be an easy route. However it's a bit convoluted as pi3d already converts the PIL.Image into a numpy array see https://github.com/tipam/pi3d/blob/master/pi3d/Texture.py#L163
The following works ok as a short-cut into the workings of pi3d.Texture but it's a bit of a hack calling the 'private' function _load_opengl. I might look at making a more robust method of doing this (i.e. for mapping videos to 3D objects etc)
#!/usr/bin/python
from __future__ import absolute_import, division, print_function, unicode_literals
import demo
import pi3d
import random
import numpy as np
from PIL import Image, ImageDraw
DISPLAY = pi3d.Display.create(x=150, y=150)
shader = pi3d.Shader("uv_flat")
im = Image.open("textures/PATRN.PNG")
#draw = ImageDraw.Draw(im) # there are various PIL libraries you could use
nparr = np.array(im)
tex = pi3d.Texture(im) # can pass PIL.Image rather than path as string
sprite = pi3d.ImageSprite(tex, shader, w=10.0, h=10.0)
mykeys = pi3d.Keyboard()
while DISPLAY.loop_running():
#draw.line((random.randint(0,im.size[0]),
# random.randint(0,im.size[1]),
# random.randint(0,im.size[0]),
# random.randint(0,im.size[1])), fill=128) # draw random lines
#nparr = np.array(im)
nparr += np.random.randint(-2, 2, nparr.shape) # random noise
tex.image = nparr
tex._load_opengl()
sprite.draw()
if mykeys.read() == 27:
mykeys.close()
DISPLAY.destroy()
break
PS I can't remember what version of pi3d the switch to numpy textures happened but it's quite recent so you probably have to upgrade
EDIT:
The switch from Texture.image being a bytes object to numpy array was v1.14 posted on 18Mar15
To clarify the steps to use a numpy array to initialise and refresh a changing image:
...
im = Image.fromarray(cv2im) # cv2im is a numpy array
tex = pi3d.Texture(im) # create Texture from PIL image
sprite = pi3d.ImageSprite(tex, shader, w=10.0, h=10.0)
...
tex.image = cv2im # set Texture.image to modified numpy array
tex._load_opengl() # re-run OpenGLESv2 routines
So, this is what I am trying:
import cv2
import cv2.cv as cv
cv2.namedWindow(threeDWinName, cv2.CV_WINDOW_AUTOSIZE)
img2 = cv.CreateImage((320, 240), 32, 1)
cv2.imshow(threeDWinName,img2)
Does anybody know what is going wrong with this? I get TypeError: <unknown> is not a numpy array
Thanks
The more recent version of OpenCV, cv2 uses numpy arrays for images, the preceding version cv used opencv's special Mat's. In your code you've created an image as a Mat using the old cv function CreateImage, and then tried to view it using the newer cv2.imshow function, but cv2.imshow expects a numpy array...
...so all you need to do is import numpy, and then change you CreateImage line to:
img2 = np.zeros((320,240),np.float32)
And then it should be fine :)
I'm new to OpenCV and would like to use its Python binding.
When trying out the samples on OSX, I noticed
1.) The windows imshow creates are not resizable
2.) I can fix that with an prior call to cv2.namedWindow, like:
cv2.namedWindow('zoom', cv2.cv.CV_WINDOW_NORMAL)
Can we add symbols like CV_WINDOW_NORMAL from cv into cv2 !?
Who has commit rights to openCV's Python binding ?
Thanks,
Sebastian Haase
There are some omisions in the current new cv2 lib. Typically these are constants that did not get migrated to cv2 yet and are still in cv only.
Here is some code to help you find them:
import cv2
import cv2.cv as cv
nms = [(n.lower(), n) for n in dir(cv)] # list of everything in the cv module
nms2 = [(n.lower(), n) for n in dir(cv2)] # list of everything in the cv2 module
search = 'window'
print "in cv2\n ",[m[1] for m in nms2 if m[0].find(search.lower())>-1]
print "in cv\n ",[m[1] for m in nms if m[0].find(search.lower())>-1]
cv2 is a more faithful wrapper around the C++ libs than the previous cv. I found it confusing at first but it is much easier once you make the change. The code is much easier to read and numpy matrix manipulations are very fast.
I suggest you find and use the cv constants while reporting their omissions as bugs to the opencv bug tracker at willowgarage. cv2 is fresh and minty but will improve.
FYI. it is well worth instantiating the named windows before use, also killing them on exit. IMHO
E.g.
import cv2
if __name__ == '__main__':
cap = cv2.VideoCapture(0) # webcam 0
cv2.namedWindow("input")
cv2.namedWindow("grey")
key = -1
while(key < 0):
success, img = cap.read()
cv2.imshow("input", img)
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("grey", grey)
key = cv2.waitKey(1)
cv2.destroyAllWindows()