summaryrefslogtreecommitdiff
path: root/mariokart.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mariokart.cpp')
-rw-r--r--mariokart.cpp885
1 files changed, 885 insertions, 0 deletions
diff --git a/mariokart.cpp b/mariokart.cpp
new file mode 100644
index 0000000..dc6eaa9
--- /dev/null
+++ b/mariokart.cpp
@@ -0,0 +1,885 @@
+/*
+ * unbenannt.cxx
+ *
+ * Copyright 2012 Unknown <flo@archie>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+
+#define FREEBSD
+//#define LINUX
+
+#include <vector>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <fcntl.h>
+
+#ifdef LINUX
+#include <linux/input.h>
+#include <linux/uinput.h>
+#endif
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include "util.h"
+#include "steer_interface.h"
+#include "naive_steerer.h"
+#include "road_thresholder_iface.h"
+#include "road_thresholder.h"
+
+#include <iostream>
+#include <list>
+#include <xcb/xcb.h>
+#include <assert.h>
+
+#include <opencv2/opencv.hpp>
+
+using namespace std;
+using namespace cv;
+
+class XorgGrabber
+{
+ public:
+ XorgGrabber(const char* win_title);
+ ~XorgGrabber();
+ void read(Mat& mat);
+
+ private:
+ xcb_connection_t* conn;
+ xcb_window_t grabbed_win;
+ int grab_width, grab_height;
+ xcb_screen_t* grab_screen;
+ xcb_get_image_reply_t* img;
+
+};
+
+XorgGrabber::XorgGrabber(const char* win_title)
+{
+ conn=xcb_connect(NULL,NULL);
+
+ bool found_win=false;
+ grab_screen=NULL;
+ img=NULL;
+
+ /* Find configured screen */
+ const xcb_setup_t* setup = xcb_get_setup(conn);
+ for (xcb_screen_iterator_t i = xcb_setup_roots_iterator(setup);
+ i.rem > 0; xcb_screen_next (&i))
+ {
+ xcb_screen_t* scr = i.data;
+ xcb_query_tree_reply_t* reply = xcb_query_tree_reply( conn, xcb_query_tree(conn, scr->root), NULL);
+ if (reply)
+ {
+ int len = xcb_query_tree_children_length(reply);
+ xcb_window_t* children = xcb_query_tree_children(reply);
+ xcb_get_window_attributes_cookie_t* cookies = new xcb_get_window_attributes_cookie_t[len];
+ for (int i=0; i<len; ++i)
+ cookies[i]=xcb_get_window_attributes(conn, children[i]);
+
+ for (int i=0; i<len; ++i)
+ {
+ xcb_get_window_attributes_reply_t* attr =
+ xcb_get_window_attributes_reply (conn, cookies[i], NULL);
+
+
+ xcb_get_property_reply_t* title_reply = xcb_get_property_reply(conn,
+ xcb_get_property(conn, false, children[i], XCB_ATOM_WM_NAME, XCB_GET_PROPERTY_TYPE_ANY, 0, 128),
+ NULL );
+
+ if (!attr->override_redirect && attr->map_state == XCB_MAP_STATE_VIEWABLE)
+ {
+ char* title=(char*)(title_reply+1);
+ cout << title << endl;
+ if (strstr(title, win_title))
+ {
+ xcb_get_geometry_reply_t* geo;
+ geo = xcb_get_geometry_reply (conn, xcb_get_geometry (conn, children[i]), NULL);
+ if (geo)
+ {
+ grab_width=geo->width;
+ grab_height=geo->height;
+
+ free(geo);
+
+ grabbed_win=children[i];
+ found_win=true;
+
+ grab_screen=scr;
+ }
+ else
+ {
+ cerr << "geo==NULL!" << endl;
+ }
+ }
+ }
+
+ free(title_reply);
+ free(attr);
+ }
+
+ free(reply);
+ delete[] cookies;
+ }
+ else
+ {
+ cout << "xcb_get_setup failed" << endl;
+ }
+ }
+
+ if (found_win)
+ {
+ xcb_get_image_reply_t* img = xcb_get_image_reply (conn,
+ xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, grabbed_win,
+ 0, 0, grab_width, grab_height, ~0), NULL);
+
+
+
+ xcb_depth_iterator_t depth_iterator = xcb_screen_allowed_depths_iterator(grab_screen);
+
+ int ndepths=xcb_screen_allowed_depths_length(grab_screen);
+
+ for (int i=0; i<ndepths; ++i)
+ {
+ if (depth_iterator.data->depth == img->depth)
+ {
+ xcb_visualtype_t* visuals = xcb_depth_visuals(depth_iterator.data);
+ int nvisuals = xcb_depth_visuals_length(depth_iterator.data);
+
+ for (int j=0;j<nvisuals;j++)
+ {
+ if (visuals[j].visual_id==img->visual)
+ {
+ assert(visuals[j]._class==XCB_VISUAL_CLASS_TRUE_COLOR || visuals[j]._class==XCB_VISUAL_CLASS_DIRECT_COLOR);
+ cout << (int)visuals[j]._class << "," << XCB_VISUAL_CLASS_TRUE_COLOR << endl;
+ cout << visuals[j].red_mask << endl;
+ cout << visuals[j].green_mask << endl;
+ cout << visuals[j].blue_mask << endl;
+ break;
+ }
+ }
+
+ break;
+ }
+
+ xcb_depth_next(&depth_iterator);
+ }
+
+
+
+ int nformats = xcb_setup_pixmap_formats_length(setup);
+ xcb_format_t* formats = xcb_setup_pixmap_formats(setup);
+ for (int i=0;i<nformats;i++)
+ {
+ if (formats[i].depth==img->depth)
+ {
+ cout << (int)formats[i].bits_per_pixel << endl;
+ cout << (int)formats[i].scanline_pad << endl;
+ break;
+ }
+ }
+
+ cout << grab_width << "x" << grab_height << endl;
+
+ free(img);
+
+ }
+ else
+ {
+ throw string("FATAL: did not find window, exiting.");
+ }
+
+
+}
+
+XorgGrabber::~XorgGrabber()
+{
+ if (img) free(img);
+ xcb_disconnect(conn);
+}
+
+void XorgGrabber::read(Mat& mat)
+{
+ if (img) free(img);
+
+
+ // mat gets invalid when the next read() is called!
+ img = xcb_get_image_reply (conn,
+ xcb_get_image (conn, XCB_IMAGE_FORMAT_Z_PIXMAP, grabbed_win,
+ 0, 0, grab_width, grab_height, ~0), NULL);
+
+ mat = Mat(grab_height, grab_width, CV_8UC4, xcb_get_image_data(img));
+ mat.addref();
+}
+
+
+
+
+#define THROTTLE_CNT_MAX 10
+
+
+#ifdef FREEBSD
+typedef union {
+ unsigned int Value;
+ struct {
+ unsigned R_DPAD : 1;
+ unsigned L_DPAD : 1;
+ unsigned D_DPAD : 1;
+ unsigned U_DPAD : 1;
+ unsigned START_BUTTON : 1;
+ unsigned Z_TRIG : 1;
+ unsigned B_BUTTON : 1;
+ unsigned A_BUTTON : 1;
+
+ unsigned R_CBUTTON : 1;
+ unsigned L_CBUTTON : 1;
+ unsigned D_CBUTTON : 1;
+ unsigned U_CBUTTON : 1;
+ unsigned R_TRIG : 1;
+ unsigned L_TRIG : 1;
+ unsigned Reserved1 : 1;
+ unsigned Reserved2 : 1;
+
+ signed X_AXIS : 8;
+ signed Y_AXIS : 8;
+ };
+} BUTTONS;
+
+
+char* pack(const BUTTONS* buttons, char* buf)
+{
+ buf[0]= (buttons->A_BUTTON ? 1 : 0) +
+ (buttons->B_BUTTON ? 2 : 0) +
+ (buttons->L_TRIG ? 4 : 0) +
+ (buttons->R_TRIG ? 8 : 0) +
+ (buttons->Z_TRIG ? 16 : 0) +
+ (buttons->START_BUTTON ? 32 : 0) +
+ 128;
+
+ buf[1]= (buttons->R_DPAD ? 1 : 0) +
+ (buttons->L_DPAD ? 2 : 0) +
+ (buttons->U_DPAD ? 4 : 0) +
+ (buttons->D_DPAD ? 8 : 0) +
+ ((buttons->X_AXIS & 128) ? 16 : 0) +
+ ((buttons->Y_AXIS & 128) ? 32 : 0);
+
+ buf[2]= (buttons->R_CBUTTON ? 1 : 0) +
+ (buttons->L_CBUTTON ? 2 : 0) +
+ (buttons->U_CBUTTON ? 4 : 0) +
+ (buttons->D_CBUTTON ? 8 : 0);
+
+ buf[3]= (buttons->X_AXIS & 127);
+
+ buf[4]= (buttons->Y_AXIS & 127);
+
+ return buf;
+}
+#endif
+
+class Joystick
+{
+ public:
+ Joystick();
+ ~Joystick();
+ void steer(float dir, float dead_zone=0.0);
+ void throttle(float t);
+ void press_a(bool);
+
+
+ void process();
+ void reset();
+
+ private:
+#ifdef FREEBSD
+ BUTTONS buttons;
+ void send_data();
+ int fifo_fd;
+#endif
+#ifdef LINUX
+ int fd;
+#endif
+
+ float throt;
+ int throttle_cnt;
+
+};
+
+#ifdef FREEBSD
+Joystick::Joystick()
+{
+ if ((fifo_fd=open("/var/tmp/mupen64plus_ctl", O_WRONLY )) == -1) {throw string(strerror(errno));}
+ cout << "opened" << endl;
+ if (fcntl(fifo_fd, F_SETFL, O_NONBLOCK) == -1) throw string("failed to set nonblocking io");
+
+ reset();
+}
+
+void Joystick::press_a(bool state)
+{
+ buttons.A_BUTTON=state;
+ send_data();
+}
+
+void Joystick::send_data()
+{
+ char buf[5];
+ pack(&buttons, buf);
+ write(fifo_fd, buf, 5);
+}
+
+
+
+void Joystick::steer(float dir, float dead_zone)
+{
+ if (dir<-1.0) dir=-1.0;
+ if (dir>1.0) dir=1.0;
+
+ if (fabs(dir)<dead_zone) dir=0.0;
+
+ buttons.X_AXIS = (signed) (127.0*dir);
+ send_data();
+}
+
+void Joystick::reset()
+{
+ memset(&buttons, sizeof(buttons), 0);
+ buttons.Z_TRIG=0;
+ buttons.R_TRIG=0;
+ buttons.L_TRIG=0;
+ buttons.A_BUTTON=0;
+ buttons.B_BUTTON=0;
+ send_data();
+}
+
+Joystick::~Joystick()
+{
+ close(fifo_fd);
+}
+#endif
+#ifdef LINUX
+Joystick::Joystick()
+{
+ fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
+ if(fd < 0) {
+ cerr << "open uinput failed. do you have privilegies to access it? (try chown flo:root /dev/uinput)" << endl;
+ exit(EXIT_FAILURE);
+ }
+
+ int ret;
+
+ ret=ioctl(fd, UI_SET_EVBIT, EV_KEY);
+ ret=ioctl(fd, UI_SET_EVBIT, EV_SYN);
+ ret=ioctl(fd, UI_SET_KEYBIT , BTN_A);
+ ioctl(fd, UI_SET_EVBIT, EV_ABS);
+ ioctl(fd, UI_SET_ABSBIT, ABS_X);
+ ioctl(fd, UI_SET_ABSBIT, ABS_Y);
+
+ struct uinput_user_dev meh;
+ memset(&meh,0,sizeof(meh));
+
+ strcpy(meh.name, "flotest");
+ meh.id.bustype=BUS_USB;
+ meh.id.vendor=0xdead;
+ meh.id.product=0xbeef;
+ meh.id.version=1;
+ meh.absmin[ABS_X]=0;
+ meh.absmax[ABS_X]=10000;
+ meh.absmin[ABS_Y]=0;
+ meh.absmax[ABS_Y]=10000;
+
+
+ ret=write(fd, &meh, sizeof(meh));
+
+ ioctl(fd,UI_DEV_CREATE);
+
+ reset();
+}
+
+Joystick::~Joystick()
+{
+ ioctl(fd, UI_DEV_DESTROY);
+ close(fd);
+}
+
+void Joystick::steer(float dir, float dead_zone)
+{
+ if (dir<-1.0) dir=-1.0;
+ if (dir>1.0) dir=1.0;
+
+ if (fabs(dir)<dead_zone) dir=0.0;
+
+ struct input_event ev;
+ ev.type=EV_ABS;
+ ev.code=ABS_X;
+ ev.value=5000+dir*5000;
+ write(fd, &ev, sizeof(ev));
+}
+
+
+void Joystick::press_a(bool a)
+{
+ struct input_event ev;
+ ev.type=EV_KEY;
+ ev.code=BTN_A;
+ ev.value = a ? 1 : 0;
+ write(fd, &ev, sizeof(ev));
+}
+
+void Joystick::reset()
+{
+ struct input_event ev;
+ ev.type=EV_ABS;
+ ev.code=ABS_Y;
+ ev.value=5001;
+ write(fd, &ev, sizeof(ev));
+ ev.value=5000;
+ write(fd, &ev, sizeof(ev));
+
+ cout << "Y zeroed" << endl;
+
+ steer(0.1);
+ steer(0);
+ cout << "X zeroed" << endl;
+
+ press_a(true);
+ press_a(false);
+ cout << "A zeroed" << endl;
+}
+
+#endif
+
+
+void Joystick::throttle(float t)
+{
+ if (t<0.0) t=0.0;
+ if (t>1.0) t=1.0;
+
+ throt=t;
+}
+
+void Joystick::process()
+{
+ throttle_cnt++;
+ if (throttle_cnt>=THROTTLE_CNT_MAX) throttle_cnt=0;
+
+ press_a((throttle_cnt < throt*THROTTLE_CNT_MAX));
+}
+
+
+
+#define HIST_SMOOTH 7
+
+//#define NO_BRIGHTNESS // will man nicht, nur zu demonstrationszwecken
+
+#define ERODE_RADIUS_2D 4
+
+
+#define IMG_HISTORY 3
+
+
+
+
+
+int crosshair_x=0, crosshair_y=0;
+
+void mouse_callback(int event, int x, int y, int flags, void* userdata)
+{
+ if (event==EVENT_LBUTTONDOWN)
+ {
+ crosshair_x=x;
+ crosshair_y=y;
+ }
+}
+
+
+
+
+
+sem_t thread1_go;
+sem_t thread1_done;
+Mat thread1_img;
+
+void* thread1_func(void*)
+{
+ Mat gray;
+ static Mat gray_prev;
+
+ static std::vector<cv::Point2f> points[2];
+
+ std::vector<uchar> status; // status of tracked features
+ std::vector<float> err; // error in tracking
+
+
+ cout << "thread 1 is alive :)" <<endl;
+ while(1)
+ {
+ sem_wait(&thread1_go);
+ sem_post(&thread1_done);
+
+ sem_wait(&thread1_go);
+ // now we have our private image at thread1_img.
+/*
+ cvtColor(thread1_img, gray, CV_BGR2GRAY);
+
+
+ if (points[0].size() <= 2000) // we need more points
+ {
+ std::vector<cv::Point2f> features; // detected features
+
+ // detect the features
+ goodFeaturesToTrack(gray, // the image
+ features, // the output detected features
+ 3000, // the maximum number of features
+ 0.2, // quality level
+ 10); // min distance between two features
+
+
+ // add the detected features to
+ // the currently tracked features
+ points[0].insert(points[0].end(), features.begin(),features.end());
+ }
+
+
+ // for first image of the sequence
+ if(gray_prev.empty())
+ gray.copyTo(gray_prev);
+
+ cv::calcOpticalFlowPyrLK(
+ gray_prev, gray, // 2 consecutive images
+ points[0], // input point positions in first image
+ points[1], // output point positions in the 2nd image
+ status, // tracking success
+ err); // tracking error
+
+
+
+ int k=0;
+ for(int i=0; i < points[1].size(); i++) {
+ // do we keep this point?
+ if (status[i]) {
+ // keep this point in vector
+ points[0][k] = points[0][i];
+ points[1][k++] = points[1][i];
+ }
+ }
+ // eliminate unsuccesful points
+ points[0].resize(k);
+ points[1].resize(k);
+
+
+
+ // for all tracked points
+ for(int i= 0; i < points[1].size(); i++ ) {
+ // draw line and circle
+ cv::line(thread1_img,
+ points[0][i], // initial position
+ points[1][i],// new position
+ cv::Scalar(255,255,255));
+
+ cv::circle(thread1_img, points[1][i], 2,
+ cv::Scalar(255,255,255),-1);
+ }
+
+ // 4. extrapolate movement
+ for (int i=0;i<points[0].size();i++)
+ {
+ points[0][i].x = points[1][i].x+(points[1][i].x-points[0][i].x);
+ points[0][i].y = points[1][i].y+(points[1][i].y-points[0][i].y);
+ }
+
+ cv::swap(gray_prev, gray);
+
+ */
+ // now we must stop accessing thread1_img, main() may access it
+ sem_post(&thread1_done);
+ }
+}
+
+
+int main(int argc, char* argv[])
+{
+try {
+
+
+ if (sem_init(&thread1_go, 0, 0)) throw string("sem_init failed");
+ if (sem_init(&thread1_done, 0, 0)) throw string("sem_init failed");
+
+ pthread_t thread1;
+ if (pthread_create(&thread1, NULL, thread1_func, NULL)) throw string("pthread_create failed");
+
+
+ string tmp;
+
+#ifdef LINUX
+ Joystick joystick;
+ cout << "joystick initalized, now starting mupen." << endl;
+#endif
+
+ if (fork()==0) { system("mupen64plus --nogui --noask ~/MarioKart64.rom"); exit(0); }
+
+#ifdef FREEBSD
+ sleep(2);
+ Joystick joystick;
+#endif
+
+ sleep(1);
+
+ joystick.reset();
+ cout << "successfully reset joystick." << endl;
+
+/* cout << "press enter to steer left" << endl;
+ getchar();
+
+
+ cout << "now steering left. press enter to continue." << endl;
+ joystick.steer(-1.0);
+ getchar();
+
+ cout << "centered. press enter to steer right." << endl;
+ joystick.steer(0.0);
+ getchar();
+
+ cout << "steering right" << endl;
+ joystick.steer(1.0);
+ getchar();
+
+ cout << "centered. press enter to press a." << endl;
+ joystick.steer(0.0);
+ getchar();
+
+ cout << "pressing A" << endl;
+ joystick.press_a(true);
+ getchar();
+
+ cout << "A released." << endl;
+ joystick.press_a(false);
+ getchar();*/
+
+ cout << "waiting for game to start, press enter when started." << endl;
+ joystick.press_a(false);
+ joystick.reset();
+ getchar();
+joystick.reset();
+
+#ifdef LINUX
+ XorgGrabber capture("glN64");
+#endif
+#ifdef FREEBSD
+ XorgGrabber capture("Mupen64Plus OpenGL Video");
+#endif
+
+ Mat transform;
+
+ bool first=true;
+ int xlen, ylen;
+
+ Mat erode_2d_small=circle_mat(3);
+ Mat erode_2d_big=circle_mat(10);
+
+ #define trans_width 600
+ #define trans_height 400
+ #define road_width 100
+
+ namedWindow("edit");
+ setMouseCallback("edit", mouse_callback, NULL);
+
+ joystick.throttle(0.5);
+
+
+ VideoWriter img_writer, thres_writer, thres2_writer;
+
+ Mat img_;
+
+ capture.read(img_);
+
+ xlen=img_.cols;
+ ylen=img_.rows;
+
+ crosshair_x=xlen/2;
+ crosshair_y=0.58*ylen;
+
+ Point2f src_pts[4] = { Point2f(0, ylen), Point2f(xlen, ylen), Point2f(xlen* (.5 - 0.13), ylen/2), Point2f(xlen* (.5 + .13), ylen/2) };
+ //Point2f dest_pts[4] = { Point2f(0, ylen), Point2f(trans_width, ylen), Point2f(0, trans_height), Point2f(0, trans_height) };
+ Point2f dest_pts[4] = { Point2f(trans_width/2 - road_width/2, trans_height), Point2f(trans_width/2 + road_width/2, trans_height), Point2f(trans_width/2 - road_width/2, trans_height/2), Point2f(trans_width/2 + road_width/2, trans_height/2) };
+ transform=getPerspectiveTransform(src_pts, dest_pts);
+
+ //img_writer.open("img.mpg", CV_FOURCC('P','I','M','1'), 30, Size(xlen,ylen), false);
+ img_writer.open("img.mpg", CV_FOURCC('P','I','M','1'), 30, Size(xlen,ylen), false);
+ thres_writer.open("thres.mpg", CV_FOURCC('P','I','M','1'), 30, Size(xlen,ylen), false);
+ thres2_writer.open("thres2.mpg", CV_FOURCC('P','I','M','1'), 30, Size(xlen,ylen), false);
+
+ if (!img_writer.isOpened() || !thres_writer.isOpened() || !thres2_writer.isOpened())
+ {
+ cout << "ERROR: could not open video files!" << !img_writer.isOpened() << !thres_writer.isOpened() << !thres2_writer.isOpened() <<endl;
+ }
+
+
+ SteerIface* steerer = new NaiveSteerer(xlen/2, 0.58*ylen);
+ RoadThresholderIface* road_thresholder = new RoadThresholder();
+
+ while(1)
+ {
+ capture.read(img_);
+
+ assert ((img_.cols==xlen) && (img_.rows==ylen));
+
+ Mat img;
+ img_.convertTo(img, CV_8UC3, 1); //FINDMICH
+ img.copyTo(thread1_img); sem_post(&thread1_go);
+
+ #ifdef NO_BRIGHTNESS
+ //assert(img.type()==CV_8UC3);
+ for (int row = 0; row<img.rows; row++)
+ {
+ uchar* data=img.ptr<uchar>(row);
+
+ for (int col=0; col<img.cols;col++)
+ {
+ int sum=data[0] + data[1] + data[2];
+ if (sum>0)
+ {
+ data[0]=(int)data[0] * 256 / sum;
+ data[1]=(int)data[1] * 256 / sum;
+ data[2]=(int)data[2] * 256 / sum;
+ }
+ else
+ {
+ data[0]=255/3;
+ data[1]=255/3;
+ data[2]=255/3;
+ }
+ data+=img.step[1];
+ }
+ }
+ #endif
+
+
+ road_thresholder->process_image(img);
+ Mat img_thres = road_thresholder->get_road();
+
+ Mat img_eroded(img_thres.rows, img_thres.cols, img_thres.type());
+ Mat img_tmp(img_thres.rows, img_thres.cols, img_thres.type());
+ Mat img_thres2(img_thres.rows, img_thres.cols, img_thres.type());
+
+ erode(img_thres, img_tmp, erode_2d_small);
+ dilate(img_tmp, img_thres, erode_2d_small);
+ dilate(img_thres, img_tmp, erode_2d_big);
+ erode(img_tmp, img_thres2, erode_2d_big);
+
+
+
+
+
+
+
+
+
+
+ assert(img.rows==img_eroded.rows);
+ assert(img.cols==img_eroded.cols);
+
+
+
+
+
+/*
+ Mat img_perspective(trans_height, trans_width, img_thres.type());
+ warpPerspective(img_thres, img_perspective, transform, img_perspective.size());
+
+
+ threshold(img_perspective, img_perspective, 127, 255, THRESH_BINARY);
+ Mat img_perspective_temp(img_perspective.rows, img_perspective.cols, img_perspective.type());
+ Mat img_perspective_temp2(img_perspective.rows, img_perspective.cols, img_perspective.type());
+ erode(img_perspective, img_perspective_temp, circle_mat(7));
+ dilate(img_perspective_temp, img_perspective_temp2, circle_mat(7 + 15));
+ erode(img_perspective_temp2, img_perspective, circle_mat(15));
+ */
+
+
+ img.row(crosshair_y)=Scalar(255,0,0);
+ img.col(crosshair_x)=Scalar(255,0,0);
+ img_thres2.row(crosshair_y)=128;
+ img_thres2.col(crosshair_x)=128;
+
+ steerer->process_image(img_thres2);
+ double steer_value = steerer->get_steer_data();
+
+ Mat steer=Mat::zeros(20,1920,CV_8U);
+ steer.col( steer.cols /2 )=128;
+ if (steerer->get_confidence()>0)
+ {
+ int x = (steer_value/2.0 + 0.5)*steer.cols;
+
+ if (x<1) x=1;
+ if (x>=steer.cols-1) x=steer.cols-2;
+
+ steer.col(x) = 255;
+ steer.col(x-1)=240;
+ steer.col(x+1)=240;
+
+
+ joystick.steer( steer_value,0.05);
+ }
+ else
+ joystick.steer(0.0);
+
+
+
+
+ sem_wait(&thread1_done); // wait for thread1 to finish
+
+
+ //imshow("orig", img);
+ imshow("edit", img);
+ //imshow("perspective", img_perspective);
+ //imshow("diff", img_diff);
+
+ imshow("thres", img_thres);
+ imshow("thres2", img_thres2);
+ imshow("tracked", thread1_img);
+ imshow("steer", steer);
+
+
+
+ //img_writer << img_diff;
+ thres_writer << img_thres;
+ thres2_writer << img_thres2;
+
+ waitKey(1000/50);
+ joystick.process();
+}
+
+} //try
+catch(string meh)
+{
+ cout << "error: "<<meh<< endl;
+}
+catch(...)
+{
+ cout << "error!" << endl;
+}
+
+sem_destroy(&thread1_go);
+sem_destroy(&thread1_done);
+
+}