Using pyautogui and opencv for screenshot - python

I am using the following code:
import cv2
import numpy as np
import pyautogui
import sys
img = pyautogui.screenshot()
cv2.imshow('image',img)
When I run this, it tells me
mat is not a numpy array, neither a scalar
I have tried to use different functions from opencv and it seems they all return the same. What do I need to do in order to take a screenshot then work with it in Open CV?

After some digging, I realise that the pyautogui function is using Pillow which is giving a format that must be adapted to work with opencv.
I added the following code so that it worked:
open_cv_image = np.array(img)
# Convert RGB to BGR
open_cv_image = open_cv_image[:, :, ::-1].copy()

Related

cv2 in Python crashes when I try to open a 4 level CMYK numpy array

import numpy as np
from PIL import Image
import cv2
with Image.open("image.png") as im:
im = im.convert("CMYK")# not a true CMYK conversion here
im.show(title="image")
img = np.array(im)
#cv2.imshow('image', img)
I need to view a CMYK file hopefully using OpenCV and read pixel values in the CMYK space. I tried to load an image, convert it to CMYK(just 4 color levels) and view it using cv2. Note, I have cv2* commented out because it will cause Python to crash and OpenCv will need to be reinstalled. Will OpenCv allow me to view a (x, x, 0:3).uint8 numpy array? If so, throw me a line.
My solution was simple. I forgot the following:
cv2.waitKey(0)
cv2.destroyAllWindows()

Open CV: Problems with cv2.rectangle() method

Im just trying some things with OpenCV. Once i try to to put a rectangle on my image, I always receive the following error: Expected Ptr<cv::UMat> for argument 'img'
This happens while using the following code:
!pip install opencv-python
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import cv2
img = cv2.imread("C:/..../.../.../.../.....jpg")[...,::-1]
cv2.rectangle(img,(400,200),(500,500),(0,0,255),20)
plt.imshow(img)
plt.show()
Is there anybody who faced the same issue once?
Thanks for your help in advance
Best regards
Sascha
If you want to display with matplotlib, the best way to change from BGR to RGB is to use
img = cv2.imread("C:/..../.../.../.../.....jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
instead of
img = cv2.imread("C:/..../.../.../.../.....jpg")[...,::-1]
I tried it and it works.

m is not a numpy array, neither a scalar

import cv2
import numpy as np
from PIL import Image
img = Image.open("test.jpg")
imgfilename = img.filename
imgb,imgg,imgr = cv2.split(img)
count = 0
I've been getting the following error when I try to run my code - this is the error I'm getting:
File "WB.py", line 9, in <module>
imgb,imgg,imgr = cv2.split(img)
TypeError: m is not a numpy array, neither a scalar
You're generally not supposed to use PIL together with numpy, these libraries don't interact a lot.
From numpy (and opencv)'s point of view, images are just 2D or 3D arrays of any given type (2D for grayscale, 3D for color). Also cv2 uses BGR by default...
Start with cv2.imread(path, cv2.IMREAD_COLOR) instead of Image.open(path).
You should use the split function available in PIL for this purpose.
Image.split()
This is because images are interpreted differently in OpenCV and PIL. Hence you cannot you the functions available in these packages interchangeably.

Python: How to write a single channel png file from numpy array?

I want to write a single channel png image from a numpy array in python?
In Matlab that would be
A = randi(100,100,255)
imwrite(uint8(A),'myFilename.png','png');
I saw exampels using from PIL import Image and Image.fromarray() but they are for jpeg and 3-channel pngs only it appears...
I already found the solution using opencv, I will post it here. Hopefully it will shorten someone else's searching...
Here is a solution using opencv / cv2
import cv2
myImg = np.random.randint(255, size=(200, 400)) # create a random image
cv2.imwrite('myImage.png',myImg)
PIL's Image.fromarray() automatically determines the mode to use from the datatype of the passed numpy array, for example for an 8-bit greyscale image you can use:
from PIL import Image
import numpy as np
data = np.random.randint(256, size=(100, 100), dtype=np.uint8)
img = Image.fromarray(data) # uses mode='L'
This however only works if your array uses a compatible datatype, if you simply use data = np.random.randint(256, size=(100, 100)) that can result in a int64 array (typestr <i8), which PIL can't handle.
You can also specify a different mode, e.g. to interpret a 32bit array as an RGB image:
data = np.random.randint(2**32, size=(100, 100), dtype=np.uint32)
img = Image.fromarray(data, mode='RGB')
Internally Image.fromarray() simply tries to guess the correct mode and size and then invokes Image.frombuffer().
The image can then be saved as any format PIL can handle e.g: img.save('filename.png')
You might want not to utilise OpenCV for simple image manipulation. As suggested, use PIL:
im = Image.fromarray(arr)
im.save("output.png", "PNG")
Have you tried this? What has failed here that led you to concluding that this is JPEG-only?

Python OpenCV drawing errors after manipulating array with numpy

I'm reading in an image with OpenCV, and trying to do something with it in numpy (rotate 90deg). Viewing the result with imshow from matplotlib, it all seems to be working just fine - image is rotated. I can't use drawing methods from OpenCV on the new image, however. In the following code (I'm running this in a sagemath cloud worksheet):
%python
import cv2
import matplotlib.pyplot as plt
import numpy as np
import os, sys
image = np.array( cv2.imread('imagename.png') )
plt.imshow(image,cmap='gray')
image = np.array(np.rot90(image,3) ) # put it right side up
plt.imshow(image,cmap='gray')
cv2.rectangle(image,(0,0),(100,100),(255,0,0),2)
plt.imshow(image,cmap='gray')
I get the following error on the cv2.rectangle() command:
TypeError: Layout of the output array img is incompatible with cv::Mat (step[ndims-1] != elemsize or step[1] != elemsize*nchannels)
The error goes away if I use np.array(np.rot90(image,4) ) instead (i.e. rotate it 360). So it appears that the change in dimensions is messing it up. Does OpenCV store the dimensions somewhere internally that I need to update or something?
EDIT: Adding image = image.copy() after rot90() solved the problem. See rayryeng's answer below.
This is apparently a bug in the Python OpenCV wrapper. If you look at this question here: np.rot90() corrupts an opencv image, apparently doing a rotation that doesn't result back in the original dimensions corrupts the image and the OP in that post experiences the same error you are having. FWIW, I also experienced the same bug.... no idea why.
A way around this is to make a copy of the image after you rotate, and then show the image. This I can't really explain, but it seems to work. Also, make sure you call plt.show() at the end of your code to show the image:
import cv2
import matplotlib.pyplot as plt
import numpy as np
import os, sys
image = np.array( cv2.imread('imagename.png') )
plt.imshow(image,cmap='gray')
image = np.array(np.rot90(image,3) ) # put it right side up
image = image.copy() # Change
plt.imshow(image,cmap='gray')
cv2.rectangle(image,(0,0),(100,100),(255,0,0),2)
plt.imshow(image,cmap='gray')
plt.show() # Show image
I faced the same problem with numpy 1.11.2 and opencv 3.3.0. Not sure why, but this did the job for me.
Before using cv2.rectangle, add the line below:
image1 = image1.transpose((1,0)).astype(np.uint8).copy()
Reference
Convert data type works for my problem.
The image is of type np.int64 before the convert.
image = image.astype(np.int32) # convert data type

Categories

Resources