picamera2でカメラのオートフォーカスを調整する(Raspberry Pi、Python)

 前回picamera2でカメラが撮影している映像を表示するプレビュー画面について触れてきました:

映像が実際に見られるようになると嬉しくなる一方で、カメラ自体の機能を色々と調整したくなってきます。

 この記事でRaspberry Pi 4に取り付けたArduCam社製の「64MP Hawk-eye」にはオートフォーカス機能が付いています。そこで今回はオートフォーカス周りについて見てみる事にしましょう。

Picamera2.set_controlsメソッド

 オートフォーカスを始めカメラの様々な機能を調整するにはPicamera2.set_controlsメソッドを用います。調整する項目は多義に渡るため、このメソッドは連想配列(辞書)で値を設定します。

libcameraライブラリのcontrolsモジュール

 set_controlsメソッドに引き渡せる値はlibcameraライブラリにあるcontorlsモジュールで定義される値です。そのためこのモジュールをimportしてあげる必要があります。

オートフォーカスを連続的に稼働

 では具体的な所を。オートフォーカスと言うと動く被写体にカメラを向けた時に「きゅいきゅい」っと自動的にピントを調節してくれるあれでしょう。被写体までの距離が変わっても追従してピントを合わせてくれるので便利です。それを実現するにはオートフォーカスモード(AfMode)をContiunuousに設定します。具体的なコードを見た方が早いので、こちらをご覧下さい:

from picamera2 import Picamera2, Preview
from libcamera import controls
import time

pc2 = Picamera2()
pc2.start_preview( True )

# start後じゃないとset_controlsは動作しない
pc2.start()

# Continuousに変更
#  オートフォーカスが自動的に継続的に行われる
pc2.set_controls( {"AfMode" : controls.AfModeEnum.Continuous} )

time.sleep( 10 )

 set_controlsを使うためにlibcameraライブラリのcontrolsモジュールをインポートしています。プレビューウィンドウを起動した後にstartメソッドでカメラも起動します。

 オートフォーカスモードを設定するにはset_controlsメソッドでキーを"AfMode"、値をcontrols.AfModeEnum.Continuousと指定します。これだけでオートフォーカスがきゅいきゅいっと連続的に動いてくれます!

カメラ動作後じゃないと反応しないので注意

 set_controlsメソッドは動作中のカメラに対して有効です。その為値を反映するにはPicamera2.start()でカメラを動作させた後にset_controlsする必要があります。これ僕は嵌りまして、set_controlsを先に設定しその後にstartしてもオートフォーカスしてくれず、暫く首を傾げてました。

動作を一時停止

 きゅいきゅい動き続ける動作を一時停止したい時には、set_controlsメソッドにAfPauseをキーとして、contorls.AfPauseEnum.DefferdもしくはImmediateを指定します:

#オートフォーカスを調整

from picamera2 import Picamera2, Preview
from libcamera import controls
import time

pc2 = Picamera2()

pc2.start_preview( True )

# start後じゃないとset_controlsは動作しない
pc2.start()

# Continuousに変更
#  オートフォーカスが自動的に継続的に行われる
print( "start" )
pc2.set_controls( {"AfMode" : controls.AfModeEnum.Continuous} )
time.sleep( 5 )

# 一時停止
#  Defferdは今のフォーカス中動作が終わったら一時停止する
print( "deferred" )
pc2.set_controls( {"AfPause" : controls.AfPauseEnum.Deferred} )
time.sleep( 10 )

# 再始動
print( "resume" )
pc2.set_controls( {"AfPause" : controls.AfPauseEnum.Resume} )
time.sleep( 5 )

