物䜓たでの距離ずその速床の枬定

私が玹介するテクノロゞヌは、画像内のオブゞェクトたでの距離を決定するために芋぀けた方法で䌚っおいたせん。 それは普遍的でも耇雑でもありたせん。その本質は、可芖フィヌルドビデオカメラを䜿甚しおいるず仮定したすがルヌラヌで調敎され、画像内のオブゞェクトの座暙がルヌラヌ䞊のマヌクず比范されるずいう事実にありたす。 ぀たり、枬定は1本の線たたは軞に沿っお実行されたす。 ただし、ピクセルごずにルヌラヌにマヌクを保存する必芁はありたせん。キャリブレヌションのアルゎリズムは、ピクセルずメヌトルでのルヌラヌのサむズず、ルヌラヌの実際の真ん䞭のピクセルの座暙を知るだけで枈みたす。 明らかな制限は、平面䞊でのみ機胜するこずです。



メ゜ッド自䜓に加えお、この蚘事ではOpenCVラむブラリを䜿甚したPythonでの実装に぀いお説明し、video4linux2 APIを䜿甚しおLinuxのWebカメラから画像を取埗する機胜に぀いおも説明したす。











実際には、道路の盎接区間で車たでの距離ず速床を枬定する必芁がありたした。 長い巻尺を䜿甚し、キャンバスの䞭倮で道路に沿っお䌞ばし、カメラをセットアップしお、巻尺党䜓がカメラの芖野に入り、画像のX軞に合わせられるようにしたした。 次のステップは、ルヌレットの䞭倮に明るいものを眮き、カメラがどこにも動かないように修正し、この䞭倮のピクセル座暙を蚘録するこずでした。



すべおの蚈算は1぀の匏にたずめられたす。

l = L * K /W / x-1 + K 、ここで

lはオブゞェクトたでの必芁距離、m;

Lは「ラむン」の長さ、mです。

W-ピクセル単䜍の「ルヌラヌ」の長さ。通垞は画像の幅ず同じです。

xは、画像内のオブゞェクトの座暙です。

K =W-M/ Mはカメラの傟きを反映する係数です。ここで、 Mは「ルヌラヌ」の䞭倮の座暙です。



この公匏の結論ずしお、䞉角法の孊校知識は私にずっお非垞に有甚でした。



この関数の䟝存関係グラフを図に瀺したす









カメラの傟きが倧きいほど、グラフが急募配になりたす。 境界の堎合、カメラの軞が「ルヌラヌ」の平面に垂盎に向けられるず M = W / 2 、グラフは盎線になりたす。



しかし、蚘事はそこで終わるだけでは短すぎたす。 そのため、コンピュヌタヌのWebカメラに接続しおオブゞェクトを監芖し、その距離ず速床を蚈算するデモプログラムを䜜成するこずにしたした。 プログラミング蚀語ずしお、非垞に倚くの利点を備えたPythonを遞択したした。たた、Pythonに付属するTkinterフレヌムワヌクを遞択しおグラフィカルむンタヌフェむスを構築したため、個別にむンストヌルする必芁はありたせん。 OpenCVはオブゞェクトの远跡に適しおいたす。バヌゞョン2.2を䜿甚しおいたすが、珟圚のubuntuバヌゞョン10.10のリポゞトリにはバヌゞョン2.1のみがあり、APIが少し倉曎されおおり、バヌゞョン2.1のプログラムは機胜したせん。 原則ずしお、グラフィカルむンタヌフェむスず画像キャプチャの機胜を割り圓おるこずでOpenCVでプログラム党䜓を構築するこずは可胜ですが、プログラムの䞻芁郚分から分離しお、このラむブラリを別のものに眮き換えたり、远跡をオフにしお削陀できるようにしたかったのです。 私は叀いプログラムを䜜り盎し、䞍芁なものをすべお削陀したしたが、驚いたこずに、距離ず速床の盎接蚈算で残された行はわずかでした。原理的に論理的でしたそしお、りェブカメラの代わりに、RTSP接続のメガピクセルネットワヌクカメラが䜿甚されたす。



りェブカメラから画像を取埗するこずに関しおは、それほど単玔ではありたせん。 Windowsでは、プログラムはDirectXを䜿甚しおVideoCaptureラむブラリを介しおカメラに接続したす。ここではすべおが非垞に簡単です。 しかし、Linuxでは、PythonのWebカメラの䜿甚に関するわかりやすい蚘事はほずんどありたせん。たた、通垞、いく぀かの新しいAPIの倉曎により動䜜䞍胜になる䟋もありたす。 以前は、これらの目的でffmpegを䜿甚し、プログラムはCでしたが、ffmpegは少し「銃雀」であり、最終的なプログラムに远加の䟝存関係を負わせたくありたせんでした。 ffmpegも䜿甚するOpenCVを䜿甚できたすが、独自のPython甚ラッパヌvideo4linux2 APIを䜜成する方法が遞択されたした。



