War Thunder – PS4 – Headtracking SELBSTGEMACHT – FINAL

2 Point Head Tracking,
1 not moving referenz point (at your nacklace)
1 moving point on a wooden bar on your helmet
60 frames per second, stable

 

benötigte Hardware:
– PS3 Eye Cam ( very high framerates )
– PC/Laptop ( DualCore 2×1,8GHz, 4GB, Win7 )
– USB Serial Light Adapter
– Arduino Leonardo
– PS4
– evtl. USB Hub
– LED infrared, 2 pieces
– Resistors 100 Ohm, 2 pieces
– Batteries/Accus, AA 1.2V , 4 pieces
– Batterie Case with switch, 2 pieces
– helmet or similar else
– wooden bar or similar else
– duct tape

Hardware Hacks:
– PS3 Eye Cam – IR blocking Filter entfernen und Tageslicht blocking filter (Diskette) einsetzen

Software:
– PC/Laptop – Windows Treiber der PS3 Eye Cam
– PC/Laptop – Python 2.7.3
– PC/Laptop – openCV
– PC/Laptop – pyserial
– PC/Laptop – Arduino IDE
– Arduino Leonardo – extra sketch

Following script holds everything together:
– reading camera stream,
– analysing, finding blobs,
– calculating distances,
– calculating movement between current versus previous frame
– sending relative movement over USBSerialLight Adapter to ArduinoLeonardo

import cv2
import time
import numpy 

# python C:\python_scripts\opencv\cam_vid_60fps_binarized_flipped_blobs_SERIAL.py

##########################################
# setting up serial communication

import serial
#import time
import os




"""
C:\Users\XXXXX>python -m serial.tools.list_ports -a
Usage: list_ports.py [options] []

list_ports.py: error: no such option: -a
"""
# C:\Python27\Lib\site-packages\serial\tools\list_ports.py  <<< look for options.. discoverd -v ! write_to_path = "C:\\python_scripts\\py_serial\\actual_com_ports.txt" os.system("python -m serial.tools.list_ports -v > " + write_to_path)

fr = open( write_to_path , "rb")
frc = fr.read()
fr.close()

"""
COM14               
    desc: Arduino Uno (COM14)
    hwid: USB VID:PID=2341:0001 SNR=55330343831351D03232
COM9                
    desc: Arduino Leonardo (COM9)
    hwid: USB VID:PID=2341:8036
2 ports found
"""

frc = str(frc).split("\n")

com_dict = {}
COM_id = ""
for line in frc:
   #print line
   if line[0:3] == "COM":
    
     COM_id = line.strip()
     #print "COM_id: ",COM_id
     com_dict[COM_id]  =  ""
     
   if line.find("desc:") != -1:
    line2 = line
    line2 = line2.replace("desc: ","")
    line2 = line2.replace("("+COM_id+")","")
    line2 = line2.replace("\t","")
    line2 = line2.strip()
    #print "line2: >>",line2,"<<"
    com_dict[COM_id] = line2
    
    
arduino_leonardo_COMport = ""
arduino_uno_COMport = ""

for e in com_dict:
    print e, ": ", com_dict[e]
    
    if com_dict[e].lower().find("leonardo")!=-1:
      arduino_leonardo_COMport = e
    if com_dict[e].lower().find("uno")!=-1:
      arduino_uno_COMport = e

print "arduino_uno_COMport: ",arduino_uno_COMport
print "arduino_leonardo_COMport: ",arduino_leonardo_COMport




if 1==1:

  #COMport = 14
  #serial_port = COMport-1
  #serial_port = "COM14"
  #serial_port = "COM11"
  #serial_port = arduino_leonardo_COMport
  serial_port = arduino_uno_COMport

  baudrate = 9600

  connected = False

  
  """
  ser = serial.Serial(port=serial_port,
baudrate=baudrate,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_TWO,
bytesize=serial.EIGHTBITS,
timeout=0,
xonxoff=0,
rtscts=0)
        """
        
        
  ser = serial.Serial( serial_port, baudrate)  # open first serial port
  #ser.DtrEnable = "true";
  
  print("initialising")
  time.sleep(2) # waiting the initialization...

  print ser.name          # check which port was really used


# EOF setting up serial
######################################################
#