# AFを即一時停止
print( "immediate" )
pc2.set_controls( {"AfPause" : controls.AfPauseEnum.Immediate} )
time.sleep( 5 )

 上のコードは起動後にオートフォーカスをContinuousで5秒動かし続けた後Deferredにより一時停止をかけています。ただしカメラがスキャン中の場合は停止しません。その後Continuousを再始動し、さらに5秒後今度はImmediateで即停止を試みます。

 実際動かしてみると、ん~、動作している感じはありますが、カメラが「スキャン中」か否かを見た目だけでは判断できない所もあり、Deferred指定しているけどオートフォーカスし続けるとか、Immediateかけたけど止まってない?みたいな挙動もありました。使い処が難しい指定かもしれません(-_-;

オートフォーカスを指定した時だけ稼働

 Continuousは便利なのですが、都度ピントを合わせようと頑張るので時にそれが余計なおせっかいになる事があります。例えばカメラを移動させた後にピントを合わせてくれるだけで充分、という事も良くあります。そういう場合はAfModeをcontrols.AfModeEnum.Autoに指定します:

#オートフォーカスを調整

from picamera2 import Picamera2, Preview
from libcamera import controls
import time

pc2 = Picamera2()

pc2.start_preview( True )

# start後じゃないとset_controlsは動作しない
pc2.start()

# オートフォーカスモードをAutoに設定
#  controls.AfTriggerEnum.Startでオートフォーカス開始
#  動作をキャンセルするときはCancelを指定
pc2.set_controls( {"AfMode" : controls.AfModeEnum.Auto} )
time.sleep( 2 )

# オートフォーカス開始
pc2.set_controls( {"AfTrigger" : controls.AfTriggerEnum.Start} )
time.sleep( 3 )

# オートフォーカス動作をキャンセル
pc2.set_controls( {"AfTrigger" : controls.AfTriggerEnum.Cancel} )
time.sleep( 8 )

 Autoを指定した場合、それだけではオートフォーカスしてくれません。あくまでもモードを設定しただけなので「動け!」と命令するまでは停止したままなんです。

 その「動け!」という命令もset_controlsで行います。AfTriggerをキーとしcontrols.AfTriggerEnum.Startを値として渡すとオートフォーカスを開始してくれます。取り付けたカメラが持っているフォーカス機能を駆使してきゅいきゅいとピントを合わせ、ピントが合ったと判断された所で動作を終了します。その後はまた「動け!」と言われるまでピント合わせはしてくれません。

 時にAutoでオートフォーカスを開始した後それを取りやめたい事もあります。その場合はAfTriggerにcontrols.AfTriggerEnum.Cancelを指定するとキャンセルが入ります。これは割とパキっと停止してくれました。

オートフォーカスの速度を指定

 カメラモジュールによってはオートフォーカスの速度を速くする事が出来ます。それを指定するにはAfSpeedをキーにしてcontrols.AfSpeedEnum.Fastを与えます:

#オートフォーカスを調整

from picamera2 import Picamera2, Preview
from libcamera import controls
import time

pc2 = Picamera2()

pc2.start_preview( True )

# start後じゃないとset_controlsは動作しない
pc2.start()

# Continuousに変更
#  オートフォーカスが自動的に継続的に行われる
print( "start" )
pc2.set_controls( {"AfMode" : controls.AfModeEnum.Continuous} )

# フォーカス速度を高速にしてみる
#  対応しないカメラもあるので注意
pc2.set_controls( {"AfSpeed" : controls.AfSpeedEnum.Fast} )
time.sleep( 10 )

 僕が取り付けた64MP HAwk-eyeの場合、んー…変わってないかな(^-^;;。心の目で見ると速くなっているかも…。カメラモジュールが対応していれば反応するんでしょう。

 速度を通常に戻す場合はcontrols.AfSpeedEnum.Normalを指定します。

オートフォーカスが機能する距離感を設定

 例えばあまりに近しい対象物に対してはフォーカスして欲しくない事があります。景色を撮影している時に目の前に何かが横切ったとして、きゅいきゅいっとそれにオートフォーカスするのは避けたい…みたいな。逆に非常に近い物にピントを合わせている時に遠くの景色にフォーカスして欲しくないというケースも考えられます。

 そういう時にAfRangeをキーとしてざっくりとしたフォーカスの距離感を調整する機能があります:

#オートフォーカスを調整

from picamera2 import Picamera2, Preview
from libcamera import controls
import time

pc2 = Picamera2()

pc2.start_preview( True )

# start後じゃないとset_controlsは動作しない
pc2.start()

# Continuousに変更
#  オートフォーカスが自動的に継続的に行われる
print( "start" )
pc2.set_controls( {"AfMode" : controls.AfModeEnum.Continuous} )

# フォーカスの距離感をMacroに指定
pc2.set_controls( {"AfRange" : controls.AfRangeEnum.Macro} )
time.sleep( 10 )

 AfRangeでcontrols.AfRangeEnum.Macroを指定するとごく近い対象物にピントを合わせるようになります。
 一方でそういう近距離のは除くもっと遠い位置にある物にフォーカスするにはcontrols.AfRangeEnum.Normalを指定します。
 マクロ距離もノーマル距離も含むどんな位置にも頑張ってフォーカスさせるにはcontrols.AfRangeEnum.Fullを設定します。

 こちらも試してみたのですが、僕の環境だとはっきりとした違いは見受けられませんでした。マクロがどのくらいの距離なのかはカメラモジュールによって違うと思われるので、それが分かれば差異を感じられるかもしれません。

マニュアルフォーカス…その前に

 もちろんオートフォーカスを使いたくない状況も良くあります。オートフォーカスは大抵一番手前の対象物にピントを合わせますが「いや、俺がピント合わせたいのもっと後ろの被写体だし!」って思う事あります。そういう時はマニュアルフォーカスに切り替えて手動でピントを合わせます。

 マニュアルなので被写体までの距離とか云々をこちらで指定しなければなりません。この指定自体は単純です。でも、マニュアル操作で寧ろ必要なのは「プレビューを見ながら調整する仕組み」かと思うんです。つまり、動作しているカメラに対して外部から値を与え変更するという枠組み。これが無いとマニュアル操作はあまり意味を成しません。

 という事で、次回はマニュアル操作を実践する前に「起動中のカメラにリアルタイムに外部からパラメータを指定する」という枠組みを考えてみようと思います。

ではまた(^-^)/

<次回>

この記事が気に入ったらサポートをしてみませんか?