static void create_eyes(ModeInfo * mi, Eyes * e, Eyes * eyes, int num_eyes) { EyeScrInfo *ep = &eye_info[MI_SCREEN(mi)]; Display *display = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); int win_width = MI_WIDTH(mi); int win_height = MI_HEIGHT(mi); unsigned long black_pixel = MI_BLACK_PIXEL(mi); unsigned long white_pixel = MI_WHITE_PIXEL(mi); Bool iconic = MI_IS_ICONIC(mi); Pixmap pix = e->pixmap; /* preserve pixmap handle */ int w = e->width; /* remember last w/h */ int h = e->height; int npixels = MI_NPIXELS(mi); /* num colors in colormap */ int cycs = MI_CYCLES(mi); /* affects eye lifetime */ int maxw = win_width / 2; /* widest eyes can be */ int color, lid_color; int i; (void) memset((char *) e, 0, sizeof (Eyes)); /* wipe everything */ e->pixmap = pix; /* remember Pixmap handle */ /* sanity check the cycles value */ if (cycs < 1) cycs = 1; if (cycs > MAX_CYCLES) cycs = MAX_CYCLES; e->time_to_die = (unsigned long) LIFE_MIN + NRAND(LIFE_RANGE); e->time_to_die *= (unsigned long) cycs; /* multiply life by cycles */ e->time_to_die += ep->time; e->pupil_pixel = black_pixel; /* pupil is always black */ if (MI_NPIXELS(mi) <= 2) { /* TODO: stipple the eyelid? */ e->eyelid_pixel = black_pixel; e->eyeball_pixel = white_pixel; } else { lid_color = NRAND(npixels); e->eyelid_pixel = MI_PIXEL(mi, lid_color); while ((color = NRAND(npixels + 5)) == lid_color) { /* empty */ } if (color >= npixels) { /* give white a little better chance */ e->eyeball_pixel = white_pixel; } else { e->eyeball_pixel = MI_PIXEL(mi, color); } } if (iconic) { /* only one pair of eyes, fills entire window */ e->width = win_width; e->height = win_height; } else { if (maxw - MIN_EYE_SIZE > MIN_EYE_SIZE) e->width = NRAND(maxw - MIN_EYE_SIZE) + MIN_EYE_SIZE; else e->width = NRAND(MIN_EYE_SIZE) + MIN_EYE_SIZE; e->x = (win_width - e->width > 0) ? NRAND(win_width - e->width) : 0; e->height = NRAND(e->width * 3 / 4) + (e->width / 4); e->y = (win_height - e->height > 0) ? NRAND(win_height - e->height) : 0; /* check for overlap with other eyes */ for (i = 0; i < num_eyes; i++) { if (&eyes[i] == e) { /* that's me */ continue; } if (eyes_overlap(e, &eyes[i])) { /* collision, force retry on next cycle */ e->time_to_die = 0; break; } } } /* If the Pixmap is smaller than the new size, make it bigger */ if ((e->width > w) || (e->height > h)) { if (e->pixmap != None) { XFreePixmap(display, e->pixmap); } if ((e->pixmap = XCreatePixmap(display, window, e->width, e->height, MI_DEPTH(mi))) == None) { e->width = e->height = 0; return; } } /* Set the transformation matrix for this set of eyes * If iconic, make the eyes image one pixel shorter and * skinnier, they seem to fit in the icon box better that way. */ SetTransform(&e->transform, 0, (iconic) ? e->width - 1 : e->width, (iconic) ? e->height - 1 : e->height, 0, W_MIN_X, W_MAX_X, W_MIN_Y, W_MAX_Y); /* clear the offscreen pixmap to background color */ XSetForeground(display, ep->eyeGC, black_pixel); XFillRectangle(display, (Drawable) e->pixmap, ep->eyeGC, 0, 0, e->width, e->height); /* make the full eye images in the offscreen Pixmap */ make_eye(mi, e->pixmap, e, 0, True); make_eye(mi, e->pixmap, e, 1, True); }
static void paint_eyes(ModeInfo * mi, Eyes * e, Fly * f, Eyes * eyes, int num_eyes) { EyeScrInfo *ep = &eye_info[MI_SCREEN(mi)]; Display *display = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); GC gc = ep->eyeGC; Bool iconic = MI_IS_ICONIC(mi); int focusx = (f->x + (f->width / 2)) - e->x; int focusy = (f->y + (f->height / 2)) - e->y; Pixmap pix = e->pixmap; TPoint point; int i; if (pix == None) { e->time_to_die = 0; /* "should not happen" */ } if (ep->time >= e->time_to_die) { /* Sorry Bud, your time is up */ if (e->painted) { /* only unpaint it if previously painted */ XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); XFillRectangle(display, window, gc, e->x, e->y, e->width, e->height); } /* randomly place the eyes elsewhere */ create_eyes(mi, e, eyes, num_eyes); pix = e->pixmap; /* pixmap may have changed */ } /* If the bouncer would intersect this pair of eyes, force the * eyes to move. This simplifies the code, because we do not * have to deal with drawing the bouncer on top of the eyes. * When trying to do so, there was too much annoying flashing * and ghost images from the undraw. I decided to observe the * KISS principle and keep it simple. I think the effect is * better also. * We must draw the flyer on the eyes when iconic, but that is * easy because the eyes repaint the whole box each time. */ if ((!iconic) && (fly_touches_eye(f, e))) { e->time_to_die = 0; } if (e->time_to_die == 0) { return; /* collides with something */ } /* set the point to look at and compute the pupil position */ point.x = Tx(focusx, focusy, &e->transform); point.y = Ty(focusx, focusy, &e->transform); computePupil(0, point, &(e->pupil[0])); computePupil(1, point, &(e->pupil[1])); if (e->painted) { /* if still looking at the same point, do nothing further */ if (TPointEqual(e->pupil[0], e->last_pupil[0]) && TPointEqual(e->pupil[1], e->last_pupil[1])) { return; } } for (i = 0; i < 2; i++) { /* update the eye, calculates the changed rectangle */ make_eye(mi, pix, e, i, False); /* Only blit the change if the full image has been painted */ if (e->painted) { /* copy the changed rectangle out to the screen */ XCopyArea(display, pix, window, gc, e->bbox.x, e->bbox.y, (int) e->bbox.width, (int) e->bbox.height, e->x + e->bbox.x, e->y + e->bbox.y); } /* remember where we're looking, for the next time around */ e->last_pupil[i] = e->pupil[i]; } /* always do full paint when iconic, eliminates need to track fly */ if (iconic || (!e->painted)) { XCopyArea(display, pix, window, gc, 0, 0, e->width, e->height, e->x, e->y); } /* when iconic, pretend to never paint, causes full paint each time */ if (!iconic) { e->painted++; /* note that a paint has been done */ } }
void filter(const float *img, const int rows, const int cols, int * x_pos,int *y_pos,int *width) // Algorithm inspired by: // Robust real-time pupil tracking in highly off-axis images // Lech Świrski Andreas Bulling Neil A. Dodgson // Computer Laboratory, University of Cambridge, United Kingdom // Eye Tracking Research & Applications 2012 { point_t img_size = {rows,cols}; int min_h = 16; int max_h = 80; int h, i, j; float best_response = -10000; point_t best_pos ={0,0}; int best_h = 0; int h_step = 4; int step = 5; for (h = min_h; h < max_h; h+=h_step) { eye_t eye = make_eye(h); // printf("inner factor%f outer.factor %f center %i \n",eye.inner.f,eye.outer.f,(int)eye.w_half ); for (i=0; i<rows-eye.w; i +=step) { for (j=0; j<cols-eye.w; j+=step) { // printf("|%2.0f",img[i * cols + j]); point_t offset = {i,j}; float response = eye.outer.f*area(img,img_size,eye.outer.s,eye.outer.e,offset) +eye.inner.f*area(img,img_size,eye.inner.s,eye.inner.e,offset); // printf("| %5.2f ",response); if(response > best_response){ // printf("!"); best_response = response; best_pos = (point_t){i,j}; // printf("%i %i", (int)best_pos.r,(int)best_pos.c); best_h = eye.h; } } // printf("\n"); } } // now we refine the search at pixel resolution This hole part can be commented out if needed point_t window_lower = {MAX(0,best_pos.r-step+1),MAX(0,best_pos.c-step+1)}; point_t window_upper = {MIN(img_size.r,best_pos.r+step),MIN(img_size.c,best_pos.c+step)}; for (h = best_h-h_step+1; h < best_h+h_step; h+=1) { eye_t eye = make_eye(h); // printf("inner factor%f outer.factor %f center %i \n",eye.inner.f,eye.outer.f,(int)eye.w_half ); for (i=window_lower.r; i<MIN(window_upper.r,img_size.r-eye.w); i +=1) { for (j=window_lower.c; j<MIN(window_upper.c,img_size.c-eye.w); j +=1) { // printf("|%2.0f",img[i * cols + j]); point_t offset = {i,j}; float response = eye.outer.f*area(img,img_size,eye.outer.s,eye.outer.e,offset) +eye.inner.f*area(img,img_size,eye.inner.s,eye.inner.e,offset); // printf("| %5.2f ",response); if(response > best_response){ // printf("!"); best_response = response; best_pos = (point_t){i,j}; // printf("%i %i", (int)best_pos.r,(int)best_pos.c); best_h = eye.h; } } // printf("\n"); } } // point_t start = {0,0}; // point_t end = {1,1}; // printf("FULL IMG SUM %1.0f\n",img[(img_size.r-1) * img_size.c + (img_size.c-1)] ); // printf("AREA:%f\n",area(img,img_size,start,end,(point_t){0,0})); *x_pos = (int)best_pos.r; *y_pos = (int)best_pos.c; *width = best_h*3; }