゜ヌスコヌドはある孊科のペヌゞから取られたした。 これらのうち、私は目的に䞍芁なものをすべおすぐに削陀し、最終的に2぀の線集枈みファむルV4L2.cpp



ずV4L2.h



実際、これはWebカメラに接続するために最䜎限必芁なAPIです。 Pythonのラッパヌの䜜業䞭に、video4linux2デバむスには、READ、MMAP、およびSTREAMの3぀の方法でアクセスできるこずがわかりたしたが、私のWebカメラではMMAPメ゜ッドのみが機胜したす。 結局のずころ、私にずっおうたくいかなかったプログラムの他の䟋では、READメ゜ッドを䜿甚したした。



たた、りェブカメラはYUYV圢匏YUV422の画像を提䟛し、RGBずは異なり、色情報が2倍少ないこずも理解されおいたす。 YUYVでは、2぀のピクセルが4バむトで゚ンコヌドされ、RGBでは6バむトず぀゚ンコヌドされるため、節玄は1.5倍になりたす。 Yは、ピクセルごずに異なる茝床成分です。 UずVはピクセルの色を決定する色差コンポヌネントです。したがっお、2぀のピクセルごずにUずVの同じ倀を䜿甚したす。これらの衚蚘でWebカメラからのバむトストリヌムを衚す堎合、YUYV YUYV YUYV YUYV YUYV YUYV-this 12ピクセル。 VLCプレヌダヌを䜿甚しおWebカメラがどのフォヌマットで動䜜するかを確認し、それを䜿甚しおキャプチャデバむスを開き、コヌデックに関する情報を芁求できたす。図のようになりたす。









Webカメラにアクセスするためのラむブラリの゜ヌスコヌドは次のずおりです。

main_v4l2.cpp





 #include "V4L2.h" #include <cstring> #include <iostream> using namespace std; extern "C" { // Specify the video device here V4L2 v4l2("/dev/video0"); unsigned char *rgbFrame; float clamp(float num) { if (num < 0) num = 0; if (num > 255) num = 255; return num; } // Convert between YUV and RGB colorspaces void yuv2rgb(unsigned char y, unsigned char u, unsigned char v, unsigned char &r, unsigned char &g, unsigned char &b) { float C = y - 16; float D = u - 128; float E = v - 128; r = (char)clamp(C + ( 1.402 * E )) ; g = (char)clamp(C - ( 0.344136 * D + 0.714136 * E )) ; b = (char)clamp(C + ( 1.772 * D )) ; } unsigned char *getFrame() { unsigned char *frame = (unsigned char *)v4l2.getFrame(); int i = 0, k = 0; unsigned char Y, U, V, R, G, B; for (i=0;i<640*480*2;i+=4) { Y = frame[i]; U = frame[i+1]; V = frame[i+3]; yuv2rgb(Y, U, V, R, G, B); rgbFrame[k] = R; k++; rgbFrame[k] = G; k++; rgbFrame[k] = B; k++; Y = frame[i+2]; yuv2rgb(Y, U, V, R, G, B); rgbFrame[k] = R; k++; rgbFrame[k] = G; k++; rgbFrame[k] = B; k++; } return rgbFrame; } void stopCapture() { v4l2.freeBuffers(); } // Call this before using the device void openDevice() { // set format struct v4l2_format fmt; CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // Adjust resolution fmt.fmt.pix.width = 640; fmt.fmt.pix.height = 480; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; if (!v4l2.set(fmt)) { fprintf(stderr, "device does not support used settings.\n"); } v4l2.initBuffers(); v4l2.startCapture(); rgbFrame = (unsigned char *)malloc(640*480*3); } }
      
      





アルゎリズムは非垞に理解しやすいです-最初に名前が最初に䞎えられたデバむス「/ dev / video0」を開き、次にgetFrame



リク゚ストごずにりェブカメラからフレヌムを読み取り、RGB圢匏に倉換し、フレヌムぞのリンクをリク゚ストした人に䞎えたす。 必芁に応じお、このラむブラリをすばやくコンパむルするためのMakefile



も提䟛しおいたす。



そしお、Python甚のこのラむブラリのラッパヌは次のずおりです。

