'Split video into images with OpenCV on Django

I have a REST api where my user can upload base64 encoded videos. Upon upload, i'd like to split the video into frames to train an AI. Here is my current version of my serializer:

# My models
class UserProfile(models.Model):
    user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
    captureDateTime = models.CharField(_('Capture datetime'), blank=True, null=True, max_length=100)

class UserUploadedData(models.Model):
    profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
    rawData = models.TextField(_('Raw Data'), blank=True, null=True)
    file = models.FileField(_('File'), blank=True)

    def save(self, *args, **kwargs):
        super(UserUploadedData,self).save(*args, **kwargs)

# My serializers
class UserUploadedDataSerializer(serializers.ModelSerializer):
    profile = serializers.SlugRelatedField(source="parent.id", slug_field='profile', read_only=True)
    class Meta:
        model = UserUploadedData
    fields = "__all__"

class UserProfileSerializer(serializers.Serializer):
    customerId = serializers.SlugRelatedField(source='user', queryset=get_user_model().objects.all(), many=False, slug_field='customerId')
    uploadedData = UserUploadedData(many=True)

    def __video_to_frames(self, userUploadedData):
        print("Video to frames: ")
        print(userUploadedData.file.path)
    
        # Start capturing the feed
        cap = cv2.VideoCapture(userUploadedData.file.path)
    
        # Find the number of frames
        video_length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) - 1
        print ("Number of frames: ", video_length)
        count = 0
        print ("Converting video..\n")
        # Start converting the video
        while cap.isOpened():
            # Extract the frame
            ret, frame = cap.read()
            if not ret:
                continue
        
            if count % 12 == 0:
                # Write the results back to output location.
                filename = datetime.now().strftime('%Y.%m.%d.%H.%M.%S')
                path = "media/"+filename+"-"+str(count+1)+'.jpg'
            
                print(path)
            
                cv2.imwrite(path, frame)
            
                f = open(path, 'r')
                print(type(f))
            
                tempImageFile = ContentFile(File(f.read()))       # this is were things go wrong...  
                UserUploadedData.objects.create(profile=userUploadedData.profile, file=tempImageFile)
        
            count = count + 1
        
            # If there are no more frames left
            if (count > (video_length-1)):
                # Release the feed
                cap.release()
                break
        
    
        print ("Converting video.. done!\n")
        return

    def create(self, validated_data):
        #print(validated_data)   
        user = validated_data.get('user')
    
        profile = UserProfile.objects.create(user=user, captureDateTime=validated_data)       
        dataArray = validated_data.get('profile').get('data')
        for bioData in dataArray:
            rawData = bioData.get('rawData')
            format, mediastr = rawData.split(';base64,') 
            ext = format.split('/')[-1]
            decodedMedia = base64.b64decode(mediastr)
        
            if ext.lower() == 'mp4':
                print("Split video...")
                filename = datetime.now().strftime('temp_%Y.%m.%d.%H.%M.%S')
                tempVideoFile = ContentFile(decodedMedia, name=filename+'.'+ext)         
                object = UserUploadedData.objects.create(profile=profile, file=tempVideoFile, **bioData)
        
                # Save all converted images 
                self.__video_to_frames(object)
            else:
                print("Save image")
                filename = datetime.now().strftime('%Y.%m.%d.%H.%M.%S')
                file = ContentFile(decodedMedia, name=filename+'.'+ext)
                        
                object = UserUploadedData.objects.create(profile=profile, file=file, **bioData)        
    
        return profile

The error trace is the following:

Number of frames:  25
Converting video..
media/2022.03.20.22.58.14-1.jpg
<class '_io.TextIOWrapper'>
Internal Server Error: /bis/v1/customer/save/
(...)
    File "C:\Users\me\Documents\Sources\python\project\app\serializers.py", line 67, in __video_to_frames
tempImageFile = ContentFile(File(f.read()))
    File "C:\Python38\lib\encodings\cp1252.py", line 23, in decode
    return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 251: character maps to <undefined>

At the moment, the MP4 file is saved corrected, but the individual images are not :(

Thanks for your help!



Solution 1:[1]

Try using filename = datetime.now().strftime('%Y-%m-%d-%H-%M-%S')

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 YScharf