1

カメラからフレームをキャプチャし、別のスレッドによって更新された画像をブレンドするアプリに取り組んでいます。私の問題は、500 ミリ秒ごとに呼び出されるイメージ作成スレッドが、他のスレッドに影響を与えるピーク コンピューティング パワーを消費することです。

明確にするためにいくつかのログを次に示します。

captureOutput(): used time:  0.027741014957428  , frame rate:  36.0477077545513
captureOutput(): used time:  0.0285720229148865  , frame rate:  34.9992719444091
captureOutput(): used time:  0.0310209989547729  , frame rate:  32.2362281581567
captureOutput(): used time:  0.0268059968948364  , frame rate:  37.3050852733863
captureOutput(): used time:  0.0263729691505432  , frame rate:  37.9176115624965
motionCallback(): starting drawing: 
captureOutput(): used time:  0.0376390218734741  , frame rate:  26.5681718127947
motionCallback(): elapesed time:  0.0835540294647217
captureOutput(): used time:  0.0581380128860474  , frame rate:  17.2004502795793
captureOutput(): used time:  0.0364410281181335  , frame rate:  27.4415967836645
captureOutput(): used time:  0.0278580188751221  , frame rate:  35.8963070734734
captureOutput(): used time:  0.0283130407333374  , frame rate:  35.3194137435949
captureOutput(): used time:  0.0271909832954407  , frame rate:  36.7768972947616
captureOutput(): used time:  0.0268760323524475  , frame rate:  37.2078730552999

ご覧のとおり、captureOutput のフレーム レートは 30 fps を超えています。motionCallback が画像を作成するとすぐに、フレーム レートが低下し、その後再び上昇します。motionCallback() は 15 番目のキャプチャ フレームごとにしか呼び出されないため、平均的な計算能力で十分であることに注意してください。

captureOutput() は、次のように作成されたキューで実行されています。

required init?(coder aDecoder: NSCoder) {
  super.init(coder: aDecoder)
  self.m_captureSessionQueue = DispatchQueue(label: "CaptureSessionOutputQueue", attributes: DispatchQueueAttributes.serial)
}

後で、AVCapture を次のようにセットアップします。

videoDataOutput.setSampleBufferDelegate(self, queue: self.m_captureSessionQueue)

motionCallback() は次のように設定されます。

let interval = 0.4
if m_manager.isDeviceMotionAvailable {
  m_manager.showsDeviceMovementDisplay = true
  m_manager.deviceMotionUpdateInterval = interval
  // XArbitraryCorrectedZVertical
  m_manager.startDeviceMotionUpdates(using: CMAttitudeReferenceFrame.xArbitraryCorrectedZVertical , to: OperationQueue.main, withHandler: motionCallback)
  print("viewDidLoad(): CM initialized !")
}

以降:

func motionCallback(_ motion: CMDeviceMotion?, error: NSError?) -> Void {
  guard let mot = motion else {return}
  print("motionCallback(): starting drawing: ")

  let start = NSDate() // <<<<<<<<<< Start time
  self.m_instrview?.update(attitude: mot.attitude)
  self.m_overlayImage = CIImage(image: self.m_instrview!.generateImage()!)

  let end = NSDate()  // <<<<<<<<<<   end time
  let timeInterval: Double = end.timeIntervalSince(start as Date)
  print("motionCallback(): elapesed time: ", timeInterval)
}

そして、次のような generateImage():

func generateImage() -> UIImage {
  UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main().scale )
  drawHierarchy(in: self.bounds, afterScreenUpdates: true)
  let image = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext()
  return image!
}

アイデアは、CoreMotion システムが更新を取得するたびに、新しいイメージを生成することです。

私の質問は、フレーム レートの低下の原因となるピーク CPU 電力を消費しないように、motionCallback() の計算時間を平均化するにはどうすればよいですか? したがって、10 倍長く実行することは受け入れますが、その間は CPU の 1/10 しか消費しません。

これを制御する方法はありますか?

ありがとうクリス

4

1 に答える 1