Search code examples
iosswiftvideouiimageavasset

Swift: extracting image from video comes out blurry even though video looks sharp?


The code below was inspired by other posts on SO and extracts an image from a video. Unfortunately, the image looks blurry even though the video looks sharp and fully in focus.

Is there something wrong with the code, or is this a natural difficulty of extracting images from videos?

func getImageFromVideo(videoURL: String) -> UIImage {
    do {
        let asset = AVURLAsset(URL: NSURL(fileURLWithPath: videoURL), options: nil)
        let imgGenerator = AVAssetImageGenerator(asset: asset)
        imgGenerator.appliesPreferredTrackTransform = true
        let cgImage = try imgGenerator.copyCGImageAtTime(CMTimeMake(0, 1), actualTime: nil)
        let image = UIImage(CGImage: cgImage)
        return image
    } catch {
        ...
    }
}

Solution

  • Your code is working without errors or problems. I've tried with a video and the grabbed image was not blurry.

    I would try to debug this by using a different timescale for CMTime.

    With CMTimeMake, the first argument is the value and the second argument is the timescale.

    Your timescale is 1, so the value is in seconds. A value of 0 means 1st second, a value of 1 means 2nd second, etc. Actually it means the first frame after the designated location in the timeline.

    With your current CMTime it grabs the first frame of the first second: that's the first frame of the video (even if the video is less than 1s).

    With a timescale of 4, the value would be 1/4th of a second. Etc.

    Try finding a CMTime that falls right on a steady frame (it depends on your video framerate, you'll have to make tests).

    For example if your video is at 24 fps, then to grab exactly one frame of video, the timescale should be at 24 (that way each value unit would represent a whole frame):

    let cgImage = try imgGenerator.copyCGImageAtTime(CMTimeMake(0, 24), actualTime: nil)
    

    On the other hand, you mention that only the first and last frames of the video are blurry. As you rightly guessed, it's probably the actual cause of your issue and is caused by a lack of device stabilization.

    A note: the encoding of the video might also play a role. Some MPG encoders create incomplete and interpolated frames that are "recreated" when the video plays, but these frames can appear blurry when grabbed with copyCGImageAtTime. The only solution I've found for this rare problem is to grab another frame just before or just after the blurry one.