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()
Answer from bikz05 on Stack OverflowHow 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 - cv2 Writing stream from array - Stack Overflow
python - Reading an 2D array or list with OpenCV - Stack Overflow
python 3.x - Creating cv2.VideoCapture() object directly from numpy array image data - Stack Overflow
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
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()I think this is what you are looking for. you need to add one more dimension to your list of points using np.expand_dims
import numpy as np
import cv2
my_list = np.array([[1, 0, 1], [2, 0, 1], [2, 0, 2]], dtype=np.uint8)
img = np.expand_dims(my_list, axis=0)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 70, 110, apertureSize=3)
# and so on
lines = cv2.HoughLines(edges, 1, np.pi / 180, 150)
EDIT:
As you have clarified that your input list's values are from the gray colour space.
you can simply change array datatype to np.uint8 and it will work.
import numpy as np
import cv2
my_list = np.array([[1, 0, 1], [2, 0, 1], [2, 0, 2]], dtype=np.uint8)
edges = cv2.Canny(my_list, 70, 110, apertureSize=3)
# and so on
lines = cv2.HoughLines(edges, 1, np.pi / 180, 150)
Just visualizing with a slightly larger 2D array and detecting the diagonal line present in the array with the following code:
my_list = np.eye(100) #np.array([[0,1,0,1],[0,2,0,1],[0,2,0,2]])
gray = (255*my_list/np.max(my_list)).astype('uint8')
edges = cv2.Canny(gray,70,110,apertureSize = 3)
lines = cv2.HoughLines(edges,1,np.pi/180,50)
lines
# array([[[-1. , 2.3561945]],
# [[ 1. , 2.3561945]]], dtype=float32)
# original image
plt.imshow(gray, 'gray')
plt.show()

# canny edges detected
plt.imshow(edges)
plt.show()

# lines detected with Hough transform
im = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
if lines is not None:
for i in range(len(lines)):
rho = lines[i][0][0]
theta = lines[i][0][3]
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
pt1 = (int(x0 + 1000*(-b)), int(y0 + 1000*(a)))
pt2 = (int(x0 - 1000*(-b)), int(y0 - 1000*(a)))
print(pt1, pt2)
cv2.line(im, pt1, pt2, (0,0,255), 2, cv2.LINE_AA)
plt.imshow(im)
plt.show()

- To play image for
3seconds add same image3times to frames list (1 list element = 1 second) - Set
fpsto1inVideoWriter
Code:
import cv2
frames = [cv2.imread('frame1.jpg'),
cv2.imread('frame2.jpg'),
cv2.imread('frame2.jpg'),
cv2.imread('frame2.jpg'),
cv2.imread('frame2.jpg')]
height, width, _ = frames[0].shape
out = cv2.VideoWriter('output.avi', cv2.VideoWriter_fourcc(*'DIVX'), 1, (width, height))
[out.write(f) for f in frames]
out.release()
Output:

Each image is a frame in your video, since you set the frames per second to 15 in your cv2.VideoWriter object, it will display those images rather quick. What you could do is lower the frames per seconds or duplicate your frames to match up the frames per second.
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)