You can use newer OpenCV python interface (if I'm not mistaken it is available since OpenCV 2.2). It natively uses numpy arrays:
import cv2
im = cv2.imread("abc.tiff")
print(type(im))
result:
<type 'numpy.ndarray'>
Answer from Andrey Kamaev on Stack OverflowPython - byte image to NumPy array using OpenCV - Stack Overflow
How to convert image file object to numpy array in with openCv python? - Stack Overflow
How can I turn numpy ndarray into an opencv image? Or alternatively, is there a module that can take numpy array screenshots at a high FPS?
python - How can I read a numpy array image with OpenCV? - Stack Overflow
You can use newer OpenCV python interface (if I'm not mistaken it is available since OpenCV 2.2). It natively uses numpy arrays:
import cv2
im = cv2.imread("abc.tiff")
print(type(im))
result:
<type 'numpy.ndarray'>
PIL (Python Imaging Library) and Numpy work well together.
I use the following functions.
from PIL import Image
import numpy as np
def load_image( infilename ) :
img = Image.open( infilename )
img.load()
data = np.asarray( img, dtype="int32" )
return data
def save_image( npdata, outfilename ) :
img = Image.fromarray( np.asarray( np.clip(npdata,0,255), dtype="uint8"), "L" )
img.save( outfilename )
The 'Image.fromarray' is a little ugly because I clip incoming data to [0,255], convert to bytes, then create a grayscale image. I mostly work in gray.
An RGB image would be something like:
out_img = Image.fromarray( ycc_uint8, "RGB" )
out_img.save( "ycc.tif" )
I created a 2x2 JPEG image to test this. The image has white, red, green and purple pixels. I used cv2.imdecode and numpy.frombuffer
import cv2
import numpy as np
f = open('image.jpg', 'rb')
image_bytes = f.read() # b'\xff\xd8\xff\xe0\x00\x10...'
decoded = cv2.imdecode(np.frombuffer(image_bytes, np.uint8), -1)
print('OpenCV:\n', decoded)
# your Pillow code
import io
from PIL import Image
image = np.array(Image.open(io.BytesIO(image_bytes)))
print('PIL:\n', image)
This seems to work, although the channel order is BGR and not RGB as in PIL.Image. There are probably some flags you might use to tune this. Test results:
OpenCV:
[[[255 254 255]
[ 0 0 254]]
[[ 1 255 0]
[254 0 255]]]
PIL:
[[[255 254 255]
[254 0 0]]
[[ 0 255 1]
[255 0 254]]]
I searched all over the internet finally I solved:
NumPy array (cv2 image) - Convert
NumPy to bytes
and
bytes to NumPy
:.
#data = cv2 image array
def encodeImage(data):
#resize inserted image
data= cv2.resize(data, (480,270))
# run a color convert:
data= cv2.cvtColor(data, cv2.COLOR_BGR2RGB)
return bytes(data) #encode Numpay to Bytes string
def decodeImage(data):
#Gives us 1d array
decoded = np.fromstring(data, dtype=np.uint8)
#We have to convert it into (270, 480,3) in order to see as an image
decoded = decoded.reshape((270, 480,3))
return decoded;
# Load an color image
image= cv2.imread('messi5.jpg',1)
img_code = encodeImage(image) #Output: b'\xff\xd8\xff\xe0\x00\x10...';
img = decodeImage(img_code) #Output: normal array
cv2.imshow('image_deirvlon',img);
print(decoded.shape)
You can get full code from here
If you effectively have the contents of a JPEG/PNG file in your variable called response, I think you can do:
frame = cv2.imdecode(response)
Or, you may need to do:
frame = cv2.imdecode(np.fromstring(response, np.uint8), cv2.IMREAD_COLOR)
Failing that, another way is like this:
from io import BytesIO
from scipy import misc
frame = misc.imread(BytesIO(response))
If the file is in read-byte mode (which means mode='rb') in your case, then numpy.frombuffer() also works, for example :
file = request.files['fileName']
frame = cv2.imdecode(np.frombuffer(file.read(), numpy.uint8), cv2.IMREAD_COLOR)
I'm attempting to automate a game using opencv and yolov5. My final problem is that I can't get a script to capture the screen fast enough to follow the objects correctly. I found a module called DXCam that can capture images at astounding speeds, though I can't use them in my algorithm as they are ndarrays and not normal arrays. Is there a way to convert the ndarrays into normal arrays (this process does not need to be fast, I can simply buffer them and alter them after they've been captured)? This is the script that produces the ndarrays:
def record():
size = (pyautogui.size())
box = pyautogui.locateOnScreen('game_screen.png', region=(0, 0, size[0], size[1]), grayscale=True, confidence=0.7)
record_time = 3
target_fps = 120
writer = cv2.VideoWriter(
"output.mp4", cv2.VideoWriter_fourcc(*"mp4v"), target_fps, (box.width, box.height)
)
camera = dxcam.create(output_color="RGB")
camera.start(target_fps=120, video_mode=True, region=(box.left, box.top, box.left + box.width, box.top + box.height))
cur_time = time.time()
while time.time() < cur_time + record_time:
writer.write(camera.get_latest_frame())
camera.stop()
writer.release()Alternatively, are there any faster methods than this? This one for example is not fast enough for my needs (Merely 12-13 frames a second):
def record_bad():
height = GetSystemMetrics(1)
width = GetSystemMetrics(0)
file_name = 'output.mp4v'
fourcc = cv2.VideoWriter_fourcc(*'MP4V')
captured_video = cv2.VideoWriter(file_name, fourcc, 120.0, (width, height))
time_before = time.time()
frames = []
while time.time() > time_before + 3:
img = ImageGrab.grab(bbox=(0, 0, width, height)) # bbox specifies specific region (bbox= x,y,width,height)
img_final = cv2.cvtColor(np.array(img), cv2.COLOR_BGR2GRGB)
frames.append(img_final)
cv2.waitKey(0)
for frame in frames:
captured_video.write(frame)
captured_video.release()
cv2.destroyAllWindows()Your code can be fixed as follows:
import numpy as np, cv
vis = np.zeros((384, 836), np.float32)
h,w = vis.shape
vis2 = cv.CreateMat(h, w, cv.CV_32FC3)
vis0 = cv.fromarray(vis)
cv.CvtColor(vis0, vis2, cv.CV_GRAY2BGR)
Short explanation:
np.uint32data type is not supported by OpenCV (it supportsuint8,int8,uint16,int16,int32,float32,float64)cv.CvtColorcan't handle numpy arrays so both arguments has to be converted to OpenCV type.cv.fromarraydo this conversion.- Both arguments of
cv.CvtColormust have the same depth. So I've changed source type to 32bit float to match the ddestination.
Also I recommend you use newer version of OpenCV python API because it uses numpy arrays as primary data type:
import numpy as np, cv2
vis = np.zeros((384, 836), np.float32)
vis2 = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
This is what worked for me...
import cv2
import numpy as np
#Created an image (really an ndarray) with three channels
new_image = np.ndarray((3, num_rows, num_cols), dtype=int)
#Did manipulations for my project where my array values went way over 255
#Eventually returned numbers to between 0 and 255
#Converted the datatype to np.uint8
new_image = new_image.astype(np.uint8)
#Separated the channels in my new image
new_image_red, new_image_green, new_image_blue = new_image
#Stacked the channels
new_rgb = np.dstack([new_image_red, new_image_green, new_image_blue])
#Displayed the image
cv2.imshow("WindowNameHere", new_rgbrgb)
cv2.waitKey(0)
You don't need to convert NumPy array to Mat because OpenCV cv2 module can accept NumPyarray.
The only thing you need to care for is that {0,1} is mapped to {0,255} and any value bigger than 1 in NumPy array is equal to 255. So you should divide by 255 in your code, as shown below.
img = numpy.zeros([5,5,3])
img[:,:,0] = numpy.ones([5,5])*64/255.0
img[:,:,1] = numpy.ones([5,5])*128/255.0
img[:,:,2] = numpy.ones([5,5])*192/255.0
cv2.imwrite('color_img.jpg', img)
cv2.imshow("image", img)
cv2.waitKey()
You are looking for scipy.misc.toimage:
import scipy.misc
rgb = scipy.misc.toimage(np_array)
It seems to be also in scipy 1.0, but has a deprecation warning. Instead, you can use pillow and PIL.Image.fromarray