v4l2.py





 from ctypes import * import Image import time lib = cdll.LoadLibrary("linux/libv4l2.so") class VideoDevice(object): def __init__(self): lib.openDevice() lib.getFrame.restype = c_void_p def getImage(self): buf = lib.getFrame() frame = (c_char * (640*480*3)).from_address(buf) img = Image.frombuffer('RGB', (640, 480), frame, 'raw', 'RGB', 0, 1) return img, time.time()
      
      





ご芧のずおり、耇雑なこずはたったくありたせん。 ラむブラリはctypesモゞュヌルを䜿甚しお接続されたす。 次の行を陀いお、ラッパヌの䜜成に問題はありたせんでした。



 frame = (c_char * (640*480*3)).from_address(buf)
      
      





私はすぐには来たせんでした。 実際には、 getFrame()



からc_char_p



ずしおデヌタを読み取るず、ctypesはデヌタをれロで終わる文字列ずしお解釈したす。぀たり、バむトストリヌムでれロが怜出されるずすぐに読み取りが停止したす。 同じ蚭蚈により、読み取るバむト数を明確に指定できたす。 私たちの堎合、それは垞に固定倀-640 * 480 * 3です。



ここでは、Windowsで画像を取埗するための゜ヌスコヌドは提䟛したせんが、耇雑さにも違いはなく、 directx.py



ずいう名前のwindows



フォルダヌのアヌカむブにwindows



たす。



そしお、OpenCVを䜿甚しお蚘述されたオブゞェクトの远跡クラスの゜ヌスコヌドを匕甚したほうがよいでしょう。 OpenCVに同lkdemo.py



れおいるlkdemo.py



䟋を䟋ずしお取り䞊げ、クラスに倉換するこずでニヌズに合わせお再床単玔化したした。

tracker.py





 class Tracker(object): "Simple object tracking class" def __init__(self): self.grey = None self.point = None self.WIN_SIZE = 10 def target(self, x, y): "Tell which object to track" # It needs to be an array for the optical flow calculation self.point = [(x, y)] def takeImage(self, img): "Loads and processes next frame" # Convert it to IPL Image frame = cv.CreateImageHeader(img.size, 8, 3) cv.SetData(frame, img.tostring()) if self.grey is None: # create the images we need self.grey = cv.CreateImage (cv.GetSize (frame), 8, 1) self.prev_grey = cv.CreateImage (cv.GetSize (frame), 8, 1) self.pyramid = cv.CreateImage (cv.GetSize (frame), 8, 1) self.prev_pyramid = cv.CreateImage (cv.GetSize (frame), 8, 1) cv.CvtColor (frame, self.grey, cv.CV_BGR2GRAY) if self.point: # calculate the optical flow new_point, status, something = cv.CalcOpticalFlowPyrLK ( self.prev_grey, self.grey, self.prev_pyramid, self.pyramid, self.point, (self.WIN_SIZE, self.WIN_SIZE), 3, (cv.CV_TERMCRIT_ITER|cv.CV_TERMCRIT_EPS, 20, 0.03), 0) # If the point is still alive if status[0]: self.point = new_point else: self.point = None # swapping self.prev_grey, self.grey = self.grey, self.prev_grey self.prev_pyramid, self.pyramid = self.pyramid, self.prev_pyramid
      
      





たず、どのポむントを監芖するかを圌に䌝えなければなりたせん。これには、 target



メ゜ッドがありたす。 次に、 takeImage



メ゜ッドを䜿甚しおフレヌムごずにそれを䞎え、画像フレヌムを理解できる圢匏に倉換し、操䜜に必芁な画像アルゎリズムを䜜成し、フレヌムをカラヌからグレヌの濃淡に転送し、これらのすべおの関数をCalcOpticalFlowPyrLK



送りたすルヌカス・カナダのピラミッド法。 この関数の終了時に、远跡しおいるポむントの新しい座暙を取埗したす。 ポむントが倱われた堎合、 status[0]



はれロになりたす。 光束は、1点だけでなく蚈算できたす。 りェブカメラでlkdemo.py



を実行し、倚くのポむントをうたく凊理しおいるこずを確認したす。



たた、Python Imaging Libraryの画像をOpenCV圢匏に倉換するこずに぀いおも説明したす。実際、カラヌ画像のOpenCVは異なる順序の色成分を䜿甚したすcv.CvtColor(frame, frame, cv.CV_BGR2RGB)



、完党な倉換には、コヌドを行cv.CvtColor(frame, frame, cv.CV_BGR2RGB)



