質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

2657閲覧

【Swift】AVAssetImageGeneratorで1フレーム毎の画像を取得したい

kazuhiro_ikeda

総合スコア5

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2021/04/20 10:25

解決したいこと

AVAssetImageGeneratorで、任意の動画の**「全フレームにおける画像」**を取得したい
→現在のソースコードでの間違いを理解したい

前提

・下記ソースで、INとして入力している動画のFPSは60のものを対象にしている
・下記ソースでは、動画における**「全てのフレームにおける画像」の取得を試みているが**、結果(return)の画像を見ると、思うように画像が取得できていない

現在のソースコード

Swift

1 internal func test(mediaURL: URL!) throws -> [UIImage] { 2 /// UIImage格納変数 3 var images: [UIImage] = [UIImage]() 4 5 /// URLから、動画を取得 6 let asset = AVAsset(url: mediaURL) 7 8 /// 画像変換器生成 9 let imageGenerator = AVAssetImageGenerator(asset:asset) 10 imageGenerator.appliesPreferredTrackTransform = true 11 12 /// duration取得 13 let time: CMTime = asset.duration 14 // 補足:一例として読み込ませている動画の情報 15 // time: CMTime(value: 1158, timescale: 600, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0) 16 // 動画長: 1.93秒 17 // FPS: 60 18 var tmp_time: CMTime = time 19 20 21 // 画像の取得 22 do { 23 /// フレーム数分ループ 24 /// →読み込ませた動画のfpsが60、であるため、"1.93*60"分だけの画像を取得したい 25 for time_i in (0..<time.value / 10) { 26 27 /// 画像初期化 28 let imageRef: CGImage 29 30 /// 取得対象の画像指定 31 tmp_time.value = time_i * 10 32 imageRef = try imageGenerator.copyCGImage(at: tmp_time, actualTime: tmp_time2) 33 34 images.append(imageRef) 35 } 36 } catch { 37 throw APIError.generateImage("画像取得失敗") 38 } 39 return images 40 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tomato879241

2021/04/21 04:26

「結果(return)の画像を見ると、思うように画像が取得できていない」とはどういう画像が取得できていることを意味しているのでしょうか?いずれにせよ全てのフレームごとのデータを取得することはできないと思います。
tomato879241

2021/04/22 11:42

動画から抜き取ったものを配列に保存するのはあまり賢明なやり方ではないと思いますけど?
kazuhiro_ikeda

2021/04/25 02:01

> 動画から抜き取ったものを配列に保存するのはあまり賢明なやり方ではないと思いますけど? 本問題は解決したのですが、よろしければ上記について理由教えてください。 参考リンクなどだけでもご提示いただけると幸いですが、いかがでしょうか? ちなみに、画像の配列を生成した理由は、「動画」を作り直したかったからです。 ↓作り直す流れ ①動画からフレーム単位で画像を取得 ②一枚一枚の画像に対して何らかの修正 ③再度合成 ここで、③のインプットとして[UIImage]型のデータ必要になったため、画像の配列を生成する方針とした次第です。 →動画生成の参考:https://blog.ch3cooh.jp/entry/ios/generate_movie_using_avassetwriter
tomato879241

2021/04/25 06:21

自分でどうしてか、自分のやっている方法が正しいか、とか時間をかけて自分で考えてみましたか?自分もかなり昔(8・9年前)にObjective-Cでコードを書いている時に、Apple社の開発者のサイトで画像ファイルを配列に保存する方法を聞いたことがあります。すると質問の答えが返ってくる代わりに、Apple社の誰かに何故画像を配列に保存するんだと聞かれたり、画像は配列に保つものではないとか、どうして画像を配列に保つ必要があるのか、とか色々と尋問を受けたことを覚えています。もしその自分の経験を聞いても何もピンとこないのであれば、年・月かけて何故それがだめなのかを考えてください。
guest

回答1

0

自己解決

解決方法

AVAssetReaderTrackOutputを使用して解決できました。
ご回答いただきました方、ありがとうございました!

Swift

1 internal func test(mediaURL: URL!) throws { 2 /// URLから、動画を取得 3 let asset = AVAsset(url: mediaURL) 4 5 /// AVAssetReaderの生成 6 let reader = try! AVAssetReader(asset: asset) 7 let videoTrack = asset.tracks(withMediaType: .video).first! 8 let outputSettings = [String(kCVPixelBufferPixelFormatTypeKey): NSNumber(value: kCVPixelFormatType_32BGRA)] 9 let trackReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, 10 outputSettings: outputSettings) 11 let fps = videoTrack.nominalFrameRate 12 print("fps: ", fps) 13 14 reader.add(trackReaderOutput) 15 reader.startReading() 16 17 do { 18 /// フレーム数分ループ 19 while let sampleBuffer = trackReaderOutput.copyNextSampleBuffer() { 20 if let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) { 21 22 /// ピクセルバッファをベースにCoreImageのCIImageオブジェクトを作成 23 let ciImage = CIImage(cvPixelBuffer: imageBuffer) 24 25 /// CGImageを作成 26 let pixelBufferWidth = CGFloat(CVPixelBufferGetWidth(imageBuffer)) 27 let pixelBufferHeight = CGFloat(CVPixelBufferGetHeight(imageBuffer)) 28 let imageRect:CGRect = CGRect(x: 0, y: 0, width: pixelBufferWidth, height: pixelBufferHeight ) 29 let ciContext = CIContext.init() 30 let cgimage = ciContext.createCGImage(ciImage, from: imageRect ) 31 } 32 } 33 } catch { 34 throw APIError.generateImage("画像変換失敗") 35 } 36 }

補足

動画における「全てのフレームにおける画像」の取得を試みているが、結果(return)の画像を見ると、思うように画像が取得できていない

自身のコードでは、1秒毎にしか画像を取得できてませんでした。
AVAssetImageGeneratorのcopyCGImageメソッドでは、1秒未満単位の位置における画像を取得できないものなのですかね。今後調査してわかったら補足しようと思います。

参考

「avasset frame」とググったら出てきました。
https://stackoverflow.com/questions/26600979/processing-all-frames-in-an-avasset

投稿2021/04/25 01:52

kazuhiro_ikeda

総合スコア5

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問