I am writing a simple program that reads and does some operations with a series of images. One of the input images has some faults (I think it's the result of disconnecting thumb drive during data transfer).
So the only statement involving the input image that does not cause the program to freeze is cv2.imread(). The moment my program reaches any statement that involves the input, it freezes. I tried putting these statements in try-catch blocks (so that error is thrown and this image is skipped) but nothing changes. Is there anything I can do to make my program see the error in the input then ignore it and go to the next image instead of freezing?
As per OpenCV doc:
The function imread loads an image from the specified file and returns it. If the image cannot be read (because of missing file, improper permissions, unsupported or invalid format), the function returns an empty matrix ( Mat::data==NULL ).
Therefore, just check for None value, for example:
for fname in fnames:
img = cv2.imread(fname)
if img is None:
continue
# Do your processing here
Related
I'm trying to open a zipped nifty file using nibabel library (as nib) and the following code:
img = nib.load (nifti_file)
img_data = img.get_data ()
where nifti_file is a variable with the path to the file in the same directory.
On the second line, there is an out-of-memory error that happens 60% of the time randomly while I try running those two lines.
I have enough memory space on my computer so I'm not sure why this happens and also as I mentioned sometimes it simply works.
I wrote a python script to detect broken images and count them,
The problem in my script is it detects all the images and does not detect broken images. How to fix this. I refered :
How to check if a file is a valid image file? for my code
My code
import os
from os import listdir
from PIL import Image
count=0
for filename in os.listdir('/Users/ajinkyabobade/Desktop/2'):
if filename.endswith('.JPG'):
try:
img=Image.open('/Users/ajinkyabobade/Desktop/2'+filename)
img.verify()
except(IOError,SyntaxError)as e:
print('Bad file : '+filename)
count=count+1
print(count)
I have added another SO answer here that extends the PIL solution to better detect broken images.
I also implemented this solution in my Python script here on GitHub.
I also verified that damaged files (jpg) frequently are not 'broken' images i.e, a damaged picture file sometimes remains a legit picture file, the original image is lost or altered but you are still able to load it.
I quote the other answer for completeness:
You can use Python Pillow(PIL) module, with most image formats, to check if a file is a valid and intact image file.
In the case you aim at detecting also broken images, #Nadia Alramli correctly suggests the im.verify() method, but this does not detect all the possible image defects, e.g., im.verify does not detect truncated images (that most viewer often load with a greyed area).
Pillow is able to detect these type of defects too, but you have to apply image manipulation or image decode/recode in or to trigger the check. Finally I suggest to use this code:
try:
im = Image.load(filename)
im.verify() #I perform also verify, don't know if he sees other types o defects
im.close() #reload is necessary in my case
im = Image.load(filename)
im.transpose(PIL.Image.FLIP_LEFT_RIGHT)
im.close()
except:
#manage excetions here
In case of image defects this code will raise an exception.
Please consider that im.verify is about 100 times faster than performing the image manipulation (and I think that flip is one of the cheaper transformations).
With this code you are going to verify a set of images at about 10 MBytes/sec (modern 2.5Ghz x86_64 CPU).
For the other formats psd,xcf,.. you can use Imagemagick wrapper Wand, the code is as follows:
im = wand.image.Image(filename=filename)
temp = im.flip;
im.close()
But, from my experiments Wand does not detect truncated images, I think it loads lacking parts as greyed area without prompting.
I red that Imagemagick has an external command identify that could make the job, but I have not found a way to invoke that function programmatically and I have not tested this route.
I suggest to always perform a preliminary check, check the filesize to not be zero (or very small), is a very cheap idea:
statfile = os.stat(filename)
filesize = statfile.st_size
if filesize == 0:
#manage here the 'faulty image' case
You are building a bad path with
img=Image.open('/Users/ajinkyabobade/Desktop/2'+filename)
Try the following instead (by adding / to the end of the directory path)
img=Image.open('/Users/ajinkyabobade/Desktop/2/'+filename)
or
img=Image.open(os.path.join('/Users/ajinkyabobade/Desktop/2', filename))
try the below: It worked fine for me. It identifies the bad/corrupted image and remove them as well. Or if you want you can only print the bad/corrupted file name and remove the final script to delete the file.
for filename in listdir('/Users/ajinkyabobade/Desktop/2/'):
if filename.endswith('.JPG'):
try:
img = Image.open('/Users/ajinkyabobade/Desktop/2/'+filename) # open the image file
img.verify() # verify that it is, in fact an image
except (IOError, SyntaxError) as e:
print(filename)
os.remove('/Users/ajinkyabobade/Desktop/2/'+filename)
I am getting an error that tells me that Image.load is not available. Image.open appears to work.
I was also getting errors using:
except (IOError, SyntaxError) as e:
I just changed that to:
except:
and it worked fine.
I am creating image that I would like to embed in the e-mail. I cannot figure out how to create image as binary and pass into MIMEImage. Below is the code I have and I have error when I try to read image object - the error is "AttributeError: 'NoneType' object has no attribute 'read'".
image=Image.new("RGBA",(300,400),(255,255,255))
image_base=ImageDraw.Draw(image)
emailed_password_pic=image_base.text((150,200),emailed_password,(0,0,0))
imgObj=emailed_password_pic.read()
msg=MIMEMultipart()
html="""<p>Please finish registration <br/><img src="cid:image.jpg"></p>"""
img_file='image.jpg'
msgText = MIMEText(html,'html')
msgImg=MIMEImage(imgObj)
msgImg.add_header('Content-ID',img_file)
msg.attach(msgImg)
msg.attach(msgText)
If you look at line 4 - I am trying to read image so that I can pass it into MIMEImage. Apparently, image needs to be read as binary. However, I don't know how to convert it to binary so that .read() can process it.
FOLLOW-UP
I edited code per suggestions from jsbueno - thank you very much!!!:
emailed_password=os.urandom(16)
image=Image.new("RGBA",(300,400),(255,255,255))
image_base=ImageDraw.Draw(image)
emailed_password_pic=image_base.text((150,200),emailed_password,(0,0,0))
stream_bytes=BytesIO()
image.save(stream_bytes,format='png')
stream_bytes.seek(0)
#in_memory_file=stream_bytes.getvalue()
#imgObj=in_memory_file.read()
imgObj=stream_bytes.read()
msg=MIMEMultipart()
sender='xxx#abc.com'
receiver='jjjj#gmail.com'
subject_header='Please use code provided in this e-mail to confirm your subscription.'
msg["To"]=receiver
msg["From"]=sender
msg["Subject"]=subject_header
html="""<p>Please finish registration by loging into your account and typing in code from this e-mail.<br/><img src="cid:image.png"></p>"""
img_file='image.png'
msgText=MIMEText(html,'html')
msgImg=MIMEImage(imgObj) #Is mistake here?
msgImg.add_header('Content-ID',img_file)
msg.attach(msgImg)
msg.attach(msgText)
smtpObj=smtplib.SMTP('smtp.mandrillapp.com', 587)
smtpObj.login(userName,userPassword)
smtpObj.sendmail(sender,receiver,msg.as_string())
I am not getting errors now but e-mail does not have image in it. I am confused about the way image gets attached and related to in html/email part. Any help is appreciated!
UPDATE:
This code actually works - I just had minor typo in the code on my PC.
There are a couple of conceptual errors there, both in using PIL and on what format an image should be in order to be incorporated into an e-mail.
In PIL: the ImageDraw class operates inplace, not like the Image class calls, which usually return a new image after each operation. In your code, it means that the call to image_base.text is actually changing the pixel data of the object that lies in your image variable. This call actually returns None and the code above should raise an error like "AttributeError: None object does not have attribute 'read'" on the following line.
Past that (that is, you should fetch the data from your image variable to attach it to the e-mail) comes the second issue: PIL, for obvious reasons, have images in an uncompressed, raw pixel data format in memory. When attaching images in e-mails we usually want images neatly packaged inside a file - PNG or JPG formats are usually better depending on the intent - let's just stay with .PNG. So, you have to create the file data using PIL, and them attach the file data (i.e. the data comprising a PNG file, including headers, metadata, and the actual pixel data in a compressed form). Otherwise you'd be putting in your e-mail a bunch of (uncompressed) pixel data that the receiving party would have no way to assemble back into an image (even if he would treat the data as pixels, raw pixel data does not contain the image shape so-)
You have two options: either generate the file-bytes in memory, or write them to an actual file in disk, and re-read that file for attaching. The second form is easier to follow. The first is both more efficient and "the right thing to do" - so let's keep it:
from io import BytesIO
# In Python 2.x:
# from StringIO import StringIO.StringIO as BytesIO
image=Image.new("RGBA",(300,400),(255,255,255))
image_base=ImageDraw.Draw(image)
# this actually modifies "image"
emailed_password_pic=image_base.text((150,200),emailed_password,(0,0,0))
stream = BytesIO()
image.save(stream, format="png")
stream.seek(0)
imgObj=stream.read()
...
(NB: I have not checked the part dealing with mail and mime proper in your code - if you are using it correctly, it should work now)
I've got an issue where I'm unable to get the pixel data (via CGDataProviderCopyData) from the Image that gets returned when I call CGImageCreate. Any other call and I'm able to get the data from images with no problem, so obviously I'm doing something incorrectly with the parameters that I pass in.
To make sure that I have "good" pixel data, I pull it from an image returned from CGWindowListCreateImage. Further, to verify that this pixel data is not the point of failure, I have tests which convert it to a PIL Image and save it to file so that I can verify that this are as they should be.
Getting the pixel data:
display_monitor = get_rightmost_monitor()
image = CG.CGWindowListCreateImage(
CG.CGRectInfinite,
CG.kCGWindowListOptionOnScreenOnly,
display_monitor,
CG.kCGWindowImageDefault
)
new_image = CG.CGBitmapContextCreateImage(context)
prov = CG.CGImageGetDataProvider(new_image)
data = CG.CGDataProviderCopyData(prov)
return data
For testing purposes, I'm simply trying to recreate the image object from which the pixel data came. So, I feed all of the attributes of the first image into the parameters of the CGImageCreate function.
rebuilt_image = CG.CGImageCreate(
CG.CGImageGetWidth(image), # width
CG.CGImageGetHeight(image), # height
CG.CGImageGetBitsPerComponent(image), # bitsPerComponent
CG.CGImageGetBitsPerPixel(image), # bitsPerPixel
CG.CGImageGetBytesPerRow(image), # bytesPerRow
CGImageGetColorSpace(image), # colorspace
CG.CGImageGetBitmapInfo(image), # bitmapInfo
data, # pixel data from image
None, # decode
False, # shouldInterpolate
CG.kCGRenderingIntentDefault)
Now, the Image gets created without throwing any errors. However, upon calling CGDataProviderCopyData to extract the pixeldata, everything crashes and spits out this error:
<Error>: copy_read_only: vm_copy failed: status 1
Despite my best googling, I'm unable to figure out what's causing this to fail. There are similar quesitons on SO, like this one. However, they're not quite in line with the issue I'm having, or perhaps due to my inexperience with the Core Graphics framework, I'm unable to translate the solutions offered in those questions to something applicable to my issue.
Could someone clear up where I've gone wrong?
Thanks!
I need open an image, verify the image, then reopen it (see last sentence of below quote from PIL docs)
im.verify()
Attempts to determine if the file is broken, without actually decoding
the image data. If this method finds any problems, it raises suitable
exceptions. This method only works on a newly opened image; if the
image has already been loaded, the result is undefined. Also, if you
need to load the image after using this method, you must reopen the
image file.
This is what I have in my code, where picture is a django InMemoryUploadedFile object:
img = Image.open(picture)
img.verify()
img = Image.open(picture)
The first two lines work fine, but I get the following error for the third line (where I'm attempting to "reopen" the image):
IOError: cannot identify image file
What is the proper way to reopen the image file, as the docs suggest?
This is no different than doing
f = open('x.png')
Image.open(f)
Image.open(f)
The code above does not work because PIL advances in the file while reading its first few bytes to (attempt to) identify its format. Trying to use a second Image.open in this situation will fail as noted because now the current position in the file is past its image's header. To confirm this, you can verify what f.tell() returns. To solve this issue you have to go back to the start of the file either by doing f.seek(0) between the two calls to Image.open, or closing and reopening the file.
Try doing a del img between the verify and second open.