Overcome opencv CV_IO_MAX_IMAGE_PIXELS limitation in python - python

I'm trying to use opencv to open an image size 4864 x 382565 and it is bigger than CV_IO_MAX_IMAGE_PIXELS limitation which is 2^30 pixels.
img = cv2.cvtColor(cv2.imread(path),cv2.COLOR_BGR2GRAY)
You can do the trick of calling set CV_IO_MAX_IMAGE_PIXELS=18500000000 from the shell before running python script to bypass this check, but I wonder is there a better solution?
Thanks

I think I found the solution
os.environ["OPENCV_IO_MAX_IMAGE_PIXELS"] = pow(2,40).__str__()
import cv2 # import after setting OPENCV_IO_MAX_IMAGE_PIXELS
This will change the limitation to 2^40
Just remember to import opencv AFTER setting the environment variable, otherwise it wouldn't work

Related

Scikit image: resize() got an unexpected keyword argument 'anti_aliasing'

I am trying to use the resize function using aliasing exactly as described in the documentation: http://scikit-image.org/docs/dev/auto_examples/transform/plot_rescale.html
from skimage.transform import resize
im_test = resize(im_test, (im_test.shape[0] / 3, im_test.shape[1] / 3),anti_aliasing=True)
However this returns:
Scikit image: resize() got an unexpected keyword argument
'anti_aliasing'
What is the reason for this? Is anti_aliasing on by default? What is the best way to resize an image with anti aliasing if this function can't be used?
Checking the code here with git blame, it seems it was introduced on 19.09.2017.
The only release version supporting this currently should be: v0.13.1, which you will need then!
For checking, what kind of version you are using currently, i recommend opening your interpreter (of your used python-distribution) and do:
import skimage as sk
sk.__version__
# '0.13.0' i would not be able to use it, it seems
there are two sets of documentation
1) http://scikit-image.org/docs/dev/api/skimage.transform.html#skimage.transform.resize
2)http://scikit-image.org/docs/0.11.x/api/skimage.transform.html#resize
the second one doesn't accept anti_aliasing as a parameter and is the 0.11 version, the one that accepts anti aliasing is 0.14
looks like older version uses a box filter while resizing,and all pixels have equal weight

Copying a PIL image as quickly as I can open it

I'm finding that in PIL I can load an image from disk substantially more quickly than I can copy it. Is there a faster way to copy an image than by calling image.copy()? (and how is this even possible?)
Sample code:
import os, PIL.Image, timeit
test_filepath = os.path.expanduser("~/Test images/C.jpg")
load_image_cmd = "PIL.Image.open('{}')".format(test_filepath)
print((PIL.Image.open(test_filepath)).__class__)
print(min(timeit.repeat(load_image_cmd, setup='import PIL.Image', number=10000)))
print(min(timeit.repeat("img.copy()", setup='import PIL.Image; img = {}'.format(load_image_cmd), number=10000)))
Produces:
PIL.JpegImagePlugin.JpegImageFile
0.916192054749
1.85366988182
Adding gc.enable to the setup for timeit doesn't change things much.
According to the PIL documentation, open() is a lazy operation, which means that it's not really doing all the work to use the image yet.
To do a copy() however, it almost certainly has to read the whole thing in and process it.
EDIT:
To test whether this is true, you should access a pixel in each image as part of your timeit.
EDIT 2:
Another glance at the doc shows that a load() after the open() ought to do the trick of making it do all its work.

opencv getImage() error