# python C:\python_scripts\opencv\cam_vid_60fps_binarized_flipped_blobs_SERIAL.py

# http://docs.opencv.org/trunk/doc/py_tutorials/py_gui/py_video_display/py_video_display.html


#cam = cv2.VideoCapture(0) # laptop eingebaute cam
#cam = cv2.VideoCapture(1) # wenn direct am laptop
cam = cv2.VideoCapture(1)

print "cam.isOpened(): ",cam.isOpened()

# - CV_CAP_PROP_FPS Frame rate.
#print "FPS: ", cam.get( 10 ) # ? ret
#print "x: ", cam.GetCaptureProperty( CV_CAP_PROP_FPS )
print "CV_CAP_PROP_FRAME_WIDTH:  ", cam.get(3)
print "CV_CAP_PROP_FRAME_HEIGHT: ", cam.get(4)
print "CV_CAP_PROP_FPS:          ", cam.get(5)
# cam.get(propId)   
# propId integer 0 bis 18

if 1==11:
   size = (int(cv2.GetCaptureProperty(cam , cv2.CV_CAP_PROP_FRAME_WIDTH)), int(cv2.GetCaptureProperty(cam , cv2.CV_CAP_PROP_FRAME_HEIGHT)))
   print "size: ",size


"""
Property identifier. It can be one of the following:
0 CV_CAP_PROP_POS_MSEC Current position of the video file in milliseconds or video capture timestamp.
1 CV_CAP_PROP_POS_FRAMES 0-based index of the frame to be decoded/captured next.
2 CV_CAP_PROP_POS_AVI_RATIO Relative position of the video file: 0 - start of the film, 1 - end of the film.
3 CV_CAP_PROP_FRAME_WIDTH Width of the frames in the video stream.
4 CV_CAP_PROP_FRAME_HEIGHT Height of the frames in the video stream.
5 CV_CAP_PROP_FPS Frame rate.
6 CV_CAP_PROP_FOURCC 4-character code of codec.
7 CV_CAP_PROP_FRAME_COUNT Number of frames in the video file.
8 CV_CAP_PROP_FORMAT Format of the Mat objects returned by retrieve() .
9 CV_CAP_PROP_MODE Backend-specific value indicating the current capture mode.
10 CV_CAP_PROP_BRIGHTNESS Brightness of the image (only for cameras).
11 CV_CAP_PROP_CONTRAST Contrast of the image (only for cameras).
12 CV_CAP_PROP_SATURATION Saturation of the image (only for cameras).
13 CV_CAP_PROP_HUE Hue of the image (only for cameras).
14 CV_CAP_PROP_GAIN Gain of the image (only for cameras).
15 CV_CAP_PROP_EXPOSURE Exposure (only for cameras).
16 CV_CAP_PROP_CONVERT_RGB Boolean flags indicating whether images should be converted to RGB.
17 CV_CAP_PROP_WHITE_BALANCE Currently not supported
18 CV_CAP_PROP_RECTIFICATION Rectification flag for stereo cameras (note: only supported by DC1394 v 2.x backend currently)
"""

if 1==11:

        cam.set(3,320) # CV_CAP_PROP_FRAME_WIDTH
        cam.set(4,240) # CV_CAP_PROP_FRAME_HEIGHT

cam.set(5,100) # fps
print "cam get fps: ", cam.get(5) # fps


# 'module' object has no attribute 'createBackgroundSubtractorMOG'
#fgbg = cv2.BackgroundSubtractorMOG()
#fgbg = cv2.BackgroundSubtractorMOG2()

counter_frames = 0
start_time = time.time()
fps = 0

# http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.html
#kernel = numpy.ones((2,2),numpy.uint8)
#kernel = numpy.ones((5,5),numpy.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
#kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
#kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
#kernel = numpy.ones((10,10),numpy.uint8)

cv2__THRESH_BINARY = cv2.THRESH_BINARY
cv2__flip          = cv2.flip
cv2__morphologyEx  = cv2.morphologyEx
cv2__MORPH_OPEN    = cv2.MORPH_OPEN
cv2__MORPH_CLOSE   = cv2.MORPH_CLOSE
cv2__imshow        = cv2.imshow
cv2__waitKey       = cv2.waitKey

