home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: OtherApp / OtherApp.zip / wincam.zip / winc_src.zip / convert.c < prev    next >
C/C++ Source or Header  |  1997-02-28  |  26KB  |  898 lines

  1. /*
  2.  *
  3.  * routines to convert raw wincam imagemaps to real greyscale or rgb
  4.  * scaling is in here too.
  5.  *
  6.  * Copyright (C) 1996, Paul G. Fox
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify it
  9.  * under the terms of the GNU General Public License as published by the
  10.  * Free Software Foundation; either version 2 of the License, or (at your
  11.  * option) any later version.
  12.  * 
  13.  * This program is distributed in the hope that it will be useful, but
  14.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * General Public License for more details.
  17.  * 
  18.  * You should have received a copy of the GNU General Public License along
  19.  * with this program; if not, write to the Free Software Foundation, Inc.,
  20.  * 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  * $Header: E:/winc/RCS/convert.c 1.1 1997/03/01 03:44:14 Derek Exp Derek $
  23.  */
  24. #define NDEBUG 1
  25.  
  26. #include "private.h"
  27. #include "trace.h"
  28. #include "color.h"
  29. #include <assert.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32.  
  33. #define EVEN(i) (((i)&1) == 0)
  34. #define ODD(i)    (((i)&1) != 0)
  35.  
  36. #define TOLOWER(c) (isupper((unsigned char)c) ? tolower((unsigned char)c) : (c))
  37.  
  38.  
  39. int strncasecmp (char* a, char * b, int n)
  40. {
  41.     char *p =a;
  42.     char *q =b;
  43.     
  44.     for(p=a, q=b;; p++, q++) {
  45.         int diff;
  46.         if (p == a+n) return 0;    /*   Match up to n characters */
  47.         if (!(*p && *q)) return *p - *q;
  48.         diff = TOLOWER(*p) - TOLOWER(*q);
  49.         if (diff) return diff;
  50.     }
  51. }
  52.  
  53.  
  54.  
  55. /*
  56.  * grey is pretty easy -- every pair of pixels gets averaged horizontally
  57.  */
  58. void
  59. winc_grey_convert(
  60.     byte *image,    /* raw data from camera */
  61.     byte *convimage,    /* data with adjacent pixels averaged */
  62.     int *rows_p,
  63.     int *cols_p,
  64.     int offs,
  65.     int scantype,
  66.     int fraction,
  67.     struct winc_image_adjust *ia)
  68. {
  69.     int b;
  70.     int nr, nc;
  71.     int rows, cols;
  72.     byte *outp;
  73.  
  74.     TRACE("g", __FILE__ ": massaging grey image\n");
  75.  
  76.     rows = *rows_p;
  77.     cols = *cols_p;
  78.  
  79.     if (fraction != 1)
  80.     scantype = 1;
  81.  
  82.     outp = convimage;
  83.     nr = 0;
  84.     while (nr < rows) {
  85.     for (nc = 0; nc < cols; nc++) {
  86.         b = *image++;
  87.         b -= offs;
  88.         if (nr < cols) { /* not in last column? */
  89.         b += *image;
  90.         b -= offs;
  91.         b /= 2; /* average the two values */
  92.         }
  93.         if (b < 0) {
  94.         b = 0;
  95.         TRACE("g", __FILE__ ": clamped offset adjust at zero\n");
  96.         }
  97.         *outp++ = b;
  98.     }
  99.  
  100.     nr++;
  101.     /* skip every other row for full-height single-scan images */
  102.     if (scantype == 1 && fraction == 1)
  103.         outp += cols;
  104.     }
  105.  
  106.     /* need to go back and duplicate the odd rows from the even ones */
  107.     if (scantype == 1 && fraction == 1) {
  108.     outp = convimage;
  109.     for (nr = 0; nr < rows; nr++) {
  110.         memcpy(outp + cols, outp, cols);
  111.         outp += 2*cols;
  112.     }
  113.     *rows_p = rows * 2;
  114.     }
  115.  
  116.     *rows_p  = 492/fraction;
  117.  
  118. }
  119.  
  120. /*
  121.  * notes on color levels.  the default values here are those suggested
  122.  * as defaults in the comments in color.c.  the StarDot software itself
  123.  * adjusts these values with 3 sliders, labelled in percentages, whose
  124.  * ranges go from 0 to very high values, like 200 or 300.  the numbers
  125.  * are labelled as a percentage, but i think they're actuall just absolute
  126.  * values, where 128, 75, 128 are the "normal" values.
  127.  *
  128.  * for various lighting scenarios, the default slider values are:
  129.  *
  130.  *    lightsource        red    green        blue
  131.  *  --------------------------------------------------------
  132.  *    sunlight        138    80 (136)    117
  133.  *    flourescent        138    88 (149)    116
  134.  *    tungsten        98    78 (132)    157
  135.  *    halogen            103    96 (163)    153
  136.  *    studio            112    77 (131)    142
  137.  *    daylight w/ filter    104    65 (110)    150
  138.  *
  139.  *  green values in parentheses are divided by .59, to correct for
  140.  *  the 75 <--> 128 aberration.  that is, a "standard" line would
  141.  *  read:              100    59 (100)    100
  142.  *
  143.  */
  144.  
  145. /*
  146.  * fill in the image adjustment descriptor.  most of the work is for the
  147.  * color balance entries.  note that we use 100/100/100 as the default
  148.  * values.  i've modified color.c to do the adjustment of green down by 59%
  149.  * to match stardot's recommendation. 
  150.  *
  151.  * i've normalized the numbers in the chart above so that a) they're out of
  152.  * 100, rather than 128, b) the average of the three numbers is always 128. 
  153.  * i don't know if that was right or not...
  154.  */
  155.  
  156. void
  157. winc_image_adjustments(
  158.     struct winc_image_adjust *ia,
  159.     char *s,
  160.     int widen,
  161.     int vig)
  162. {
  163.     char newname[40];
  164.     char *ns;
  165.  
  166.     assert(ia);
  167.  
  168.     ia->widen = widen;
  169.     ia->vignette_correction = vig;
  170.  
  171.     /* the input string is either the name of a predefined set
  172.      * of adjustments, or a parenthesized triple, e.g. "(105, 76,54)"
  173.      */
  174.     /* if s is NULL or "", we do defaults. */
  175.     if (!s || !*s) {
  176.     s = winc_configvar("WinCamColor", "");
  177.     if (!*s) /* i.e. we got back the default val */
  178.         goto defaults;
  179.     }
  180.  
  181. retry:
  182.     if (s[0] == '(') {
  183.     char rparen[2];
  184.     if (sscanf(s, "( %d , %d , %d %1s",
  185.             &ia->red, &ia->green, &ia->blue, rparen) != 4 ||
  186.         rparen[0] != ')')
  187.         goto error_defaults;
  188.     } else if (strncasecmp(s, "sunlight", strlen(s)) == 0) {
  189.     ia->red =   (136*100)/128;    /* 138; */
  190.     ia->green = (134*100)/128;    /* 136; */
  191.     ia->blue =  (115*100)/128;    /* 117; */
  192.     } else if (strncasecmp(s, "flourescent", strlen(s)) == 0) {
  193.     ia->red =   (131*100)/128;    /* 138; */
  194.     ia->green = (142*100)/128;    /* 149; */
  195.     ia->blue =  (111*100)/128;    /* 116; */
  196.     } else if (strncasecmp(s, "tungsten", strlen(s)) == 0 ||
  197.         strncasecmp(s, "incandescent", strlen(s)) == 0) {
  198.     ia->red =   ( 98*100)/128;
  199.     ia->green = (132*100)/128;
  200.     ia->blue =  (157*100)/128;
  201.     } else if (strncasecmp(s, "halogen", strlen(s)) == 0) {
  202.     ia->red =   ( 94*100)/128;    /* 103; */
  203.     ia->green = (149*100)/128;    /* 163; */
  204.     ia->blue =  (140*100)/128;    /* 153; */
  205.     } else if (strncasecmp(s, "studio", strlen(s)) == 0) {
  206.     ia->red =   (112*100)/128;
  207.     ia->green = (131*100)/128;
  208.     ia->blue =  (142*100)/128;
  209.     } else if (strncasecmp(s, "filter", strlen(s)) == 0) {
  210.     ia->red =   (110*100)/128;    /* 104; */
  211.     ia->green = (116*100)/128;    /* 110; */
  212.     ia->blue =  (158*100)/128;    /* 150; */
  213.     } else if (strncasecmp(s, "defaults", strlen(s)) == 0) {
  214.     goto defaults;
  215.     } else {
  216.     /*
  217.      * aliases:  allow the user to set up their own color balances,
  218.      * by setting variables named "WinCamColor_XXXX" where XXXX is
  219.      * matched exactly against the passed-in string.  Most of the
  220.      * time the invocation of winc will be something like "winc -l
  221.      * Office", and we should find something like
  222.      *        "WinCamColor_Office=(100,100,120)", 
  223.      * but we might as well allow for
  224.      *        "WinCamColor_Office=flourescent"
  225.      * as well, so we just fully reparse the value we get.  (Note
  226.      * that since config variable names are case-sensitive, you
  227.      * can't use "winc -l office" unless define "WinCamColor_office".
  228.      */
  229.     ns = s;
  230.     sprintf(newname, "WinCamColor_%.*s", 40 - 15, ns);
  231.     s = winc_configvar(newname, "");
  232.     if (!s || !*s) {
  233.         s = newname;
  234.         goto error_defaults;
  235.     }
  236.     /* we found something.  retry the "parse". */
  237.     goto retry;
  238.     }
  239.     TRACE("g", __FILE__ ": lighting r %d g %d b %d\n",
  240.                     ia->red, ia->green, ia->blue);
  241.     return;
  242.  
  243. error_defaults:
  244.     if (s)
  245.     errormsg("warning: bad color adjust: %s, using defaults\n", s);
  246. defaults:
  247.     ia->red = cfg_number(winc_configvar("WinCamRedLevel", "100"));
  248.     ia->green = cfg_number(winc_configvar("WinCamGreenLevel", "100"));
  249.     ia->blue = cfg_number(winc_configvar("WinCamBlueLevel", "100"));
  250.     TRACE("g", __FILE__ ": default lighting r %d g %d b %d\n",
  251.                     ia->red, ia->green, ia->blue);
  252. }
  253.  
  254. /* set up most of the colordata struct expected by sharpcolor() */
  255. void
  256. setup_colordata(struct colordata *cdp, int cols, int color, int fraction,
  257.     struct winc_image_adjust *ia)
  258. {
  259.  
  260.     /* the sharpcolor routines wants these based on 128 */
  261.     cdp->redlev = (ia->red * 128)/100;
  262.     cdp->greenlev = (ia->green * 128)/100;
  263.     cdp->bluelev = (ia->blue * 128)/100;
  264.  
  265.     cdp->bufwidth = cols;
  266.     cdp->bufheight = (fraction == 1) ? 246 : 492/fraction;
  267.     cdp->intensity = 336;    /* suggested 336 */
  268.     cdp->pixlimits[0] = 3;  /* suggested 3 */
  269.     cdp->pixlimits[1] = 8;  /* suggested 8 */
  270.     cdp->hazelevel = 8;     /* suggested 8 */
  271.     cdp->diflimit  = 42;    /* suggested 42 */
  272.  
  273.     cdp->options = 0
  274.         | OPT_COLOR_AVG 
  275.         /* | OPT_COLOR_CROP */
  276.         | OPT_COLOR_TRACING 
  277.         | OPT_EDGE_CORRECTION
  278.         ;
  279.     if (ia->widen)
  280.     cdp->options |= OPT_HORIZ_STRETCH;
  281.     if (ia->vignette_correction)
  282.     cdp->options |= OPT_VIGNETTE_CORRECTION;
  283.  
  284.     cdp->mode = RESET_LINESTATS;
  285.     sharpcolor(cdp);
  286.  
  287.     cdp->mode = color ? COLOR_INTERLACED_24 : GREY_INTERLACED_8;
  288.  
  289. }
  290.  
  291. byte tempoutput[11*512*3*2];
  292.  
  293.  
  294. void
  295. winc_color_convert(
  296.     byte *image,    /* image from winc_image_snap() or winc_image_fetch() */
  297.     byte *convimage,    /* where to put the rgb result */
  298.     int *rows_p,
  299.     int *cols_p,
  300.     int offs,
  301.     int color,
  302.     int scantype,
  303.     int fraction,
  304.     struct winc_image_adjust *ia)
  305. {
  306.     int rows, cols, outcols, nr, camrow;
  307.     struct colordata cd;
  308.     byte *inp, *outp;
  309.     int rgb;
  310.  
  311.     TRACE("g", __FILE__ ": calling stardot code\n");
  312.  
  313.     rows = *rows_p;
  314.     cols = *cols_p;
  315.  
  316.     rgb = (color) ? 3 : 1;
  317.  
  318.     /* full height single and double-scan images have fraction == 1 here */
  319.     setup_colordata(&cd, cols, color, fraction, ia);
  320.  
  321.     if (fraction != 1)
  322.     scantype = 1;
  323.  
  324.     if (cd.options & OPT_HORIZ_STRETCH)
  325.     outcols = (cols*100)/80;
  326.     else
  327.     outcols = cols;
  328.  
  329.     cd.blacklevs[0] = offs;
  330.     cd.blacklevs[1] = offs;
  331.     cd.temp_off = tempoutput;
  332.  
  333.     nr = 0;
  334.     camrow = 0;
  335.     inp = image;
  336.     outp = convimage;
  337.     while (nr < rows) {
  338.     /* fake up line number the color code expects, in bank/offset form */
  339.     cd.linenum = ((camrow & 1) * 256) + (camrow >> 1);
  340.     cd.input_off = inp;
  341.     cd.result_off = outp;
  342.  
  343.     sharpcolor(&cd);
  344.  
  345.     nr++;
  346.     if (scantype == 2)
  347.         camrow += 1;    /* "use" both banks */
  348.     else
  349.         camrow += 2;    /* use first bank only */
  350.     inp += cols;
  351.     outp += rgb*outcols;
  352.     /* skip every other row for full-height single-scan images */
  353.     if (scantype == 1 && fraction == 1)
  354.         outp += rgb*outcols;
  355.  
  356.     }
  357.  
  358.     /* need to go back and duplicate the odd rows from the even ones */
  359.     if (scantype == 1 && fraction == 1) {
  360.     outp = convimage;
  361.     for (nr = 0; nr < rows; nr ++) {
  362.         memcpy(outp + rgb*outcols, outp, rgb*outcols);
  363.         outp += 2*rgb*outcols;
  364.     }
  365.     *rows_p = rows * 2;
  366.     }
  367.  
  368.     *rows_p = 492/fraction;
  369.     *cols_p = outcols;
  370.  
  371. }
  372.  
  373.  
  374. result
  375. winc_snap_and_process(
  376.     cam_t cam,
  377.     int u_exp,         /* exposure (in microseconds) */
  378.     byte *image,    /* image from winc_image_snap() or winc_image_fetch() */
  379.     byte *convimage,    /* where to put the rgb result */
  380.     int *rows_p,
  381.     int *cols_p,
  382.     int color,
  383.     int scantype,
  384.     int fraction,
  385.     struct winc_image_adjust *ia)
  386. {
  387.     int rows, cols, outrows, outcols, camrow, processrow;
  388.     int start, send, skip, repeat;
  389.     struct colordata cd;
  390.     byte *inp, *outp;
  391.     int blackadj;
  392.     int pairflag;
  393.     int rgb;
  394.     result r;
  395.     byte csum;
  396.     unsigned long sum;
  397.     int got_starfield;
  398.     byte star_line[512];
  399.  
  400.     TRACE("g", __FILE__ ": calling stardot code\n");
  401.  
  402.     if (get_repeats(fraction, 
  403.         &start, &send, &skip, &repeat, &cols, &rows) != OK)
  404.     return NotOK;
  405.  
  406.     /* full height single and double-scan images have fraction == 1 here */
  407.     setup_colordata(&cd, cols, color, fraction, ia);
  408.  
  409.     if (fraction != 1)
  410.     scantype = 1;
  411.  
  412.     if (cd.options & OPT_HORIZ_STRETCH)
  413.     outcols = (cols*100)/80;
  414.     else
  415.     outcols = cols;
  416.  
  417.     outrows = 492/fraction;
  418.  
  419.     if (winc_black_offset(cam, &blackadj, 0 ) != OK) {
  420.     errormsg(__FILE__ ": failed to get black adjustment\n");
  421.     return NotOK;
  422.     }
  423.     r = winc_image_expose(cam, scantype, fraction, u_exp, image);
  424.     if (r != OK)
  425.     return r;
  426.  
  427.     rgb = (color) ? 3 : 1;
  428.  
  429.     cd.blacklevs[0] = blackadj;
  430.     cd.blacklevs[1] = blackadj;
  431.     cd.temp_off = tempoutput;
  432.  
  433.     pairflag = 0;
  434.     camrow = 0;
  435.     processrow = 0;
  436.     inp = image;
  437.     outp = convimage;
  438.  
  439.     /* send the initial get row command */
  440.     if (winc_send_cmd(cam, Cmd_send_row, camrow>>1, (camrow & 1), 
  441.             start, send, skip, repeat/2,
  442.             -1) != OK)
  443.     return NotOK;
  444.  
  445.     while (1) {
  446.  
  447.     got_starfield = (winc_starfield_line(star_line, cam, camrow,
  448.                     start, send, skip, repeat) == OK);
  449.  
  450.     /* get 512 bytes plus a checksum byte */
  451.     if (winc_get_resp_wait(cam, cols, inp, 2000, &sum) != OK)
  452.         return NotOK;
  453.  
  454.     if (winc_get_resp_wait(cam, 1, &csum, 200, 0) != OK)
  455.         return NotOK;
  456.  
  457.     if ((sum & 0xff) != csum)
  458.         errormsg( __FILE__ 
  459.         ": warning: camera row %d checksum incorrect\n", camrow);
  460.  
  461.     if (got_starfield)
  462.         winc_starfield_fix(inp, star_line, cols);
  463.  
  464.     /* fake up line number the color code expects, in bank/offset form */
  465.     cd.linenum = ((processrow & 1) * 256) + (processrow >> 1);
  466.     cd.input_off = inp;
  467.     cd.result_off = outp;
  468.  
  469.  
  470.     inp += cols;
  471.     outp += rgb*outcols;
  472.     /* skip every other row for full-height single-scan images */
  473.     if (scantype == 1 && fraction == 1)
  474.         outp += rgb*outcols;
  475.  
  476.     /* of the 492 possible rows (in two banks) the camera can give us,
  477.      * which do we _really_ want? */
  478.     if (scantype == 2) {    /* double scan -- all of them, both banks */
  479.         camrow++;
  480.         processrow++;
  481.     } else if (fraction <= 2) { /* full/half height -- every row in bank */
  482.         camrow += 2;
  483.         processrow += 2;
  484.     } else if (!color) {    /* greyscale -- simple alternation */
  485.         camrow += fraction/2;
  486.         processrow += 2;
  487.     } else {
  488.         /* to satisfy color processing req'ts we want to take rows from
  489.          * the camera in pairs.  so rather than taking alternate rows, we
  490.          * take 2, skip 2, or take 2, skip 6, etc.
  491.          */
  492.         camrow += 2 * ((pairflag++ & 1) ? fraction - 1 : 1);
  493.         processrow += 2;
  494.     }
  495.  
  496.     if (camrow >= 492)
  497.         break;
  498.  
  499.     if (winc_send_cmd(cam, Cmd_send_row, camrow>>1, (camrow & 1), 
  500.             start, send, skip, repeat/2,
  501.             -1) != OK)
  502.         return NotOK;
  503.  
  504.     /* while that data is arriving, process the previous row */
  505.     sharpcolor(&cd);
  506.  
  507.     }
  508.  
  509.     /* one more row to process */
  510.     sharpcolor(&cd);
  511.  
  512.     /* need to go back and duplicate the odd rows from the even ones */
  513.     if (scantype == 1 && fraction == 1) {
  514.     outp = convimage;
  515. #if 1 || COPY
  516.     for (camrow = 0; camrow < 246; camrow++) {
  517.         memcpy(outp + rgb*outcols, outp, rgb*outcols);
  518.         outp += 2*rgb*outcols;
  519.     }
  520. #else
  521.     for (camrow = 0; camrow < 245; camrow++) {
  522.         int i;
  523.         for (i = 1; i < rgb*outcols - 1; i++) {
  524.         *(outp + i + rgb*outcols) =  (
  525.         *(outp + i + 0 * rgb*outcols - rgb) +
  526.         2 * *(outp + i + 0 * rgb*outcols    ) +
  527.         *(outp + i + 0 * rgb*outcols + rgb) +
  528.         *(outp + i + 2 * rgb*outcols - rgb) +
  529.         2 * *(outp + i + 2 * rgb*outcols    ) +
  530.         *(outp + i + 2 * rgb*outcols + rgb) ) / 8;
  531.         }
  532.         outp += 2*rgb*outcols;
  533.     }
  534.     memcpy(outp + rgb*outcols, outp, rgb*outcols);
  535.     outp += 2*rgb*outcols;
  536. #endif
  537.     }
  538.     *rows_p = outrows;
  539.     *cols_p = outcols;
  540.  
  541.     return OK;
  542.  
  543. }
  544.  
  545.  
  546.  
  547. /* 
  548.  * the wincam images are narrow by 20%, i.e. they need to be expanded
  549.  * by 25% (512 becomes 640) to make the scene aspect ratio right.
  550.  * this does that, in a simple, hard-coded way.
  551.  *
  552.  * there are 5 new pixels for every 4 old pixels.
  553.  *
  554.  *    0    1    2    3      4    5    6     7    8    9
  555.  *  |     |    |    |    |    |      |    |    |     | original pixels
  556.  *  --------------------------------------------------------------
  557.  *  |    |   |    |   |    |   |    |   |    |   |    | wider image pixels
  558.  *    0   1   2   3   4   5   6   7   8   9  10  11
  559.  *
  560.  * new pixel 0 is .8 * old pixel 0
  561.  * new pixel 1 is .2 * old pixel 0 plus .6 * old pixel 1.
  562.  * etc.
  563.  *
  564.  * we start at the end and work backwards so we can do it in-place.
  565.  *
  566.  * note that this results in a blurring of the image.  it could be
  567.  * argued that it would be better to preserve bits 1 through 4, and just
  568.  * create a 5th by duplicating 4, or perhaps averaging between 4 and 6.
  569.  * indeed, that's exactly what StarDot's code does.
  570.  */
  571.  
  572. int
  573. winc_aspect_fix(
  574.     byte *image,
  575.     int rows,
  576.     int origcols,
  577.     int rgb)
  578. {
  579.     int newcols = 5 * origcols / 4;    /* new image is 125% as wide as old */
  580.     int nc;
  581.     byte *widerimage;
  582.  
  583.     if (!rgb) {
  584.     widerimage = image + rows * newcols;
  585.     image = image + rows * origcols;
  586.  
  587.     while (rows--) {
  588.         for (nc = newcols; nc > 0; nc -= 5) {
  589.         image -= 4;
  590.         widerimage -= 5;
  591.         widerimage[4] = (4 * image[3]            ) / 4;
  592.         widerimage[3] = (1 * image[3] + 3 * image[2]) / 4;
  593.         widerimage[2] = (2 * image[2] + 2 * image[1]) / 4;
  594.         widerimage[1] = (3 * image[1] + 1 * image[0]) / 4;
  595.         widerimage[0] = (        4 * image[0]) / 4;
  596.  
  597.         }
  598.     }
  599.     } else { /* same as above, but for each of three colors */
  600. #define B 3
  601.     widerimage = image + rows * newcols * B;
  602.     image = image + rows * origcols * B;
  603.  
  604.     while (rows--) {
  605.         for (nc = newcols; nc > 0; nc -= 5) {
  606.         image -= 4*B;
  607.         widerimage -= 5*B;
  608.         widerimage[4*B+2] = (4 * image[3*B+2]            ) / 4;
  609.         widerimage[4*B+1] = (4 * image[3*B+1]            ) / 4;
  610.         widerimage[4*B+0] = (4 * image[3*B+0]            ) / 4;
  611.         widerimage[3*B+2] = (1 * image[3*B+2] + 3 * image[2*B+2]) / 4;
  612.         widerimage[3*B+1] = (1 * image[3*B+1] + 3 * image[2*B+1]) / 4;
  613.         widerimage[3*B+0] = (1 * image[3*B+0] + 3 * image[2*B+0]) / 4;
  614.         widerimage[2*B+2] = (2 * image[2*B+2] + 2 * image[1*B+2]) / 4;
  615.         widerimage[2*B+1] = (2 * image[2*B+1] + 2 * image[1*B+1]) / 4;
  616.         widerimage[2*B+0] = (2 * image[2*B+0] + 2 * image[1*B+0]) / 4;
  617.         widerimage[1*B+2] = (3 * image[1*B+2] + 1 * image[0*B+2]) / 4;
  618.         widerimage[1*B+1] = (3 * image[1*B+1] + 1 * image[0*B+1]) / 4;
  619.         widerimage[1*B+0] = (3 * image[1*B+0] + 1 * image[0*B+0]) / 4;
  620.         widerimage[0*B+2] = (            4 * image[0*B+2]) / 4;
  621.         widerimage[0*B+1] = (            4 * image[0*B+1]) / 4;
  622.         widerimage[0*B+0] = (            4 * image[0*B+0]) / 4;
  623.         }
  624.     }
  625.     }
  626.     return newcols;
  627. }
  628.  
  629. #define absval(a) (((a) >= 0) ? (a) : -(a))
  630.  
  631. int
  632. winc_compare_image(
  633.     byte *image1,  /* the two images being */
  634.     byte *image2,  /*    compared */
  635.     int rows,       /* rows of pixels */
  636.     int cols,       /* columns of pixels */
  637.     int maxdiff,   /* percent pixels changed for image to be diff */
  638.     int thresh,    /* amount pixel val must, as percentage of max */
  639.     int maxval,    /* maximum pixel value */
  640.     int rgb)       /* boolean -- three bits per pixel, or one */
  641. {
  642.     int i;
  643.     int d;
  644.     int diffcount = 0;
  645.  
  646.     /* convert percentages to absolutes */
  647.     maxdiff = (maxdiff * (rows * cols)) / 100;
  648.     thresh = (thresh * (maxval+1)) / 100;
  649.  
  650.     for (i = rows * cols * (rgb ? 3 : 1); i > 0; i--) {
  651.     d = *image1 - *image2;
  652.     if (absval(d) > thresh) {
  653.         if (++diffcount > maxdiff)
  654.         return 0;
  655.     }
  656.     image1++;
  657.     image2++;
  658.  
  659.     }
  660.     return 1;
  661. }
  662.  
  663.  
  664. #ifdef HARDLY_WORTH_SAVING  /* my early attempt at color processing */
  665. /*
  666.  * color is tricky.  here's how i understand it.
  667.  * the sensors in the CCD array are arranged in clusters of four, and
  668.  * each of the four is sensitive to a different color.
  669.  * the pairs in the even rows can be combined simply to get red, the pairs
  670.  * in the odd rows can be combined simply to get blue, and if you combine
  671.  * all four, and subtract red and blue, you'll get something resembling
  672.  * green.  :-)    that all works pretty well, and for solid color scenes, i
  673.  * think the code below (or something simpler) would do just fine.  for
  674.  * each output rgb pixel on the screen, it calculates the r, g, and b
  675.  * values from the sensor cluster of which it is the upper left element.
  676.  * the far right column and the bottom row are treated specially, and are
  677.  * simply copies of the column (or row) previous.
  678.  * 
  679.  * white balance should be achieved by tuning the equations for creating
  680.  * red, blue, and green.
  681.  *
  682.  * the big trouble comes when an image transition falls in the middle of
  683.  * one of these clusters of 4 sensors.    then you calculate a red value, for
  684.  * instance, from two sensors that are actually "sensing" unrelated parts
  685.  * of the image, and you may get a bright (often red) spot that shouldn't
  686.  * be there.
  687.  *
  688.  * my lame initial attempt at fixing this modifies the basic calculation
  689.  * thusly:  for each pixel, calculate the red and blue values as usual from
  690.  * the cluster to the right, but also calculate them from the cluster to
  691.  * the left.  chose the value wiht the lower red and blue values.  this
  692.  * gets rid of "spikes", but it also seems to remove a lot of color
  693.  * information.  it also doesn't do anything about vertical transitions.
  694.  * consider it an experiment-in-progress.
  695.  *
  696.  * oh -- the above algorithms are complicated by the fact that the data
  697.  * is in "banks" returned from the two scans, and that their are two sets
  698.  * of sensors interleaved.  so, taking that interleaving into account,
  699.  * the sensors look like:
  700.  * 
  701.  *
  702.  *    cyg  yemg cyg  yemg cyg  yemg ... 
  703.  *    cyg  yemg cyg  yemg cyg  yemg ... 
  704.  *    cymg yeg  cymg yeg  cymg yeg  ... 
  705.  *    cymg yeg  cymg yeg  cymg yeg  ... 
  706.  *    cyg  yemg cyg  yemg cyg  yemg ... 
  707.  *    cyg  yemg cyg  yemg cyg  yemg ... 
  708.  *    cymg yeg  cymg yeg  cymg yeg  ... 
  709.  *    cymg yeg  cymg yeg  cymg yeg  ... 
  710.  *    .
  711.  *    .
  712.  *    .
  713.  *
  714.  * the "official" equations look something like:
  715.  *    red = yemg - .71 * cyg.
  716.  *    blue = cymg - .66 * yeg.
  717.  *    green = ((yemg+cyg+cymg+yeg)/2 - red - blue) / 2.
  718.  * but as you can see below, i've played with that a lot.
  719.  *
  720.  * i'm not happy with this at all.  but it only took a day or two
  721.  * so far.
  722.  */
  723.  
  724. static void putcolors(int, int, int, int, int, int, int, int, byte *);
  725.  
  726. void
  727. winc_color_convert(
  728.     byte *image,
  729.     byte *convimage,
  730.     int rows,
  731.     int cols,
  732.     int offs,
  733.     int scantype,
  734.     int fraction,
  735.     struct winc_image_adjust *ia)
  736. {
  737.     int r, c;
  738.     int cyg = 0, yemg = 0, cymg = 0, yeg = 0;
  739.     int cyg2 = 0, yemg2 = 0, cymg2 = 0, yeg2 = 0; 
  740.     int u, l, ul, ur, ll, lr;
  741.  
  742.     TRACE("g", __FILE__ ": emitting PGM format\n");
  743.  
  744.     /* this could _clearly_ be sped way up.  if i thought it
  745.      * was even close to "right", i might even bother.
  746.      */
  747.     for (r = 0; r < rows - 1 ; r++) {
  748.     for (c = 0; c < cols - 1 ; c++, image++) {
  749.         u = *image;
  750.         l = *(image + 2 * cols);
  751.         ur = *(image + 1);
  752.         lr = *(image + 2 * cols + 1);
  753.         if (c) {
  754.         ul = *(image - 1);
  755.         ll = *(image + 2 * cols - 1);
  756.         } else {
  757.         ul = ur;
  758.         ll = lr;
  759.         }
  760.         if (offs) {
  761.         u  -= offs; if (u  < 0) u  = 0;
  762.         l  -= offs; if (l  < 0) l  = 0;
  763.         ur -= offs; if (ur < 0) ur = 0;
  764.         lr -= offs; if (lr < 0) lr = 0;
  765.         ul -= offs; if (ul < 0) ul = 0;
  766.         ll -= offs; if (ll < 0) ll = 0;
  767.         }
  768.         if (EVEN(c) && EVEN(r/2)) {
  769.         cyg   = u; 
  770.         cyg2  = u; 
  771.         yemg  = ur; 
  772.         yemg2 = ul; 
  773.         cymg  = l; 
  774.         cymg2 = l; 
  775.         yeg   = lr; 
  776.         yeg2  = ll; 
  777.         } else if (ODD(c) && EVEN(r/2)) {
  778.         yemg  = u;
  779.         yemg2 = u;
  780.         cyg   = ur;
  781.         cyg2  = ul;
  782.         yeg   = l;
  783.         yeg2  = l;
  784.         cymg  = lr;
  785.         cymg2 = ll;
  786.         } else if (EVEN(c) && ODD(r/2)) {
  787.         cymg  = u;
  788.         cymg2 = u;
  789.         yeg   = ur;
  790.         yeg2  = ul;
  791.         cyg   = l;
  792.         cyg2  = l;
  793.         yemg  = lr;
  794.         yemg2 = ll;
  795.         } else /* (ODD(c) && ODD(r/2)) */ {
  796.         yeg   = u;
  797.         yeg2  = u;
  798.         cymg  = ur;
  799.         cymg2 = ul;
  800.         yemg  = l;
  801.         yemg2 = l;
  802.         cyg   = lr;
  803.         cyg2  = ll;
  804.         }
  805.         putcolors(cyg, yemg, cymg, yeg, cyg2, yemg2, cymg2, yeg2, convimage);
  806.         convimage += 3;
  807.     }
  808.     /* take care of last column -- we just copy the column before */
  809.     putcolors(cyg, yemg, cymg, yeg, cyg2, yemg2, cymg2, yeg2, convimage);
  810.     convimage += 3;
  811.     image++;
  812.     }
  813.     /* take care of last row -- it's really a copy of the row above, but
  814.     that data is gone, so we reproduce it here */
  815.     for (c = 0; c < cols - 1 ; c++, image++) {
  816. #if LATER
  817.     if (EVEN(c)) {
  818.         cymg = *image;
  819.         yeg = *(image + 1);
  820.         cyg = *(image - 2 * cols);
  821.         yemg = *(image - 2 * cols + 1);
  822.     } else /* if (ODD(c)) */ {
  823.         yeg = *image;
  824.         cymg = *(image + 1);
  825.         yemg = *(image - 2 * cols);
  826.         cyg = *(image - 2 * cols + 1);
  827.     }
  828.     putcolors(cyg, yemg, cymg, yeg, convimage);
  829. #else
  830.     putcolors(0, 0, 0, 0, 0, 0, 0, 0, convimage);
  831. #endif
  832.     convimage += 3;
  833.     }
  834.  
  835.     /* take care of last pixel -- again, it's the same as the one just
  836.      * before */
  837. #if LATER
  838.     putcolors(cyg, yemg, cymg, yeg, convimage);
  839. #else
  840.     putcolors(0, 0, 0, 0, 0, 0, 0, 0, convimage);
  841. #endif
  842.     convimage += 3;
  843.  
  844. }
  845.  
  846. static void
  847. putcolors(int cyg, int yemg, int cymg, int yeg, 
  848.     int cyg2, int yemg2, int cymg2, int yeg2, byte *outp)
  849. {
  850.     int red, blue, green;
  851.     int red2, blue2;
  852. #if OFFICIAL
  853.     red  = yemg - (cyg * 7)/10;
  854.     blue = cymg - (yeg * 2)/3;
  855.     green = ((yemg + cyg + cymg + yeg)/2 - red - blue) / 2;
  856. #else
  857.     red  = yemg - (cyg * 7)/10;
  858.     if (red < 0) red = 0;
  859.     red2  = yemg2 - (cyg2 * 7)/10;
  860.     if (red2 < 0) red2 = 0;
  861.     blue = cymg - (yeg * 2)/3;
  862.     if (blue < 0) blue = 0;
  863.     blue2 = cymg2 - (yeg2 * 2)/3;
  864.     if (blue2 < 0) blue2 = 0;
  865. #if 1
  866.     if (red > red2 || blue > blue2) {
  867.     red = red2;
  868.     blue = blue2;
  869.     yemg = yemg2;
  870.     cyg = cyg2;
  871.     cymg = cymg2;
  872.     yeg = yeg2;
  873.     }
  874. #endif
  875.     green = (((yemg + cyg + cymg + yeg)/2 - red - blue) * 4) / 9;
  876.     red = (red * 5) / 2;
  877.     blue = (blue * 5) / 2;
  878.     if (red > 255) {
  879.     red = 255;
  880.     }
  881.     if (green > 255) {
  882.     green = 255;
  883.     }
  884.     if (blue > 255) {
  885.     blue = 255;
  886.     }
  887. #endif
  888.  
  889.     TRACE("g", __FILE__ ": cyg %d yemg %d cymg %d yeg %d\n",
  890.                 cyg, yemg, cymg, yeg);
  891.     TRACE("g", __FILE__ ": rgb are %d %d %d\n", red, green, blue);
  892.  
  893.     *outp++ = red;
  894.     *outp++ = green;
  895.     *outp = blue;
  896. }
  897. #endif
  898.