1

I have images stored in the another format in a folder. In a separate folder, I have text files that contain the coordinates of the rectangles which are supposed to be drawn over the image. I use the read_file function to read the NumPy array from the file.

From the script given below, I can successfully plot the coordinates over the image one after the other. But this just generates images one after the other, whereas I want a video of the aforementioned images, i.e. Images produced by the script given below.

Code snippet which does the aforementioned:

for idx, val in enumerate(img_list):
    image = read_file(img_list[idx])
    with open(annot_list[idx], 'r') as f:
        lines = [idx.rstrip('\n') for idx in f.readlines()]
        annots = [list(map(int, idx.split(','))) for idx in lines]
    plt.figure()
    plt.imshow(image, cmap='gray')
    for jdx, annot in enumerate(annots):
        x1 = annots[jdx][0]
        y1 = annots[jdx][1]
        w = annots[jdx][2] - x1
        h = annots[jdx][3] - y1
        rect = patches.Rectangle((x1, y1), w, h, linewidth=3, edgecolor='r', facecolor='none')
        plt.gca().add_patch(rect)
    plt.show()

Here, img_listand annot_list variables contain the names of the image files and the names of the respective annotation files.

This generates an array of images one after the other. How do I generate a video of these frames? What should I tweak? I have looked at this thread but I can't seem to figure out what I need to change so as to generate a video. I don't necessarily have to save the video and I don't want to save the frames in the frame list because I have around 5000 images.

Thank You and I appreciate any help I can get.

duddal
  • 19
  • 2
  • 7
  • opencv has a VideoWriter class. You can push one image after the other (with an assumed constant framerate). – Micka Apr 29 '21 at 09:23
  • I saw a few threads related to that and also the documentation for Python but just couldn't figure out how to do that. Can you perhaps help? – duddal Apr 29 '21 at 09:51

1 Answers1

0

First, define a video writer before the loop. In the loop, after showing the image, define a figure and a random plot in order to save the image into an array. Finally, write each image into the video writer.

out = cv2.VideoWriter('output.avi', -1, 20.0, (640, 480)) # Change the 640 and 480 to the dimensions of your images

for idx, val in enumerate(img_list):
    image = read_file(img_list[idx])
    with open(annot_list[idx], 'r') as f:
        lines = [idx.rstrip('\n') for idx in f.readlines()]
        annots = [list(map(int, idx.split(','))) for idx in lines]
    plt.figure()
    plt.imshow(image, cmap='gray')
    for jdx, annot in enumerate(annots):
        x1 = annots[jdx][0]
        y1 = annots[jdx][1]
        w = annots[jdx][2] - x1
        h = annots[jdx][3] - y1
        rect = patches.Rectangle((x1, y1), w, h, linewidth=3, edgecolor='r', facecolor='none')
        plt.gca().add_patch(rect)
    plt.show()

    fig = plt.figure() # Define figure
    fig.add_subplot(111) # Random plot
    fig.canvas.draw()
    img = np.fromstring(fig.canvas.tostring_rgb(), dtype='uint8', sep='') # Get image array
    out.write(img) # Write to video writer

out.release() # End the video writer

If this part doesn't work:

    fig = plt.figure() # Define figure
    fig.add_subplot(111) # Random plot
    fig.canvas.draw()
    img = np.fromstring(fig.canvas.tostring_rgb(), dtype='uint8', sep='') # Get image array
    out.write(img) # Write to video writer

You can try:

    plt.savefig("temp.png")
    img = cv2.imread("temp.png")
    out.write(img) # Write to video writer
Red
  • 26,798
  • 7
  • 36
  • 58
  • I get the following error when I tried the suggested solution: Traceback (most recent call last): File "D:/FH-AACHEN/Thesis/labelImg_test_Annotation/test_annotations.py", line 41, in img = np.fromstring(fig.canvas.tostring_rgb(), dtype='uint8', sep='') File "C:\Users\DELL\AppData\Roaming\Python\Python37\site-packages\matplotlib\backends\backend_agg.py", line 415, in tostring_rgb return self.renderer.tostring_rgb() AttributeError: 'FigureCanvasTkAgg' object has no attribute 'renderer' OpenCV: FFMPEG: format avi / AVI (Audio Video Interleaved) – duddal Apr 29 '21 at 13:08
  • @duddal I made an edit; added `fig.canvas.draw()`. – Red Apr 29 '21 at 13:13
  • Yes, I tried this after looking [here]https://stackoverflow.com/questions/20051160/renderer-problems-using-matplotlib-from-within-a-script but it still doesn't work. It seems like, it cannot read the NumPy array of the image – duddal Apr 29 '21 at 13:19
  • Also the image array is (512,1536) so it is not an RGB image. Is tostring_rgb() the problem? – duddal Apr 29 '21 at 13:22
  • The output video that is saved is 0KB. Therefore I think it did not work. – duddal Apr 29 '21 at 13:30
  • But does this mean, I have to save all the 5000 images I am trying to create a video from? – duddal Apr 29 '21 at 14:52
  • @duddal Yes, though you'll only be getting one file. Or have a look here: https://stackoverflow.com/q/29317262/13552470 – Red Apr 29 '21 at 16:15