ですが、ほずんどのトラッキングアルゎリズムは色成分ず混同されおいるかどうかにかかわらず、たったく同じです。この䟋では通垞、癜黒画像のみを䜿甚しおいたす。 したがっお、この行をコヌドに含めるこずはできたせん。



たた、最も単玔な数孊しか存圚しないため、蚘事の距離を盎接蚈算するためのクラスの゜ヌスコヌドも提䟛しおいたせん。 ファむルdistance_measure.py



にありたす。



グラフィカルむンタヌフェむスを圢成し、他のすべおのモゞュヌルをロヌドするメむンスクリプトの゜ヌスコヌドを衚瀺するだけです。

main.py





 from distance_measure import Calculator from webcam import WebCam from tracker import Tracker from Tkinter import * import ImageTk as PILImageTk import time class GUIFramework(Frame): "This is the GUI" def __init__(self,master=None): Frame.__init__(self,master) self.grid(padx=10,pady=10) self.distanceLabel = Label(self, text='Distance =') self.distanceLabel.grid(row=0, column=0) self.speedLabel = Label(self, text='Speed =') self.speedLabel.grid(row=0, column=1) self.imageLabel = None self.cameraImage = None self.webcam = WebCam() # M = 510, L = 0.5, W = 640 self.dist_calculator = Calculator(500, 0.5, 640, 1) self.tracker = Tracker() self.after(100, self.drawImage) def updateMeasure(self, x): (distance, speed) = self.dist_calculator.calculate(x, time.time()) self.distanceLabel.config(text = 'Distance = '+str(distance)) # If you want get km/h instead of m/s just multiply # m/s value by 3.6 #speed *= 3.6 self.speedLabel.config(text = 'Speed = '+str(speed) + ' m/s') def imgClicked(self, event): """ On left mouse button click calculate distance and tell tracker which object to track """ self.updateMeasure(event.x) self.tracker.target(event.x, event.y) def drawImage(self): "Load and display the image" img, timestamp = self.webcam.getImage() # Pass image to tracker self.tracker.takeImage(img) if self.tracker.point: pt = self.tracker.point[0] self.updateMeasure(pt[0]) # Draw rectangle around tracked point img.paste((128, 255, 128), (int(pt[0])-2, int(pt[1])-2, int(pt[0])+2, int(pt[1])+2)) self.cameraImage = PILImageTk.PhotoImage(img) if not self.imageLabel: self.imageLabel = Label(self, image = self.cameraImage) self.imageLabel.bind("<Button-1>", self.imgClicked) self.imageLabel.grid(row=1, column=0, columnspan=2) else: self.imageLabel.config(image = self.cameraImage) # 30 FPS refresh rate self.after(1000/30, self.drawImage) if __name__ == '__main__': guiFrame = GUIFramework() guiFrame.mainloop()
      
      





䞊で蚀ったように、グラフィカルむンタヌフェむスを䜜成するためにTkinterラむブラリを遞択したした。たた、GTK、QT、そしおもちろんwxPythonなどの他のツヌルキットも䜿甚したしたが、Tkinterはすぐに動䜜したすが、䜿いやすいですが、もちろん、その䞊に耇雑なむンタヌフェむスを䜜成するこずはできたせんが、その機胜はタスクに十分すぎるほどです。 クラスの初期化では、 grid



を䜜成しお他のりィゞェットを配眮したす2぀のテキストフィヌルドず1぀の画像。 Tkinterを䜿甚するず、りェブカメラから画像をダりンロヌドするためのストリヌムを個別に䜜成する必芁さえありたせんでした。䞀定期間埌に指定された機胜を実行できるafter



メ゜ッドがあるからです。 Label



は、 config



メ゜ッドを䜿甚しおテキストず画像を曎新できたす。 ずおも簡単です bind



メ゜ッドを䜿甚したマりスクリックむベントの凊理は、 imgClicked



メ゜ッドに倉換されたす。



画像ずそのタむムスタンプはself.webcam.getImage



関数self.webcam.getImage



おself.webcam.getImage



たす。 Webカメラモゞュヌルは、プログラムが珟圚実行されおいるオペレヌティングシステムに応じお、Webカメラを操䜜するための適切なモゞュヌルのみをロヌドしたす。



もう䞀床、プログラム-distance-measureでアヌカむブぞのリンクを提䟛したす。

ubuntuに必芁なパッケヌゞpython、python-imaging、python-imaging-tk、opencvバヌゞョン2.2およびbuild-essentialはV4L2ラッパヌをコンパむルしたす。

プログラムは以䞋から開始したす。

python main.py





オブゞェクトの远跡を開始するには、クリックする必芁がありたす。



それだけです



䟿利なリンク






All Articles