I wrapped opencv today with simplecv python interface. After going through the official SimpleCV Cookbook I was able to successfully Load, Save, and Manipulate images. Thus, I know the library is being loaded properly.
However, under the Using a Camera, Kinect, or Virtual Camera heading I was unsuccessful in running some commands. In particular, mycam = Camera() worked, but img = mycam.getImage() produced the following error:
In [35]: img = mycam.getImage().save()
OpenCV Error: Bad argument (Array should be CvMat or IplImage) in cvGetSize, file /home/jordan/OpenCV-2.2.0/modules/core/src/array.cpp, line 1237
---------------------------------------------------------------------------
error Traceback (most recent call last)
/home/simplecv/<ipython console> in <module>()
/usr/local/lib/python2.7/dist-packages/SimpleCV-1.1-py2.7.egg/SimpleCV/Camera.pyc in getImage(self)
332
333 frame = cv.RetrieveFrame(self.capture)
--> 334 newimg = cv.CreateImage(cv.GetSize(frame), cv.IPL_DEPTH_8U, 3)
335 cv.Copy(frame, newimg)
336 return Image(newimg, self)
error: Array should be CvMat or IplImage
I'm running Ubuntu Natty on a HP TX2500 tablet. It has a built in webcam, (CyberLink Youcam?) Has anybody seen this error before? I've been all over the web today looking for a solution, but nothing seems to be doing the trick.
Update 1: I tested cv.QueryFrame(capture) using the code found here in a separate Stack Overflow question and it worked; so I've pretty much nailed this down to a webcam issue.
Update 2: In fact, I get the exact same errors on a machine that doesn't even have a webcam! It's looking like the TX2500 is not compatible...
since the error raised from Camera.py of SimpleCV, you need to debug the getImage() method. If you can edit it:
def getImage(self):
if (not self.threaded):
cv.GrabFrame(self.capture)
frame = cv.RetrieveFrame(self.capture)
import pdb # <-- add this line
pdb.set_trace() # <-- add this line
newimg = cv.CreateImage(cv.GetSize(frame), cv.IPL_DEPTH_8U, 3)
cv.Copy(frame, newimg)
return Image(newimg, self)
then run your program, it will be paused as pdb.set_trace(), here you can inspect the type of frame, and try to figure out how get the size of frame.
Or you can do the capture in your code, and inspect the frame object:
mycam = Camera()
cv.GrabFrame(mycam.capture)
frame = cv.RetrieveFrame(mycam.capture)
To answer my own question...
I bought a Logitech C210 today and the problem disappeared.
I'm now getting warnings:
Corrupt JPEG data: X extraneous bytes before marker 0xYY.
However, I am able to successfully push a video stream to my web-browser via JpegStreamer(). If I cannot solve this error, I'll open a new thread.
Thus, for now, I'll blame the TX2500.
If anybody finds a fix in the future, please post.
Props to #HYRY for the investigation. Thanks.
I'm geting the camera with OpenCV
from opencv import cv
from opencv import highgui
from opencv import adaptors
def get_image()
cam = highgui.cvCreateCameraCapture(0)
im = highgui.cvQueryFrame(cam)
# Add the line below if you need it (Ubuntu 8.04+)
#im = opencv.cvGetMat(im)
return im
Anthony, one of the SimpleCV developers here.
Also instead of using image.save(), this function writes the file/video to disk, you instead probably want to use image.show(). You can save if you want, but you need to specify a file path like image.save("/tmp/blah.png")
So you want to do:
img = mycam.getImage()
img.show()
As for that model of camera I'm not sure if it works or not. I should note that we also wrapper different camera classes not just OpenCV, this is because OpenCV has a problem with webcams over 640x480, we now can do high resolution cameras.
Also I should mention, which I didn't realize, is that OpenCV less than 2.3 is broken with webcams on Ubuntu 11.04 and up. I didn't realize this as I was running Ubuntu 10.10 before, by the looks of your output you are using python 2.7 which makes me think you are on Ubuntu 11.04 or higher. Anyway, we have a fix for this problem. It is now pushed up into the master, it basically does a check to see if OpenCV is working, if not it will fall back to pygame.
This fix will also be in the 1.2 release of SimpleCV (It's in the master branch now)

CvSize does not exist?

I have installed the official python bindings for OpenCv and I am implementing some standard textbook functions just to get used to the python syntax. I have run into the problem, however, that CvSize does not actually exist, even though it is documented on the site...
The simple function: blah = cv.CvSize(inp.width/2, inp.height/2) yields the error 'module' object has no attribute 'CvSize'. I have imported with 'import cv'.
Is there an equivalent structure? Do I need something more? Thanks.
It seems that they opted to eventually avoid this structure altogether. Instead, it just uses a python tuple (width, height).
To add a bit more to Nathan Keller's answer, in later versions of OpenCV some basic structures are simply implemented as Python Tuples.
For example in OpenCV 2.4:
This (incorrect which will give an error)
image = cv.LoadImage(sys.argv[1]);
grayscale = cv.CreateImage(cvSize(image.width, image.height), 8, 1)
Would instead be written as this
image = cv.LoadImage(sys.argv[1]);
grayscale = cv.CreateImage((image.width, image.height), 8, 1)
Note how we just pass the Tuple directly.
The right call is cv.cvSize(inp.width/2, inp.height/2).
All functions in the python opencv bindings start with a lowercased c even in the highgui module.
Perhaps the documentation is wrong and you have to use cv.cvSize instead of cv.CvSize ?
Also, do a dir(cv) to find out the methods available to you.

How do I create an OpenCV image from a PIL image?

I want to do some image processing with OpenCV (in Python), but I have to start with a PIL Image object, so I can't use the cvLoadImage() call, since that takes a filename.
This recipe (adapted from http://opencv.willowgarage.com/wiki/PythonInterface) does not work because cvSetData complains argument 2 of type 'void *' . Any ideas?
from opencv.cv import *
from PIL import Image
pi = Image.open('foo.png') # PIL image
ci = cvCreateImage(pi.size, IPL_DEPTH_8U, 1) # OpenCV image
data = pi.tostring()
cvSetData(ci, data, len(data))
I think the last argument to the cvSetData is wrong too, but I am not sure what it should be.
The example you tried to adapt is for the new python interface for OpenCV 2.0. This is probably the source of the confusion between the prefixed and non-prefixed function names (cv.cvSetData() versus cv.SetData()).
OpenCV 2.0 now ships with two sets of python bindings:
The "old-style" python wrapper, a python package with the opencv.{cv,highgui,ml} modules
The new interface, a python C extension (cv.pyd), which wraps all the OpenCV functionalities (including the highgui and ml modules.)
The reason behind the error message is that the SWIG wrapper does not handle conversion from a python string to a plain-old C buffer. However, the SWIG wrapper comes with the opencv.adaptors module, which is designed to support conversions from numpy and PIL images to OpenCV.
The following (tested) code should solve your original problem (conversion from PIL to OpenCV), using the SWIG interface :
# PIL to OpenCV using the SWIG wrapper
from opencv import cv, adaptors, highgui
import PIL
pil_img = PIL.Image.open(filename)
cv_img = adaptors.PIL2Ipl(pil_img)
highgui.cvNamedWindow("pil2ipl")
highgui.cvShowImage("pil2ipl", cv_img)
However, this does not solve the fact that the cv.cvSetData() function will always fail (with the current SWIG wrapper implementation).
You could then use the new-style wrapper, which allows you to use the cv.SetData() function as you would expect :
# PIL to OpenCV using the new wrapper
import cv
import PIL
pil_img = PIL.Image.open(filename)
cv_img = cv.CreateImageHeader(pil_img.size, cv.IPL_DEPTH_8U, 3) # RGB image
cv.SetData(cv_img, pil_img.tostring(), pil_img.size[0]*3)
cv.NamedWindow("pil2ipl")
cv.ShowImage("pil2ipl", cv_img)
A third approach would be to switch your OpenCV python interface to the ctypes-based wrapper. It comes with utility functions for explicit data conversion between e.g. python strings and C buffers. A quick look on google code search seems to indicate that this is a working method.
Concerning the third parameter of the cvSetData() function, size of the image buffer, but the image step. The step is the number of bytes in one row of your image, which is pixel_depth * number_of_channels * image_width. The pixel_depth parameter is the size in bytes of the data associated to one channel. In your example, it would be simply the image width (only one channel, one byte per pixel).
It's really confusing to have both swig and new python binding. For example, in the OpenCV 2.0, cmake can accept both BUILD_SWIG_PYTHON_SUPPORT and BUILD_NEW_PYTHON_SUPPORT. But anyway, I kinda figured out most pitfalls.
In the case of using "import cv" (the new python binding), one more step is needed.
cv.SetData(cv_img, pil_img.tostring(), pil_img.size[0]*3)
cv.CvtColor(cv_img, cv_img, cv.CV_RGB2BGR)
The conversion is necessary for RGB images because the sequence is different in PIL and IplImage. The same applies to Ipl to PIL.
But if you use opencv.adaptors, it's already taken care of. You can look into the details in adaptors.py if interested.
I did this using the python2.6 bindings of OpenCV2.1:
...
cv_img = cv.CreateImageHeader(img.size, cv.IPL_DEPTH_8U, 3)
cv.SetData(cv_img, img.rotate(180).tostring()[::-1])
...
The image rotation and reversion of the string is to swap RGB into BGR, that is used in OpenCV video encoding. I assume that this would also be necessary for any other use of an image converted from PIL to OpenCV.
I'm not an expert but I managed to get a opencv image from a PIL image with this code:
import opencv
img = opencv.adaptors.PIL2Ipl(pilimg)

Categories

Resources