ã¡ãœããèªäœã«å ããŠããã®èšäºã§ã¯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
ãªããžã§ã¯ãã®è¿œè·¡ãéå§ããã«ã¯ãã¯ãªãã¯ããå¿ èŠããããŸãã
ããã ãã§ã