if 1==11:
   flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
   for flag in flags:
    if flag.find("RGB")!=-1:
       print flag
       # COLOR_RGB2GRAY


prev_frame_dist_x = 999999  #init  value
prev_frame_dist_y = 999999 # init value

while(True):     

        
        ret, frame = cam.read()
        
        #cv2.imshow('frame', frame)
        
        # Our operations on the frame come here
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        
        #gray = cv2.cvtColor(frame, cv2.THRESH_BINARY)
        tresh = 253
        #tresh = 200
        ret,frame = cv2.threshold(frame,tresh,255,cv2__THRESH_BINARY )
        frame = cv2__flip(frame, 1) # 
        
        #print "frame.dtype: ",frame.dtype

        # http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.html

        #frame = cv2.erode(frame,kernel,iterations = 1)
        frame = cv2.dilate(frame,kernel,iterations = 2)
        #frame = cv2.erode(frame,kernel,iterations = 3)
        #frame = cv2__morphologyEx(frame, cv2__MORPH_OPEN, kernel) # erosion followed by dilation
        #frame = cv2__morphologyEx(frame,  cv2.MORPH_TOPHAT, kernel) 
        #frame = cv2.morphologyEx(frame, cv2.MORPH_GRADIENT, kernel) # does outline
        cv2__imshow('frame', frame)
        
        #print "frame.dtype: ",frame.dtype

        #fgmask = fgbg.apply(frame)
        #cv2.imshow('frame',fgmask)
        
		
        #x = cv2.cvtColor(frame, cv2.CV_SHAPE_CROSS)    
        #cv2.imshow('frame', x)



        #frame = cv2.convertTo(frame, CV_8U)
     
        # http://opencvpython.blogspot.de/2012/04/contour-features.html
        contours, _ = cv2.findContours(frame, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
        contour_number = 0
        contours_dict = {}

        for c in contours:

            rect = cv2.boundingRect(c)

            # rect[2]   width
            # rect[3]   height
            # sucht nur grosse blobs, alles kleiner 10x10 wird verworfen
            if rect[2] < 10 or rect[3] < 10: continue
            contour_number = contour_number+1
            
            print "contour_number: ",contour_number
            #print cv2.contourArea(c)
            print rect # x,y width,height
            contours_dict[contour_number] = rect
            print 

            if contour_number == 2:
               con1_x = contours_dict[1][0]
               con2_x = contours_dict[2][0]

               diff_con1_x_con2_x = con1_x - con2_x
               print "diff_con1_x_con2_x: ", diff_con1_x_con2_x


               con1_y = contours_dict[1][1]
               con2_y = contours_dict[2][1]

               diff_con1_y_con2_y = con1_y - con2_y
               print "diff_con1_y_con2_y: ", diff_con1_y_con2_y

               if diff_con1_x_con2_x != 999999: # 999999 is starting init val

                  diff_prev_frame_x = diff_con1_x_con2_x - prev_frame_dist_x
                  print "diff_prev_frame_x: ",diff_prev_frame_x
                  # x negativ value = move to the right
                  # x positiv value = move to the left
                  diff_prev_frame_y = diff_con1_y_con2_y - prev_frame_dist_y
                  # y negativ value = move to bottom
                  # y positiv value = move to top
                  print "diff_prev_frame_y: ",diff_prev_frame_y

                  # send these values to arduino
                  # diff_prev_frame_x
                  # diff_prev_frame_y
                  # or manipulate them multiple 2 or progressive
                  diff_prev_frame_x = diff_prev_frame_x * -1
                  
                  # ABSoluter wert, positiv.. d.h negativ number positiv machen
                  ABS_x = diff_con1_x_con2_x
                  if diff_con1_x_con2_x < 0:
                     ABS_x = diff_con1_x_con2_x * -1
                  ABS_y = diff_con1_y_con2_y
                  if diff_con1_y_con2_y < 0:
                     ABS_y = diff_con1_y_con2_y * -1

                  print "ABS_x: ",ABS_x
                  print "ABS_y: ",ABS_y

                  if ABS_x < 100:
                     diff_prev_frame_x = diff_prev_frame_x * 2 # 2
                  else:                     
                     diff_prev_frame_x = diff_prev_frame_x * 4

                  # 240 center point y
                  #  280
                  if ABS_y > 200 or ABS_y < 280:                      diff_prev_frame_y = diff_prev_frame_y * 4 # 4                   else:                      diff_prev_frame_y = diff_prev_frame_y * 8                   ser.write( str(diff_prev_frame_x) + "," + str(diff_prev_frame_y) + "\n" )                prev_frame_dist_x = diff_con1_x_con2_x                prev_frame_dist_y = diff_con1_y_con2_y                # now map the distances                # to mouse movements                # mouse movement                 # there is an posiblity to use absolute mouse via arduino,                 # http://forum.arduino.cc/index.php?topic=94140.0                # http://arduino.stackexchange.com/questions/3531/using-leonardo-and-getting-absolute-x-y-mouse-values                # WE NEED DATA FROM PREV FRAME                # CALC differences                # these differences map to mouse moves             #print rect.bx,rect.by #,c.bw,c.bh         #frame = cv2.drawContours(frame, contours, -1, (0,255,0), 3) 		         # to quit press key "q"         if cv2__waitKey(1) & 0xFF == ord('q'):             break 	          if 1==1:               counter_frames = counter_frames + 1                       #print "counter_frames: ",counter_frames 	                 cur_time = time.time()               #print "start_time: ",start_time               #print "cur_time: ",cur_time               diff_time = cur_time - start_time               #print "diff_time: ",diff_time               if diff_time > 5: # 5 sekunden
                 fps = counter_frames / 5 # frames pro sekunde		 
                 counter_frames = 0
                 start_time = time.time()
                 print "fps: ",fps
        print "fps: ",fps
	  
	  
	  
cam.release()
cv2.destroyAllWindows()

Sketch for Arduino Leonardo

/*
  Serial1-Mouse-Control 
 
 
 The mouse movement is always relative. 
 This sketch reads Serial1(RxTx) and uses incoming data 
 to set the movement of the mouse (over Serial, Main USB Port).
 
 WARNING:  When you use the Mouse.move() command, the Arduino takes
 over your mouse!  Make sure you have control before you use the mouse commands.
 
2015-02
Ronny Gey
  
*/


#include 


// read string
String mouse_x = "";
String mouse_y = "";
  
  
void setup() {
  
  // http://arduino.cc/en/pmwiki.php?n=Reference/Serial
  // http://arduino.cc/en/Main/ArduinoBoardLeonardo
  
  // Serial not needed, this is used by mouse control...
  // only for string tests, debugging
  //Serial.begin(9600); // first Serial Port, main USB port... OR sending to PS4
  //while (!Serial) {
  //  ; // wait for serial port to connect. Needed for Leonardo only
  //}
  
  // second Serial Port on Leonardo! pins Rx(Pin0)/Tx(Pin1) for receiving data from Laptop
  Serial1.begin(9600); 
  while (!Serial1) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  
  // initialize mouse control:
  Mouse.begin();
}

void loop() {
  // read Serial_1, data coming from Laptop

  // send data only when you receive data:
  // read RxTx
  if (Serial1.available() > 0) {
    
      // getting x,y from Laptop over Serial1
      // Kommaseparated value: x,y\n
      // -10,5
      // 5,-10
      // 10,10
      mouse_x = Serial1.readStringUntil(',');
      mouse_y = Serial1.readStringUntil('\n');
      //Serial1.print("I received X,Y: ");
      //Serial1.print(mouse_x);
      //Serial1.print(" : ");
      //Serial1.println(mouse_y); 
      
      //Syntax:  Mouse.move(xVal, yPos, wheel);
      Mouse.move(mouse_x.toInt(), mouse_y.toInt(), 0);
      // http://arduino.cc/en/Tutorial/StringToIntExample     
     
  } // EOF serial1 available
   
 
  /* only for debugging purpose
  // send data only when you receive data:
  if (Serial.available() > 0) {
      
      // getting x,y from Laptop over Serial1
      // comma separated value: x,y\n
      // -10,5
      // 5,-10
      // 10,10
      mouse_x = Serial.readStringUntil(',');
      mouse_y = Serial.readStringUntil('\n');
      Serial.print("I received X,Y: ");
      Serial.print(mouse_x);
      Serial.print(" : ");
      Serial.println(mouse_y);     

     
  } // EOF serial available
  */  
        
}

thats all

 

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.