picamera.capture() can be used to capture the image to a stream-like object (an io.BytesIO stream) or even directly to a numpy array.
An example from here shows how to do it and gives important notes to the resolution (rounding up the requested resolution). It is necessary to keep this rounding in mind when allocating a buffer object as it must be large enough to receive all the image data. So fetching the data might require are larger buffer and the uninitialized pixels have to be stripped off afterwards (there's an example in the documenation linked above).
import numpy as np
with picamera.PiCamera() as camera:
camera.resolution = (320, 240)
camera.framerate = 24
output = np.empty((240, 320, 3), dtype=np.uint8)
It is also important to note that when outputting to unencoded formats, the camera rounds the requested resolution. The horizontal resolution is rounded up to the nearest multiple of 32 pixels, while the vertical resolution is rounded up to the nearest multiple of 16 pixels.