Python crashes with error vm_copy failed when calling CGDataProviderCopyData - python

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!

Related

How do I generate a small image randomly in different parts of the big image?

Let's assume there are two images. One is called small image and another one is called big image. I want to randomly generate the small image inside the different parts of the big image one at a time everytime I run.
So, currently I have this image. Let's call it big image
I also have smaller image:
def mask_generation(blob_index,image_index):
experimental_image = markup_images[image_index]
h, w = cropped_images[blob_index].shape[:2]
x = np.random.randint(experimental_image.shape[0] - w)
y = np.random.randint(experimental_image.shape[1] - h)
experimental_image[y:y+h, x:x+w] = cropped_images[blob_index]
return experimental_image
I have created above function to generate the small image in big image everytime I call this function. Note: blob index is the index that I use to call specific 'small image' since I have a collection of those small images and image_index is the index to call specific 'big images'. Big images are stored in the list called experimental_image and small images are stored in list called markup images
However, when I run this, I do get the small image randomly generated but the previously randomly generated image never gets deleted and I am not too sure how to proceed with it,
Example: When I run it once
When I run it twice
How do I fix this? Any help will be appreciated. Thank you
I tried the above code but didn't work as I wanted it to work
I suppose you only want the small random image you generated in this iteration in your code.
The problem you have, is due to the modification of your calling args.
When you call your function multiple times with the same big image
markup_image = ...
result_1 = mask_generation(blob_index=0, image_index=0)
result_2 = mask_generation(blob_index=1, image_index=0)
You get in result_2 both small images.
This is due to the writing to the original image in
experimental_image[y:y+h, x:x+w] = cropped_images[blob_index]
This adds the small image to your original image in your list of images.
When getting this image the next time, the small image is already there.
To fix:
Do not alter your images, e.g. by first copying the image and then adding the small image in your function
Probably even better: Only give your function a big and small image, and make sure that they always receive a copy

How to crop and save image obtained by inference_detector() using CascadeTabNet (openCV)?

My goal is to detect tables in images and transform such tables into CSV files.
I am using CascadeTabNet to detect the location of tables.
Their example works great (https://colab.research.google.com/drive/1lzjbBQsF4X2C2WZhxBJz0wFEQor7F-fv?usp=sharing), the problem is that it does not show at the end how to save the detected table as another image (nor how to actually make that table into a CSV file, but for that, I can use other code).
This is what they had:
from mmdet.apis import init_detector, inference_detector, show_result_pyplot
import mmcv
# Load model
config_file = '/content/CascadeTabNet/Config/cascade_mask_rcnn_hrnetv2p_w32_20e.py'
checkpoint_file = '/content/epoch_36.pth'
model = init_detector(config_file, checkpoint_file, device='cuda:0')
# Test a single image
img = "/content/CascadeTabNet/Demo/demo.png"
# Run Inference
result = inference_detector(model, img)
# Visualization results
show_result_pyplot(img, result,('Bordered', 'cell', 'Borderless'), score_thr=0.85)
I tried to add the following to their code:
model.show_result(img, result, out_file='result.jpg')
And I get the following error:
TypeError: show_result() got an unexpected keyword argument 'out_file'
I also tried adding the "out_file" inside the "show_result_pyplot":
show_result_pyplot(img, result,('Bordered', 'cell', 'Borderless'), score_thr=0.85, out_file='result.jpg')
And I get the same error: show_result() got an unexpected keyword argument 'out_file'
Finally, I tried saving the image using pyplot from matplotlib, but it did not save the cropped area (the table area of the page) but all of it:
plt.savefig('foo.png')
I have been looking for solutions (How to crop an image in OpenCV using Python, How to detect symbols on a image and save it?, How to save cropped image using openCV?, How to save the detected object into a new image ...), and they all include cv2, but that did not work for me either.
In short, how to crop the area of the table and save it as a new image after using "inference_detector()"?

How to deal with error in input image

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

How to send embedded image created using PIL/pillow as email (Python 3)

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)

Unrecognized or unsupported array type in function cvGetMat in python opencv

I am trying to code in python opencv-2.4.3, It is giving me an error as below
Traceback (most recent call last):
File "/home/OpenCV-2.4.3/cam_try.py", line 6, in <module>
cv2.imshow('video test',im)
error: /home/OpenCV-2.4.3/modules/core/src/array.cpp:2482: error: (-206) Unrecognized or unsupported array type in function cvGetMat
I am not understanding what does that mean, Can anybody help me out?
Thankyou.
The relevant snippet of the error message is Unrecognized or unsupported array type in function cvGetMat. The cvGetMat() function converts arrays into a Mat. A Mat is the matrix data type that OpenCV uses in the world of C/C++ (Note: the Python OpenCV interface you are utilizing uses Numpy arrays, which are then converted behind the scenes into Mat arrays). With that background in mind, the problem appears to be that that the array im you're passing to cv2.imshow() is poorly formed. Two ideas:
This could be caused by quirky behavior on your webcam... on some cameras null frames are returned from time to time. Before you pass the im array to imshow(), try ensuring that it is not null.
If the error occurs on every frame, then eliminate some of the processing that you are doing and call cv2.imshow() immediately after you grab the frame from the webcam. If that still doesn't work, then you'll know it's a problem with your webcam. Else, add back your processing line by line until you isolate the problem. For example, start with this:
while True:
# Grab frame from webcam
retVal, image = capture.read(); # note: ignore retVal
# faces = cascade.detectMultiScale(image, scaleFactor=1.2, minNeighbors=2, minSize=(100,100),flags=cv.CV_HAAR_DO_CANNY_PRUNING);
# Draw rectangles on image, and then show it
# for (x,y,w,h) in faces:
# cv2.rectangle(image, (x,y), (x+w,y+h), 255)
cv2.imshow("Video", image)
i += 1;
source: Related Question: OpenCV C++ Video Capture does not seem to work
I was having the same error, and after about an hour of searching for the error, I found the path to the image to be improperly defined. It solved my problem, may be it will solve yours.
I solved the porblem by using a BGR-picture. the one from my cam was YUYV by default!
I am working in Windows with Opencv 2.3.1 and Python 2.7.2, so, I had the same problem, I solved it pasting the following DLL files: opencv_ffmpeg.dll and opencv_ffmpeg_64.dll in the installation folder of Python. Maybe it help you with a similar solution in Ubuntu.
For me, like Gab Hum did, I copied opencv_ffmpeg245.dll to my python code folder. Then it works.
Check your Image Array (or NpArray),(by printing it) whether you are trying to pass an array of images at one shot instead of passing each image at once.
A single image array would look like :
[[[ 76 85 103] ... [ 76 85 103]], ... ]
Rows encloses each columns, each matrix(pixes) encloses no of rows, each image comprises of matrices (pixels).
It is always good to have a sanity check, to be sure your camera is working.
In my case my camera is
raspistill -o test.jpg

Categories

Resources