diff options
-rw-r--r-- | mariokart01.cpp | 508 | ||||
-rw-r--r-- | xcb02.cpp | 48 | ||||
-rw-r--r-- | xcb03.cpp | 219 |
3 files changed, 754 insertions, 21 deletions
diff --git a/mariokart01.cpp b/mariokart01.cpp new file mode 100644 index 0000000..5f6bcf2 --- /dev/null +++ b/mariokart01.cpp @@ -0,0 +1,508 @@ +/* + * 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. + */ + + +#include <iostream> +#include <xcb/xcb.h> +#include <stdlib.h> +#include <string.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(); +} + +/* +int main() +{ + XorgGrabber grabber("Mupen64Plus OpenGL Video"); + + namedWindow("meh"); + Mat meh; + while(1) + { + grabber.read(meh); + imshow("meh",meh); + waitKey(100); + } +} +*/ + + +#define HIST_SMOOTH 7 + + //#define NO_BRIGHTN/SS // will man nicht, nur zu demonstrationszwecken + +#define ERODE_RADIUS_2D 4 + + + +Mat circle_mat(int radius) +{ + Mat result(radius*2+1, radius*2+1, CV_8U); + for (int x=0; x<=result.cols/2; x++) + for (int y=0; y<=result.rows/2; y++) + { + unsigned char& p1 = result.at<unsigned char>(result.cols/2 + x, result.rows/2 + y); + unsigned char& p2 = result.at<unsigned char>(result.cols/2 - x, result.rows/2 + y); + unsigned char& p3 = result.at<unsigned char>(result.cols/2 + x, result.rows/2 - y); + unsigned char& p4 = result.at<unsigned char>(result.cols/2 - x, result.rows/2 - y); + + if ( x*x + y*y < radius*radius ) + p1=p2=p3=p4=255; + else + p1=p2=p3=p4=0; + } + + return result; +} + +int main(int argc, char* argv[]) +{ + XorgGrabber capture("Mupen64Plus OpenGL Video"); + + int road_0=77, road_1=77, road_2=77; + + Mat transform; + + bool first=true; + int xlen, ylen; + + Mat erode_2d(ERODE_RADIUS_2D*2+1, ERODE_RADIUS_2D*2+1, CV_8U); + for (int x=0; x<=erode_2d.cols/2; x++) + for (int y=0; y<=erode_2d.rows/2; y++) + { + unsigned char& p1 = erode_2d.at<unsigned char>(erode_2d.cols/2 + x, erode_2d.rows/2 + y); + unsigned char& p2 = erode_2d.at<unsigned char>(erode_2d.cols/2 - x, erode_2d.rows/2 + y); + unsigned char& p3 = erode_2d.at<unsigned char>(erode_2d.cols/2 + x, erode_2d.rows/2 - y); + unsigned char& p4 = erode_2d.at<unsigned char>(erode_2d.cols/2 - x, erode_2d.rows/2 - y); + + if ( x*x + y*y < ERODE_RADIUS_2D*ERODE_RADIUS_2D ) + p1=p2=p3=p4=255; + else + p1=p2=p3=p4=0; + } + + #define trans_width 600 + #define trans_height 400 + #define road_width 100 + + while(1) + { + + Mat img_; + + capture.read(img_); + + if (first) + { + xlen=img_.cols; + ylen=img_.rows; + + 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); + + + first=false; + } + assert ((img_.cols==xlen) && (img_.rows==ylen)); + + namedWindow("orig"); + namedWindow("edit"); + + Mat img, img2; + img_.convertTo(img, CV_8UC3, 1); //FINDMICH + img.copyTo(img2); + + #ifdef NO_BRIGHTNESS + assert(img2.type()==CV_8UC3); + for (int row = 0; row<img2.rows; row++) + { + uchar* data=img2.ptr<uchar>(row); + + for (int col=0; col<img2.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+=3; + } + } + #endif + + + Mat img_diff(img.rows, img.cols, CV_8U); + int hist[256]; + for (int i=0; i<256; i++) hist[i]=0; + for (int row = 0; row<img2.rows; row++) + { + uchar* data=img2.ptr<uchar>(row); + uchar* data_out=img_diff.ptr<uchar>(row); + + for (int col=0; col<img2.cols;col++) + { + int diff = (abs((int)data[0] - road_0) + abs((int)data[1] - road_1) + abs((int)data[2] - road_2)) /3; + *data_out=diff; + hist[diff]++; + data+=3; + data_out++; + } + } + + int hist2[256]; + for (int i=0; i<256; i++) + { + int sum=0; + for (int j=-HIST_SMOOTH; j<=HIST_SMOOTH; j++) + { + if (i+j < 0 || i+j > 255) continue; + sum+=hist[i+j]; + } + hist2[i]=sum; + } + + int cumul=0; + int x_begin=0; + for (x_begin=0;x_begin<256;x_begin++) + { + cumul+=hist[x_begin]; + if (cumul > img.rows*img.cols/100) break; + } + + int hist_max=0; + int thres; + for (int i=0; i<256; i++) + { + if (hist2[i]>hist_max) hist_max=hist2[i]; + if ((hist2[i] < hist_max/2) && (i>x_begin)) + { + thres=i; break; + } + } + + Mat img_hist(100,256, CV_8U); + for (int row = 0; row<img_hist.rows; row++) + { + uchar* data=img_hist.ptr<uchar>(row); + + for (int col=0; col<img_hist.cols;col++) + { + *data=255; + if (col==thres) *data=127; + if (col==x_begin) *data=0; + if (hist2[col] > (img_hist.rows-row)*800) *data=0; + data++; + } + } + + Mat img_thres(img_diff.rows, img_diff.cols, img_diff.type()); + threshold(img_diff, img_thres, thres, 255, THRESH_BINARY_INV); + + Mat img_eroded(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_eroded, Mat::ones(3, 3, CV_8U)); + dilate(img_eroded, img_thres2, Mat::ones(3, 3, CV_8U)); + + + assert(img.rows==img_eroded.rows); + assert(img.cols==img_eroded.cols); + int avg_sum=0; + road_0=road_1=road_2=0; + for (int row = 0; row<img.rows; row++) + { + uchar* data=img.ptr<uchar>(row); + uchar* mask=img_eroded.ptr<uchar>(row); + + int mean_value_line_sum=0; + int mean_value_line_cnt=0; + int mean_value_line; + for (int col=0; col<img.cols;col++) + { + if (*mask) + { + avg_sum++; + mean_value_line_sum+=col; + mean_value_line_cnt++; + road_0+=data[0]; + road_1+=data[1]; + road_2+=data[2]; + } + + data+=3; + mask++; + } + + if (mean_value_line_cnt) + { + mean_value_line=mean_value_line_sum/mean_value_line_cnt; + int variance_line=0; + int stddev_line; + uchar* mask=img_eroded.ptr<uchar>(row); + for (int col=0; col<img.cols;col++) + { + if (*mask) + variance_line+=(col-mean_value_line)*(col-mean_value_line); + + data+=3; + mask++; + } + variance_line/=mean_value_line_cnt; + stddev_line=sqrt(variance_line); + if (mean_value_line>1 && mean_value_line < img.cols-2) + { + img_thres2.ptr<uchar>(row)[mean_value_line-1]=128; + img_thres2.ptr<uchar>(row)[mean_value_line]=128; + img_thres2.ptr<uchar>(row)[mean_value_line+1]=128; + } + if ((mean_value_line+stddev_line)>1 && (mean_value_line+stddev_line) < img.cols-2) + { + img_thres2.ptr<uchar>(row)[mean_value_line-1+stddev_line]=128; + img_thres2.ptr<uchar>(row)[mean_value_line+stddev_line]=128; + img_thres2.ptr<uchar>(row)[mean_value_line+1+stddev_line]=128; + } + if ((mean_value_line-stddev_line)>1 && (mean_value_line-stddev_line) < img.cols-2) + { + img_thres2.ptr<uchar>(row)[mean_value_line-1-stddev_line]=128; + img_thres2.ptr<uchar>(row)[mean_value_line-stddev_line]=128; + img_thres2.ptr<uchar>(row)[mean_value_line+1-stddev_line]=128; + } + } + } + + if (avg_sum>20) + { + road_0/=avg_sum; + road_1/=avg_sum; + road_2/=avg_sum; + } + +/* + 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)); + */ + + + imshow("orig", img); + imshow("edit", img2); + //imshow("perspective", img_perspective); + imshow("diff", img_diff); + imshow("hist", img_hist); + imshow("thres", img_thres2); + + waitKey(1000/50); + //waitKey(); +} +} @@ -42,8 +42,7 @@ int main(int argc, char **argv) xcb_screen_t* grab_screen=NULL; /* Find configured screen */ - const xcb_setup_t *setup = xcb_get_setup(conn); - xcb_screen_t *scr = NULL; + 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)) { @@ -73,26 +72,24 @@ int main(int argc, char **argv) cout << title << endl; if (strstr(title, "Mupen64Plus OpenGL Video")) { - grabbed_win=children[i]; - found_win=true; + 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; - /* Window properties */ - xcb_get_geometry_reply_t *geo; - geo = xcb_get_geometry_reply (conn, - xcb_get_geometry (conn, grabbed_win), - NULL); - if (geo == NULL) + grab_screen=scr; + } + else { cerr << "geo==NULL!" << endl; - exit(1); } - - grab_width=geo->width; - grab_height=geo->height; - - free(geo); - - grab_screen=scr; } } @@ -103,6 +100,10 @@ int main(int argc, char **argv) free(reply); delete[] cookies; } + else + { + cout << "xcb_get_setup failed" << endl; + } } if (found_win) @@ -159,15 +160,20 @@ int main(int argc, char **argv) cout << grab_width << "x" << grab_height << endl; + free(img); + while(1) { + 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 meh(grab_height, grab_width, CV_8UC4, xcb_get_image_data(img)); namedWindow("meh"); imshow("meh", meh); waitKey(50); - 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); + + free(img); } diff --git a/xcb03.cpp b/xcb03.cpp new file mode 100644 index 0000000..9fa9292 --- /dev/null +++ b/xcb03.cpp @@ -0,0 +1,219 @@ +/* + * 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. + */ + + +#include <iostream> +#include <xcb/xcb.h> +#include <stdlib.h> +#include <string.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)); +} + +int main() +{ + XorgGrabber grabber("Mupen64Plus OpenGL Video"); + + namedWindow("meh"); + Mat meh; + while(1) + { + grabber.read(meh); + imshow("meh",meh); + waitKey(100); + } +} |