home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / procssng / ccs / ccs-11tl.lha / lbl / x11 / lib / function.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-10  |  15.8 KB  |  592 lines

  1. /*
  2. %    FUNCTION . C
  3. %
  4. %    Copyright (c)    1991, 1993    Jin Guojun
  5. %
  6. %    This file includes Elastic Tuning Algorithm (ETA) (c). That maxout can
  7. %    not exceed 255 is important since only BYTE format accepted by TUNER.C.
  8. %    The real Elastic can handle byte, short, int and float format.
  9. %    So for non-byte format, scale it to byte for analysizing and
  10. %    apply Elastic to original format for final result.
  11. %    For others using ETA, use eta_curve().
  12. %
  13. %    Quantization is useful while graylevel is less than 32.
  14. %    The algorithm of quantization in this program is that sort the
  15. %    histogram in frequency order and apply the elastic function to
  16. %    corresponding index (grey level) to get those significant grey
  17. %    levels and fill them to Pseudo-color table -- graylevel, and then,
  18. %    fill as many regular stepped grey levels from top value to bottom
  19. %    as possible (If not possible, then the closest value will be used).
  20. %    The final step is to create digitizer table according to graylevel.
  21. %
  22. % Changes:    4-20-91
  23. %    All functions are mapped by quantization table(dgt), The dgt is scaling
  24. %    table (pseudo direct map table). The lkt is an enhancement table which
  25. %    always use the first entry to store minimum pixel mapping. The
  26. %    graylevel table is the real index table.
  27. %        The histogram equalization function shift minimum entry to 0
  28. %    so that multiple table index can correctly apply for every function.
  29. %    This change makes whole system to be consistent and more reliable.
  30. %    i.e. finally, the DIRECT version and the QUANTIZING version
  31. %    all use 256 level entries. The DIRECT directly maps pixel values to
  32. %    graylevel entries. The regular version uses dgt to map pixel values
  33. %    to graylevel entries. Same thing has to be done on reset routine, but
  34. %    not applied on color version. The color version must keep regular
  35. %    linear table.
  36. %    The HistoHandle() also added a segment program to use lkt to map hist,
  37. %    which is a trick work like program in CreateCLT() and FillDGT().
  38. %
  39. %        7-12-91
  40. %    Interpolation for all enhancement on main peak area.
  41. %
  42. %        7-1-1992
  43. %    Add canvas in windows.
  44. %
  45. % AUTHOR:    Jin Guojun - LBL    4/1/91
  46. */
  47.  
  48. #include "function.h"
  49.  
  50. #ifndef    VSC_BASE
  51. #define    VSC_BASE    .01
  52. #endif
  53.  
  54. bool    cntz, top;    /* count zero, top value clipping */
  55. int    topv, *dgt;
  56. PColor    MGray, Light;
  57. Panel    *Epanel;
  58. Slider    *ESlider, *LSlider, *slider, *CSlider, *QSlider;
  59. Button    *DButton, *EButton, *FButton, *fButton, *hButton, *QButton,
  60.     *ZButton, *maxButt, *Interpolate;
  61. PressButton    *RstButt, *heqButt, *rfsButt;
  62. HistoInfo    histinfo;
  63.  
  64.  
  65. /*===============================================
  66. %    Initial and Display image information    %
  67. %    on either top or bottom of the window    %
  68. %    of a panel to which xbutton belongs.    %
  69. ===============================================*/
  70. SetParameterWin(img, xbutton, Font_Height, top)
  71. Image    *img;
  72. XButtonEvent    *xbutton;
  73. {
  74. register int    py=img->frame==img->win ? 0 : img->y0;
  75.     if (xbutton->y
  76. #ifdef    SCROLLBAR_on_CANVAS
  77.             - img->y0
  78. #endif
  79.                 > (img->resize_h>>1) || top)
  80.         img->tmp_offset = Font_Height+IIMargin;
  81.     else    img->tmp_offset = -Font_Height-IIMargin,
  82.         py
  83. #ifdef    SCROLLBAR_on_CANVAS
  84.             +
  85. #endif
  86.             = img->resize_h + img->tmp_offset;
  87. return    py;
  88. }
  89.  
  90. /*===============================================================
  91. %    draw a sub-window either on the top or buttom of a      %
  92. %    window to display corresponding image information    %
  93. ===============================================================*/
  94. void
  95. ParameterWin(ii, hinf, x, y, y0, is_hist)
  96. Image    *ii;
  97. HistoInfo    *hinf;
  98. {
  99. int    fn=(ii->color_dpy ? ii->fn % ii->channels : ii->frames>1 ? ii->fn : 0),
  100.     yv, pos, vor, vr, w=ii->width, h=ii->height, mi=ii->mmm.min;
  101. char    buf[128];
  102. byte    *rp = ii->data + (ii->color_dpy ? 0 : w*h*fn);
  103. LKT*    lkt = hinf->lkt;
  104.  
  105.     if (x<0)    x=0;
  106.     if (y<0)    y=0;
  107.     if (x>w)    x=w;
  108.     if (y>h)    y=h;
  109.  
  110. #ifdef    SCROLLBAR_on_CANVAS
  111. #define    SoC    ii->x0 +
  112. #define    SoX
  113. #define    SoY
  114.     if (!is_hist)    mi=ii->marray[fn].min;
  115. #else
  116. #define    SoC
  117. #define    SoX    img->x0 +
  118. #define    SoY    img->y0 +
  119.     x += ii->x0;
  120.     if (!is_hist)    y += ii->y0,    mi=ii->marray[fn].min;
  121. #endif
  122.     pos = (is_hist | !ii->color_dpy ? y :
  123.         y * ii->channels + ii->fn % ii->channels) * w + x;
  124.     if (is_hist)    {
  125.         if (ii->color_dpy)
  126.             yv = y % (HistoSize+(BFRAME<<1));
  127.         else    yv = y;
  128.         yv = (int)((1 - (float)(yv-BFRAME)/HistoSize) * ii->mmm.maxcnt)
  129.             >> hinf->scale;
  130.         while (x && --x >= HistoSize);
  131.         vor = ii->image->data[pos] != HBGround;
  132.         vr = ii->mark_x - 1;
  133.     } else    {
  134.         yv = y;
  135.         vor = rp[pos];
  136.         vr = lkt[vor - mi];
  137.     }
  138.     if (is_hist || ii->dpy_channels==1)
  139.         sprintf(buf, "%d %d = %d [%d] {sub_image %d %d}", x, yv,
  140.             vor, vr, ii->sub_img_w, ii->sub_img_h);
  141.     else    {
  142.     register int    vog=rp[pos + w], vob=rp[pos + (w<<1)];
  143.         lkt += MaxColors;
  144.         sprintf(buf, "%d %d = %d %d %d [%d %d %d] {sub_image %d %d}",
  145.         x, yv, vor, vog, vob, vr, lkt[vog - mi],
  146.         (lkt + MaxColors)[vob - mi], ii->sub_img_w, ii->sub_img_h);
  147.     }
  148.     XClearArea(ii->dpy, ii->win, SoC 0, y0, 0, abs(ii->tmp_offset), 0);
  149.     XSetForeground(ii->dpy, ii->gc, White);
  150.     XDrawString(ii->dpy, ii->win, ii->gc, SoC 20, y0+ii->ascent,
  151.         buf, strlen(buf));
  152.     XFlush(ii->dpy);
  153. }
  154.  
  155. /*===============================================================
  156. %    Crop a sub-window. If either height or width < 4    %
  157. %    discard it. The recover routine must be associated    %
  158. %    with exposure handle routine.                %
  159. ===============================================================*/
  160. TrackSubWin(img, hinf, ox, oy, shp, cropButton, y0)
  161. Image    *img;
  162. HistoInfo    *hinf;
  163. {
  164. Window    parent, child;
  165. int    pw, ph, cx, cy, key_button;
  166. float    f = -img->mag_fact;
  167.  
  168. if (f < 0)    f = -1 / f;
  169. ox = f * (SoX ox) + img->mag_x,
  170. oy = f * (SoY oy) + img->mag_y;
  171.  
  172. while(1)    {
  173.     ImageEvent(img, PointerMotionMask);
  174.     if (XQueryPointer(img->dpy, img->win, &parent, &child, &pw, &ph, &cx, &cy,
  175.         &key_button))    {
  176.     if (!(key_button & cropButton))    break;
  177.  
  178.     if (img->sub_img)
  179.         Draws(img, 0, 1, img->sub_img);
  180.     cx = f * (SoX cx) + img->mag_x;
  181.     cy = f * (SoY cy) + img->mag_y;
  182.     if (cx < 0)    cx = 0;
  183.     else if (cx > img->width)
  184.         cx = img->width;
  185.     if (cy < 0)    cy = 0;
  186.     else if (cy > img->height)
  187.         cy = img->height;
  188.     pw = cx - ox;
  189.     ph = cy - oy;
  190.     if (pw < 0 && shp != DrawsLine)    {
  191.         pw = -pw;
  192.         img->sub_img_x = cx;
  193.     }
  194.     else    img->sub_img_x = ox;
  195.     if (ph < 0 && shp != DrawsLine)    {
  196.         ph = -ph;
  197.         img->sub_img_y = cy;
  198.     }
  199.     else    img->sub_img_y = oy;
  200.     img->sub_img_w = pw;
  201.     img->sub_img_h = ph;
  202.     img->sub_img = Draws(img, 0, 1, shp);
  203.     ParameterWin(img, hinf, img->sub_img_x, img->sub_img_y, y0, 0);
  204.     }
  205. }
  206. ClearParameterWin(img, y0);
  207. return    img->sub_img;
  208. }
  209.  
  210. VType*
  211. map_1_to_3(src, dest, cmap, w, h)
  212. register char    *src, *dest;
  213. cmap_t    **cmap;
  214. {
  215. register int    r = h;
  216.     if (!dest)    dest = nzalloc(w*3, r, "1_to_3");
  217.     while (r--) {
  218.         snf_to_rle(dest, src, w, 8, cmap);
  219.         dest += w*3;
  220.         src += w;
  221.     }
  222. return    (VType*)(dest - h*w*3);
  223. }
  224.  
  225. void
  226. LinearQuantization(cp, totalevel, cflag, rev)
  227. register XColor    *cp;
  228. register int    totalevel, cflag;
  229. {
  230. register int    i, gray, scale = 65536 / totalevel;
  231.  
  232.     for (i=0; i<totalevel; i++)    {
  233.     if (rev)
  234.         gray = totalevel - i - 1;
  235.     else    gray = i;
  236.     cp[i].pixel = gray;    /* for newmap only */
  237.     cp[i].red = cp[i].green = cp[i].blue = scale * gray;
  238.     cp[i].flags = cflag;
  239.     }
  240. }
  241.  
  242. /*==========================================
  243.     Create the Color Lookup Table.
  244. ==========================================*/
  245. CreateCLT(cp, totalevel, cflag, DoQuant, rev, hinf)
  246. XColor    *cp;
  247. HistoInfo    *hinf;
  248. {
  249. register short    j;
  250. register int    i;
  251. int    new_colors;
  252.  
  253. if (DoQuant & 1)    {
  254. Mregister    mmm;
  255. int    qlkt[MaxColors], *histp=hinf->histp,
  256.     *newhist=(int*)zalloc(MaxColors, sizeof(*newhist), "CltHist");
  257.     for (i=0; i<MaxColors; i++)
  258.         newhist[((LKT *)(hinf->lkt))[i]] += histp[i];
  259.     for (i=0; i<MaxColors; i++)    {
  260.         QSArray[i].value = newhist[i];
  261.         QSArray[i].QsIndex = i;    /* grey level to index */
  262.     }
  263.     QuickSort(0, MaxColors-1, MaxColors, QSArray);
  264.     for (i=0; i<MaxColors; i++)
  265.         if (!QSArray[i].value)    break;
  266.     if (DEBUGANY)    ShowA(QSArray, i);
  267.     mmm.min = 0;    mmm.max = totalevel;
  268.     new_curve(qlkt, hinf, &mmm, ETAQuant, i, 0, DoQuant>>1);
  269.     new_colors = totalevel << 1; /* new level may have more close values */
  270.     for (i=0; i<totalevel; i++) {    /* put important color at first. */
  271.         dgt[i] = QSArray[qlkt[i]].QsIndex;
  272.         j = dgt[i] << 8;    /* set to high byte */
  273.         cp[i].red = cp[i].green = cp[i].blue = j;
  274.         cp[i].flags = cflag;
  275. #ifdef    TRICK_Quant
  276.         newhist[qlkt[i]] = -1;    /* use newhist as flag registers */
  277.     }
  278.     for (j=0; j<totalevel<<1; j++){    /* put other colors */
  279.         if (newhist[j] < 0)    continue;
  280.         dgt[i] = QSArray[j].QsIndex;    /* save grey levels */
  281.         cp[i].red=cp[i].green=cp[i].blue = dgt[i]<<8;
  282.         cp[i++].flags = cflag;
  283.     }
  284.     for (i=0; i<new_colors; i++)    /* store grey levels */
  285.         QSArray[i].value = dgt[i];
  286. #else
  287.     }
  288.     LinearQuantization(cp+totalevel, totalevel, cflag, rev);
  289.     for (i=0; i<totalevel; i++)    /* store grey levels */
  290.         QSArray[i].value = dgt[i];
  291.     for (; i<new_colors; i++)
  292.         QSArray[i].value = cp[i].red >> 8;
  293. #endif
  294.     free(newhist);
  295. }
  296. else{    LinearQuantization(cp, totalevel, cflag, rev);
  297.     for (i=0; i<totalevel; i++)
  298.         QSArray[i].value = cp[i].red >> 8;
  299.     new_colors = totalevel;
  300.     }
  301. FillDGT(new_colors, dgt);
  302. return    new_colors;
  303. }
  304.  
  305. /*=======================================================================
  306. %    After create ColorLookTable, graylevel.rgb>>8 = QSArray.value    %
  307. %    1.    quicksort histogram in high frequency order        %
  308. %    2.    using elastic function pick significant grey levels    %
  309. %    3.    filling Pseudo-color table -- graylevel -- with result 2
  310. %    4.    filling graylevel with less frequency grey levels    %
  311. %    5.    3 & 4 save grey levels into QSArray[i].value        %
  312. %    6.    filling Digitizer Table -- FillDGT            %
  313. =======================================================================*/
  314. FillDGT(n, dgtp)
  315. register int    n, *dgtp;
  316. {
  317. register int    i, j;
  318.     for (j=0; j<MaxColors; j++)
  319.         dgtp[j] = 0;
  320.     for (i=0; i<n; i++)    /* build index's index    */
  321.         dgtp[QSArray[i].value] = i;
  322.     i = j-1;
  323.     while (!dgtp[--j]);
  324.     dgtp[i] = dgtp[j];
  325.     do {
  326.         for (j=i; --j;)
  327.         if (dgtp[j])    break;
  328.         if (i-j > 1) {
  329.         register int    k;
  330.         for (k=j+i >> 1; k>j; k--)
  331.             dgtp[k] = dgtp[j];
  332.         k = j+i >> 1;
  333.         if (i-j & 1)    k++;
  334.         for (;k<i; k++)
  335.             dgtp[k] = dgtp[i];
  336.         }
  337.     } while(i=j);    /* assignment */
  338. #ifdef    _DEBUG_
  339.     if (verbose>2)    dump_tbl(dgtp, MaxColors, 8, "dgt");
  340. #endif
  341. }
  342.  
  343.  
  344. /*=======================================
  345. *    maxout should be float point    *
  346. *    maxdiff is max-min+1,        *
  347. *    the 1 is a cell for boundary.    *
  348. *    lkt always start from 0.    *
  349. *    foreground ELA start at 1.    *
  350. *    if type=Quant, hsize=QuantV.    *
  351. =======================================*/
  352. new_curve(lkt, hinf, mmm, type, Maxout, img, hsize)
  353. LKT    *lkt;
  354. HistoInfo    *hinf;
  355. Mregister    *mmm;
  356. register int    Maxout;
  357. Image    *img;
  358. {
  359. int    flr, *histp=hinf->histp, maxdiff=mmm->max - mmm->min + 1;
  360. float    maxout;
  361. register int    i;
  362. register float    rel_val, scale, vsc;
  363.  
  364. if (img && img->color_dpy)    {
  365. register int    boff=img->fn%3 * MaxColors;
  366.     lkt += boff;
  367.     histp += boff;
  368.     if ((img->dpy_depth==24) | (img->entries<8))
  369.         maxdiff = 256;
  370.     else if (maxdiff>2)    /* unpacked bitmap */
  371.         maxdiff = img->entries;
  372.     else if (type != ETALinear)
  373.             maxdiff <<= 1;
  374. }
  375. if (type != ETAQuant)    {
  376.     flr = img->linearlow;
  377.     Maxout = img->linearup;
  378. }
  379. else    flr = 1;
  380.  
  381. maxout = Maxout;
  382.  
  383. if (verbose || maxdiff<8)
  384.     message("min=%d, max=%d, flr=%d, top=%.2f, maxdiff=%ld\n",
  385.     mmm->min, mmm->max, flr, maxout, maxdiff);
  386.  
  387. if (type==ETALinear && maxdiff > 1)    {
  388.     scale = (maxout - flr) / --maxdiff;
  389.     for (i=maxdiff; i; i--)
  390.         lkt[i] = i * scale + flr;
  391.     i = maxdiff;    /* cut top    */
  392. }
  393. else if (maxdiff < 3)
  394.     return;
  395. else if (type & ETAHistoEq) {
  396.     /*===============================
  397.     %    Histogram Equalization    %
  398.     %    this is direct mapping    %
  399.     %    regular vsc += hist[i]    %
  400.     ===============================*/
  401.     float    h_avg = hsize;
  402.     int    incr;
  403.         if (!cntz)  h_avg -= histp[0];    /* take off 0's conuts */
  404.         h_avg /= (maxout-flr);
  405.         for (i=vsc=0; i<mmm->min; i++)
  406.             vsc += histp[i];    /* very important and tricky */
  407.         for (rel_val=flr, vsc=0, i=!cntz; i < maxdiff; i++) {
  408.             vsc += histp[i+mmm->min];
  409.             incr = vsc/h_avg;
  410.             lkt[i] = rel_val + (incr>>1);
  411.             rel_val += incr;
  412.             vsc -= incr*h_avg;
  413.         }
  414.     }
  415. else{    {
  416.     register double    tmp;
  417.         if (type & ETAQuant)
  418.             vsc = hsize;    /* = ReadSlider(QSlider, 1);    */
  419.         else    vsc = img->curve==ETABackGD ? img->bgrd : img->fgrd;
  420.         vsc = VSC_BASE*vsc/mmm->max + 1;
  421.         if (vsc <= 0.)    vsc = VSC_BASE;
  422.         if (vsc != 1.)    {
  423.             for (i=tmp=maxdiff; i--;)    tmp = tmp*vsc + i;
  424.             scale = (maxout-flr) / tmp;
  425.         }
  426.         else    scale = (maxout-flr) / ((maxdiff-1)*maxdiff >> 1);
  427. #    ifdef    _DEBUG_
  428.         if (verbose)
  429.             message("Scale=%f, C=%f, vsc=%f\n", scale, tmp, vsc);
  430. #    endif
  431.     }
  432.  
  433.     if (!(type & ~ETAQuant))    /* foreground */
  434.         for(i=0, rel_val=flr; i<maxdiff; i++)
  435.         {
  436.         rel_val += i * (scale*=vsc);
  437.         lkt[i] = rel_val;
  438.         }
  439.     else for (i=maxdiff, rel_val=Maxout; i--;)
  440.         {
  441.         lkt[i] = rel_val;
  442.         rel_val -= (maxdiff-i) * (scale*=vsc);
  443.         }
  444.     i = maxdiff - 1;
  445.     if (*lkt < flr)    {
  446. #    ifdef    _DEBUG_
  447.         msg("lkt[0] = %d\n", *lkt);
  448. #    endif
  449.         *lkt = flr;
  450.     }
  451.     else if (*lkt > 255)    {
  452. #    ifdef    _DEBUG_
  453.         msg("lkt[0] = %d\n", *lkt);
  454. #    endif
  455.         *lkt = 255;
  456.     }
  457.     if (lkt[i] > 255)    lkt[i] = 255;
  458.     else if (lkt[i] < 0)    lkt[i] = 0;
  459.     }
  460. if (top)
  461.     for (; lkt[i]>Maxout-top; i--)
  462.     lkt[i] = topv;
  463. if(verbose>1)    dump_tbl(lkt, maxdiff, 8, "lkt");
  464. }
  465.  
  466. /*==============================================*
  467. *    computing the min & max for integer    *
  468. *    & trans float to integer for scaling    *
  469. *==============================================*/
  470. find_min_max(bufp, hist, mmm, r_width, r_height, width)
  471. register byte    *bufp;
  472. register int    *hist;
  473. Mregister    *mmm;
  474. {
  475. register int    i, j=0;
  476.  
  477. for (i=HistoSize; i--;)
  478.     hist[i] = j;
  479. for (i=r_height; i--; bufp+=width)
  480.     for (j=r_width; j--;)
  481.     hist[bufp[j]]++;
  482. for (i=0, j=HistoSize; hist[i]==0 && i<j; i++);
  483. while (hist[--j]==0);
  484. mmm->min = i;
  485. mmm->max = j;
  486. return    mmm->maxcnt = j - i + 1;
  487. }
  488.  
  489. interpolation(in, out, x_regions, y_regions, imp, img, hinf)
  490. byte    *in, *out;
  491. InterpMap    *imp;
  492. Image    *img;
  493. HistoInfo    *hinf;
  494. {
  495. int    i, j, maxdiff, x, y, mx, my,
  496.     rgn_h, rgn_w, xfrac, yfrac, regions, region;
  497. InterpMap    *imu, *imd, *mlu, *mld, *mru, *mrd;
  498. float    xinc, yinc, xfracinc, yfracinc, xrate, yrate,
  499.     xcomp, ycomp;
  500.  
  501. rgn_h = img->height / y_regions;
  502. rgn_w = img->width / x_regions;
  503. xfrac = img->width - rgn_w * x_regions;
  504. yfrac = img->height - rgn_h * y_regions;
  505. regions = x_regions * y_regions;
  506. hinf->histp = hinf->hist;
  507.  
  508. {
  509. register byte    *tmpp=in;
  510. for (i=region=maxdiff=0; i<y_regions; i++, tmpp+=(rgn_h-1)*img->width)
  511.     for (j=0; j<x_regions; j++, region++, tmpp+=rgn_w){
  512.     register int diff=find_min_max(tmpp, hinf->histp, imp+region, rgn_w, rgn_h,
  513.             img->width);
  514.     if (maxdiff < diff)
  515.         maxdiff = diff;
  516.     /* building new histogram table    */
  517.     new_curve(imp[region].lkt, hinf, imp+region, img->curve, 0, img,
  518.         rgn_w * rgn_h);
  519.     }
  520. }
  521. for (i=regions; i--;)
  522.     if (imp[i].diff < maxdiff)    {
  523. #ifdef    _DEBUG_
  524.     message("lkt%d = %d\n", i, imp[i].diff);
  525. #endif
  526.     for (j=imp[i].diff; j<maxdiff; j++)
  527.         imp[i].lkt[j] = imp[i].lkt[j-1];
  528.     }
  529.  
  530. /* generate new histogram    */
  531. xinc = 1. / rgn_w;
  532. yinc = 1. / rgn_h;
  533. xfracinc = 1. / xfrac;
  534. yfracinc = 1. / yfrac;
  535. mx = x_regions;
  536. for (i=0; i<y_regions; i++)    {
  537.     yrate = 1.;
  538.     my = i * mx;
  539.     if (i+1==y_regions)
  540.     mx = -mx;
  541.     imu = imp + my;
  542.     imd = imu + mx;
  543.     for (y=0; y<rgn_h; y++, yrate-=yinc){
  544.     ycomp = 1. - yrate;
  545.     for (j=0; j<x_regions; j++){
  546.         xrate = 1.;
  547.         mlu = imu + j;
  548.         mld = imd + j;
  549.         if (j+1==x_regions)    {
  550.         mru = mlu - 1;
  551.         mrd = mld - 1;
  552.         }
  553.         else{
  554.         mru = mlu + 1;
  555.         mrd = mld + 1;
  556.         }
  557.         for (x=0; x<rgn_w; x++, xrate-=xinc){
  558.         register int    A, B, C, D, where = *in++;
  559.         A = where - mlu->min;
  560.         B = where - mld->min;
  561.         C = where - mru->min;
  562.         D = where - mrd->min;
  563.         if (A < 0)    A = 0;
  564.         if (B < 0)    B = 0;
  565.         if (C < 0)    C = 0;
  566.         if (D < 0)    D = 0;
  567.         xcomp = 1. - xrate;
  568.         *out++ = xrate * (mlu->lkt[A] * yrate + mld->lkt[B] * ycomp) +
  569.             xcomp * (mru->lkt[C] * yrate + mrd->lkt[D] * ycomp);
  570.         }
  571.     }
  572.     if (xfrac){
  573.         xrate = 1.;
  574.         mlu = mru = imu + j-1;
  575.         mld = mrd = imd + j-1;
  576.         for (x=0; x<xfrac; x++, xrate-=xfracinc){
  577.         register int    where = *in++;
  578.         xcomp = 1. - xrate;
  579.         *out++ = xrate * (mlu->lkt[where - mlu->min] * yrate +
  580.                 mld->lkt[where - mld->min] * ycomp) +
  581.             xcomp * (mru->lkt[where - mru->min] * yrate +
  582.                 mrd->lkt[where - mrd->min] * ycomp);
  583.         }
  584.     }
  585.     }
  586. }
  587. if (yfrac)
  588.     for (j=img->width*yfrac; i--;)
  589.         *out++ = *in++;
  590. hinf->histp = img->hist;
  591. }
  592.