/** * @file * An example program to show usage of EDT PCI DV library to acquire and * optionally save single or multiple images from devices connected to EDT * high speed digital video interface such as the PCI DV C-Link or PCI DV * FOX / RCX. * * Provided as a starting point example for adding digital video acquisition * to a user application. Includes optimization strategies that take * advantage of the EDT ring buffer library subroutines for pipelining image * acquisition and subsequent processing. This allows you to achieve higher * performance than would normally be possible through a basic acquire/process * scheme. * * The name is somewhat misleading -- because of the parallel aspect, * it really isn't the simplest way to do image acquisition. For a * stone-simple example, see simplest_take.c. * * For more more complex operations, including error detection, diagnostics, * changing camera exposure times, and tuning the acquisition in various * ways, refer to the take.c utility. For serial, see serial_cmd.c. * * For a sample Windows GUI application code, see wintake. * * (C) 1997-2007 Engineering Design Team, Inc. */ #include "engine.h" #include "edtinc.h" #include "time.h" #define DALSA_ARRAY_SIZE 1024 #define BUFSIZE 256 static void usage(char *progname); static void save_image(u_char * image_p, int width, int height, int depth, char *basename, int count); /* * NO_MAIN isn't that simple, but is for VXWORKS so we can type * name of subroutine instead of executable and not have multiple mains * (all in one namespace) */ /* * main */ #ifdef NO_MAIN #include "opt_util.h" char *argument ; int option ; int simple_take(char *command_line) #else int main(argc, argv) int argc; char **argv; #endif { u_short *ushort_image_p; u_short image_array[DALSA_ARRAY_SIZE][DALSA_ARRAY_SIZE]; double dbl_image_array[DALSA_ARRAY_SIZE][DALSA_ARRAY_SIZE]; double *dbl_defocus_X, *dbl_defocus_Y; int ii, jj, kk; time_t start_t, end_t; double diff_t; int i; int unit = 0; int overrun, overruns=0; int timeouts, last_timeouts = 0; int recovering_timeout = FALSE; char *progname ; char *cameratype; char bmpfname[128]; int numbufs = 4; int started; u_char *image_p; PdvDev *pdv_p; char errstr[64]; int loops = 1; int width, height, depth; char edt_devname[128]; int channel = 0; #ifdef NO_MAIN char **argv = 0 ; int argc = 0 ; opt_create_argv("simple_take",command_line,&argc,&argv); #endif /* * Intialize the MATLAB variables */ Engine *ep; mxArray *T = NULL, *result = NULL, *defocusX = NULL, *defocusY = NULL; char buffer[BUFSIZE+1]; double myarray[10] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 }; /* * Start the MATLAB engine locally by executing the string * "matlab" * * To start the session on a remote host, use the name of * the host as the string rather than \0 * * For more complicated cases, use any string with whitespace, * and that string will be executed literally to start MATLAB */ if (!(ep = engOpen("\0"))) { fprintf(stderr, "\nCan't start MATLAB engine\n"); return EXIT_FAILURE; } progname = argv[0]; edt_devname[0] = '\0'; *bmpfname = '\0'; /* * process command line arguments */ --argc; ++argv; while (argc && ((argv[0][0] == '-') || (argv[0][0] == '/'))) { switch (argv[0][1]) { case 'u': /* device unit number */ ++argv; --argc; if ((argv[0][0] >= '0') && (argv[0][0] <= '9')) unit = atoi(argv[0]); else strncpy(edt_devname, argv[0], sizeof(edt_devname) - 1); break; case 'c': /* device unit number */ ++argv; --argc; if ((argv[0][0] >= '0') && (argv[0][0] <= '9')) channel = atoi(argv[0]); break; case 'N': ++argv; --argc; numbufs = atoi(argv[0]); break; case 'b': /* bitmap save filename */ ++argv; --argc; strcpy(bmpfname, argv[0]); break; case 'l': ++argv; --argc; loops = atoi(argv[0]); break; case '-': if (strcmp(argv[0], "--help") == 0) { usage(progname); exit(0); } else { fprintf(stderr, "unknown option: %s\n", argv[0]); usage(progname); exit(1); } break; default: fprintf(stderr, "unknown flag -'%c'\n", argv[0][1]); case '?': case 'h': usage(progname); exit(0); } argc--; argv++; } /* * open the interface * * EDT_INTERFACE is defined in edtdef.h (included via edtinc.h) * * edt_parse_unit_channel and pdv_open_channel) are equivalent to * edt_parse_unit and pdv_open except for the extra channel arg and * would normally be 0 unless there's another camera (or simulator) * on the second channel (camera link) or daisy-chained RCI (PCI FOI) */ if (edt_devname[0]) { unit = edt_parse_unit_channel(edt_devname, edt_devname, EDT_INTERFACE, &channel); } else { strcpy(edt_devname, EDT_INTERFACE); } if ((pdv_p = pdv_open_channel(edt_devname, unit, channel)) == NULL) { sprintf(errstr, "pdv_open_channel(%s%d_%d)", edt_devname, unit, channel); pdv_perror(errstr); return (1); } /* * get image size and name for display, save, printfs, etc. */ width = pdv_get_width(pdv_p); height = pdv_get_height(pdv_p); depth = pdv_get_depth(pdv_p); cameratype = pdv_get_cameratype(pdv_p); /* * allocate four buffers for optimal pdv ring buffer pipeline (reduce if * memory is at a premium) */ pdv_multibuf(pdv_p, numbufs); printf("reading %d image%s from '%s'\nwidth %d height %d depth %d\n", loops, loops == 1 ? "" : "s", cameratype, width, height, depth); /* * prestart the first image or images outside the loop to get the * pipeline going. Start multiple images unless force_single set in * config file, since some cameras (e.g. ones that need a gap between * images or that take a serial command to start every image) don't * tolerate queueing of multiple images */ if (pdv_p->dd_p->force_single) { pdv_start_image(pdv_p); started = 1; } else { pdv_start_images(pdv_p, numbufs); started = numbufs; } /* * Initialize the dbl_image_array */ for (ii = 0; ii < DALSA_ARRAY_SIZE; ii++) { for (jj = 0; jj < DALSA_ARRAY_SIZE; jj++) { dbl_image_array[ii][jj] = 0.0; } } for (i = 0; i < loops; i++) { /* * get the image and immediately start the next one (if not the last * time through the loop). Processing (saving to a file in this case) * can then occur in parallel with the next acquisition */ printf("image %d\r", i + 1); fflush(stdout); image_p = pdv_wait_image(pdv_p); /* add the recent image to the sum of the images */ ushort_image_p = image_p; time ( &start_t ); for (ii = 0; ii < DALSA_ARRAY_SIZE; ii++) { for (jj = 0; jj < DALSA_ARRAY_SIZE; jj++) { image_array[ii][jj] = *(ushort_image_p+(DALSA_ARRAY_SIZE*ii)+jj); dbl_image_array[ii][jj] = dbl_image_array[ii][jj]+ (double) image_array[ii][jj]; } } /* Do the centroiding on every 60th image */ if ((i % 60) > 58) { /* * Figure out how to ger this array into MATLAB * and display it! */ T = mxCreateDoubleMatrix(DALSA_ARRAY_SIZE, DALSA_ARRAY_SIZE, mxREAL); memcpy((void *)mxGetPr(T), (void *)dbl_image_array, sizeof(dbl_image_array)); engPutVariable(ep, "T", T); engEvalString(ep, "centroids = struct;"); engEvalString(ep, "centroids = centroid_image(T, centroids)"); engEvalString(ep, "disp(centroids)"); engEvalString(ep, "defocus = get_defocus(centroids)"); engEvalString(ep, "defocus_X = defocus.defocus_X"); engEvalString(ep, "defocus_Y = defocus.defocus_Y"); defocusX = engGetVariable(ep, "defocus_X"); dbl_defocus_X = mxGetPr(defocusX); defocusY = engGetVariable(ep, "defocus_Y"); dbl_defocus_Y = mxGetPr(defocusY); printf ("The X defocus is: %f \n", *dbl_defocus_X); printf ("The Y defocus is: %f \n ", *dbl_defocus_Y); } if ((overrun = (edt_reg_read(pdv_p, PDV_STAT) & PDV_OVERRUN))) ++overruns; if (i < loops - started) { pdv_start_image(pdv_p); } timeouts = pdv_timeouts(pdv_p); /* * check for timeouts or data overruns -- timeouts occur when data * is lost, camera isn't hooked up, etc, and application programs * should always check for them. data overruns usually occur as a * result of a timeout but should be checked for separately since * ROI can sometimes mask timeouts */ if (timeouts > last_timeouts) { /* * pdv_timeout_cleanup helps recover gracefully after a timeout, * particularly if multiple buffers were prestarted */ pdv_timeout_restart(pdv_p, TRUE); last_timeouts = timeouts; recovering_timeout = TRUE; printf("\ntimeout....\n"); } else if (recovering_timeout) { pdv_timeout_restart(pdv_p, TRUE); recovering_timeout = FALSE; printf("\nrestarted....\n"); } if (*bmpfname) save_image(image_p, width, height, depth, bmpfname, i); } puts(""); printf("%d images %d timeouts %d overruns\n", loops, last_timeouts, overruns); /* * --------------------------------------------------- * Note: could use memcpy in the first section here ... */ ushort_image_p = image_p; time ( &start_t ); for (ii = 0; ii < DALSA_ARRAY_SIZE; ii++) { for (jj = 0; jj < DALSA_ARRAY_SIZE; jj++) { image_array[ii][jj] = *(ushort_image_p+(DALSA_ARRAY_SIZE*ii)+jj); dbl_image_array[ii][jj] = (double) image_array[ii][jj]; } } time( &end_t ); diff_t = difftime(end_t, start_t); printf ("Array mapping has taken %.2lf second.\n", diff_t ); /* * Figure out how to ger this array into MATLAB * and display it! */ T = mxCreateDoubleMatrix(DALSA_ARRAY_SIZE, DALSA_ARRAY_SIZE, mxREAL); memcpy((void *)mxGetPr(T), (void *)dbl_image_array, sizeof(dbl_image_array)); engPutVariable(ep, "T", T); engEvalString(ep, "centroids = struct;"); engEvalString(ep, "centroids = centroid_image(T, centroids)"); engEvalString(ep, "disp(centroids)"); engEvalString(ep, "defocus = get_defocus(centroids)"); engEvalString(ep, "defocus_X = defocus.defocus_X"); engEvalString(ep, "defocus_Y = defocus.defocus_Y"); defocusX = engGetVariable(ep, "defocus_X"); dbl_defocus_X = mxGetPr(defocusX); defocusY = engGetVariable(ep, "defocus_Y"); dbl_defocus_Y = mxGetPr(defocusY); time( &end_t ); diff_t = difftime(end_t, start_t); printf ("Array mapping & MATLAB has taken %f second.\n", diff_t ); printf ("The X defocus is: %f \n", *dbl_defocus_X); printf ("The Y defocus is: %f \n ", *dbl_defocus_Y); /* * --------------------------------------------------- */ /* * if we got timeouts it indicates there is a problem */ if (last_timeouts) printf("check camera and connections\n"); pdv_close(pdv_p); /* * We're done! Free memory, close MATLAB engine and exit. */ printf("Done!\n"); mxDestroyArray(result); engClose(ep); exit(0); } static void save_image(u_char * image_p, int s_width, int s_height, int s_depth, char *tmpname, int count) { int s_db = bits2bytes(s_depth); char fname[256]; #ifdef _NT_ u_char *bbuf = NULL; if ((strcmp(&tmpname[strlen(tmpname) - 4], ".bmp") == 0) || (strcmp(&tmpname[strlen(tmpname) - 4], ".BMP") == 0)) tmpname[strlen(tmpname) - 4] = '\0'; sprintf(fname, "%s%02d.bmp", tmpname, count); #else if ((strcmp(&tmpname[strlen(tmpname) - 4], ".ras") == 0) || (strcmp(&tmpname[strlen(tmpname) - 4], ".RAS") == 0)) tmpname[strlen(tmpname) - 4] = '\0'; sprintf(fname, "%s%02d.ras", tmpname, count); #endif /* * write bmp file on Windows systems, or Sun Raster on Unux/Linux * systems. Switch on number of bytes per pixel */ switch (s_db) { case 1: #ifdef _NT_ dvu_write_bmp(fname, image_p, s_width, s_height); #else printf("writing %dx%dx%d raster file to %s\n", s_width, s_height, s_depth, fname); dvu_write_rasfile(fname, (u_char *) image_p, s_width, s_height); #endif break; case 2: printf("converting %dx%dx%d image to 8 bits, writing to %s\n", s_width, s_height, s_depth, fname); #ifdef _NT_ if (!bbuf) bbuf = (u_char *) pdv_alloc(s_width * s_height); if (bbuf == NULL) { pdv_perror("data buf malloc"); exit(1); } dvu_word2byte((u_short *) image_p, (u_char *) bbuf, s_width * s_height, s_depth); dvu_write_bmp(fname, bbuf, s_width, s_height); #else dvu_write_rasfile16(fname, (u_char *) image_p, s_width, s_height, s_depth); #endif break; case 3: printf("writing %dx%dx%d bmp file to %s\n", s_width, s_height, s_depth, fname); #ifdef _NT_ dvu_write_bmp_24(fname, (u_char *) image_p, s_width, s_height); #else dvu_write_rasfile24(fname, (u_char *) image_p, s_width, s_height); #endif break; default: printf("invalid image depth for file write...!\n"); break; } } static void usage(char *progname) { puts(""); printf("%s: simple example program that acquires images from an\n", progname); printf("EDT Digital Video Interface board (PCI DV, PCI DVK, etc.)\n"); puts(""); printf("usage: %s [-b fname] [-l loops] [-N numbufs] [-u unit] [-c channel]\n", progname); #ifdef _NT_ printf(" -b fname output to MS bitmap file\n"); #else printf(" -b fname output to Sun Raster file\n"); #endif printf(" -l loops number of loops (images to take)\n"); printf(" -N numbufs number of ring buffers (see users guide) (default 4)\n"); printf(" -u unit %s unit number (default 0)\n", EDT_INTERFACE); printf(" -c channel %s channel number (default 0)\n", EDT_INTERFACE); printf(" -h this help message\n"); }