diff options
Diffstat (limited to 'ccast/dpat.c')
-rw-r--r-- | ccast/dpat.c | 952 |
1 files changed, 952 insertions, 0 deletions
diff --git a/ccast/dpat.c b/ccast/dpat.c new file mode 100644 index 0000000..4962ae1 --- /dev/null +++ b/ccast/dpat.c @@ -0,0 +1,952 @@ + +/* + * Argyll Color Correction System + * ChromCast dither pattern code + * + * Author: Graeme W. Gill + * Date: 11/12/2014 + * + * Copyright 2014 Graeme W. Gill + * All rights reserved. + * + * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- + * see the License2.txt file for licencing details. + * + */ + +/* + * Locates minimal list of surrounders + * Find initial weight for them using minimizer + Itterates over + * Locate cell changes that match desired correction + with increasing randomness of choosing a poor match + * Reset to starting pattern when accumulated error over + best current is exceeded. + + + Problem is this is unreliable is locating good matches + for some cases. + + Problem is that it doesn't seem to work - ChromeCast doesn't + decode the way we model it :-( + + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <sys/types.h> +#include <time.h> +#include "copyright.h" +#include "aconfig.h" +#include "counters.h" +#ifndef SALONEINSTLIB +#include "numlib.h" +#else +#include "numsup.h" +#endif +#include "conv.h" +#include "base64.h" +#include "yajl.h" +#include "ccmdns.h" +#include "ccpacket.h" +#include "ccmes.h" +#include "ccast.h" + +#ifdef STANDALONE_TEST +# define DIAGNOSTICS +#endif + +#undef TEST_POINT + +/* Even/Odd filter filter index ranges (inclusive) and total size */ +#define EV_NEG -4 +#define EV_POS 4 +#define EV_WIDTH (-(EV_NEG) + 1 + EV_POS) +#define OD_NEG -4 +#define OD_POS 3 +#define OD_WIDTH (-(OD_NEG) + 1 + OD_POS) + +/* Weightings [horiz/vert] */ +double filt_v_ev[2][EV_WIDTH] = { +{ -0.003467, -0.048341, 0.028688, 0.418873, 0.704674, 0.427551, 0.032480, -0.050146, -0.003793 }, +{ -0.013477, 0.000081, -0.087119, 0.357627, 1.000252, 0.378473, -0.083496, -0.000155, -0.009850 } +}; + +/* Weightings [horiz/vert] */ +double filt_v_od[2][OD_WIDTH] = { +{ -0.026810, -0.045190, 0.186825, 0.614579, 0.623721, 0.206987, -0.040217, -0.026419 }, +{ 0.008396, -0.078987, -0.013733, 0.796594, 0.813578, 0.013555, -0.086466, 0.004781 } +}; + + +/* [horiz/vert][phase] */ +double *filt[2][2] = { { &filt_v_ev[0][-(EV_NEG)], &filt_v_od[0][-(OD_NEG)] }, + { &filt_v_ev[1][-(EV_NEG)], &filt_v_od[1][-(OD_NEG)] } }; + +/* [phase] */ +int fneg[2] = { EV_NEG, OD_NEG }; +int fpos[2] = { EV_POS, OD_POS }; + +/* Dither input size */ +#ifdef TEST_POINT +# define DISIZE 8 +#else +# define DISIZE CCDITHSIZE +#endif +#define DOSIZE ((DISIZE * 3)/2) + +#ifdef DIAGNOSTICS +int vv = 0; +#endif + +/* Upsample ipat to opat */ +/* And return the average RGB value */ +static void upsample(double ret[3], double iipat[DISIZE][DISIZE][3]) { + double ipat[DISIZE][DISIZE][3]; + double tpat[DOSIZE][DISIZE][3]; /* Intermediate pattern - horizontal up-sampled */ + double opat[DOSIZE][DOSIZE][3]; /* Output pattern */ + int x, y; + int i, j; + +//printf("~1 doing conversion\n"); + /* Convert from RGB to YCbCr */ + for (x = 0; x < DISIZE; x++) { + for (y = 0; y < DISIZE; y++) { + ccast2YCbCr(NULL, ipat[x][y], iipat[x][y]); +// ipat[x][y][0] = iipat[x][y][0]; +// ipat[x][y][1] = iipat[x][y][1]; +// ipat[x][y][2] = iipat[x][y][2]; +//printf("[%d][%d] %f %f %f -> %f %f %f\n",x,y, iipat[x][y][0], iipat[x][y][1], iipat[x][y][2], ipat[x][y][0], ipat[x][y][1], ipat[x][y][2]); + } + } + +//printf("~1 doing horiz\n"); + /* Up-sample in horizontal direction */ + for (y = 0; y < DISIZE; y++) { + + /* Zero the intermediate pattern */ + for (i = 0; i < DOSIZE; i++) { + tpat[i][y][0] = 0.0; + tpat[i][y][1] = 0.0; + tpat[i][y][2] = 0.0; + } + + /* Distribute the input according to the filter */ + for (x = 0; x < DISIZE; x++) { + int ph, ii, k; + + ph = x & 1; + ii = (int)floor(x * 1.5 + 0.5); + + /* For all the filter cooeficients */ + for (k = fneg[ph]; k <= fpos[ph]; k++) { + i = (ii + k); + while (i < 0) + i += DOSIZE; + while (i >= DOSIZE) + i -= DOSIZE; + tpat[i][y][0] += filt[0][ph][k] * ipat[x][y][0]; + tpat[i][y][1] += filt[0][ph][k] * ipat[x][y][1]; + tpat[i][y][2] += filt[0][ph][k] * ipat[x][y][2]; + } + } + } + +//printf("~1 doing vert\n"); + /* Up-sample in vertical direction */ + for (i = 0; i < DOSIZE; i++) { + + /* Zero the output pattern */ + for (j = 0; j < DOSIZE; j++) { + opat[i][j][0] = 0.0; + opat[i][j][1] = 0.0; + opat[i][j][2] = 0.0; + } + + /* Distribute the input according to the filter */ + for (y = 0; y < DISIZE; y++) { + int ph, jj, k; + + ph = y & 1; + jj = (int)floor(y * 1.5 + 0.5); + + /* For all the filter cooeficients */ + for (k = fneg[ph]; k <= fpos[ph]; k++) { + j = (jj + k); + while (j < 0) + j += DOSIZE; + while (j >= DOSIZE) + j -= DOSIZE; + opat[i][j][0] += filt[1][ph][k] * tpat[i][y][0]; + opat[i][j][1] += filt[1][ph][k] * tpat[i][y][1]; + opat[i][j][2] += filt[1][ph][k] * tpat[i][y][2]; + } + } + } +//printf("~1 doing conversion\n"); + + /* Convert from YCbCr to RGB */ + for (i = 0; i < DOSIZE; i++) { + for (j = 0; j < DOSIZE; j++) { + YCbCr2ccast(NULL, opat[i][j], opat[i][j]); + } + } +//printf("~1 done\n"); + + if (ret != NULL) { + ret[0] = ret[1] = ret[2] = 0.0; + for (j = 0; j < DOSIZE; j++) { + for (i = 0; i < DOSIZE; i++) { + ret[0] += opat[i][j][0]; + ret[1] += opat[i][j][1]; + ret[2] += opat[i][j][2]; + } + } + ret[0] /= (double)(DOSIZE * DOSIZE); + ret[1] /= (double)(DOSIZE * DOSIZE); + ret[2] /= (double)(DOSIZE * DOSIZE); + } + +#ifdef DIAGNOSTICS + if (vv) { + printf("Result\n"); + for (j = 0; j < DOSIZE; j++) { + for (i = 0; i < DOSIZE; i++) { + if (i > 0) + printf(", "); + printf("% 5.1f % 5.1f % 5.1f",opat[i][j][0],opat[i][j][1], opat[i][j][2]); + } + printf("\n"); + } + } +#endif +} + +/* ------------------------------------------------------------- */ + +/* Given a quantized RGB target, return a quantized RGB that either exactly */ +/* maps to it through YCbCr conversion, or is the closest in the */ +/* direction away from the target value, or the closest clipped value */ +static void quant_rgb(int n, double out[3], double rgb[3]) { + double ycc[3], base[3]; + double tmp[3], chval[3]; + double dist, bdist = 1e6; + double brgb[3], borgb[3]; + int ix, k; + +//printf("Quant RGB %f %f %f n %d\n", rgb[0], rgb[1], rgb[2], n); + + /* Search current rgb and surround in the same direction */ + /* it is from the target value, for a quantized rgb */ + /* that is in that direction */ + for (k = 0; k < 3; k++) + base[k] = rgb[k]; + + for (ix = 0; ix < 8; ix++) { + double dist; + + /* Comp trial RGB */ + for (k = 0; k < 3; k++) { + tmp[k] = base[k]; + if (ix & (1 << k)) { + if (n & (1 << k)) /* Move in direction base point is in */ + tmp[k] += 1.0; + else + tmp[k] -= 1.0; + if (tmp[k] < 0.0 || tmp[k] > 255.0) + break; + } + } + if (k < 3) /* Trial is out of gamut */ + continue; + + /* Quantize it */ + ccast2YCbCr(NULL, ycc, tmp); + YCbCr2ccast(NULL, chval, ycc); +//printf("Trial RGB %f %f %f\n", tmp[0], tmp[1], tmp[2]); +//printf(" result %f %f %f\n", chval[0], chval[1], chval[2]); + + /* It's OK if it is eual or greater in the desired */ + /* direction than the input rgb. */ + /* Best would be closest to input. */ + /* Least worst would be what ? */ + + dist = 0.0; + for (k = 0; k < 3; k++) { + double tt; + if (n & (1 << k)) { + tt = chval[k] - base[k]; + } else { + tt = base[k] - chval[k]; + } + if (tt >= 0.0) + dist += 0.1 * tt; + else + dist += 2.0 * -tt; + } +//printf(" dist %f\n", dist); + + /* Pick it if it is at least in the right direction */ + if (dist < bdist) { + for (k = 0; k < 3; k++) { + rgb[k] = tmp[k]; + out[k] = chval[k]; + } + bdist = dist; + } + } + +#ifdef NEVER + if (bdist > 0.0 + && rgb[0] != 0.0 && rgb[0] != 1.0 && rgb[0] != 254.0 && rgb[0] != 255.0 + && rgb[1] != 0.0 && rgb[1] != 1.0 && rgb[1] != 254.0 && rgb[1] != 255.0 + && rgb[2] != 0.0 && rgb[2] != 1.0 && rgb[2] != 254.0 && rgb[2] != 255.0) { + printf("quant_rgb failed with bdist %f\n",bdist); + printf(" rgb in %f %f %f\n",base[0],base[1],base[2]); + printf(" returning rgb %f %f %f\n",rgb[0],rgb[1],rgb[2]); + printf(" resrgb %f %f %f\n",out[0],out[1],out[2]); + } +#endif /* NEVER */ +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - */ + +typedef struct optcntx { + int di; + double *val; /* Target */ + double (*ressur)[8][3]; /* resulting RGB surrounding values */ +} optcntx; + +static double optfunc(void *fdata, double tp[]) { + optcntx *cntx = (optcntx *)fdata; + int i, k; + double iw, tmp[3]; + double err = 0.0; + + /* Compute interpolated result */ + for (k = 0; k < 3; k++) + tmp[k] = 0.0; + + iw = 1.0; + for (i = 0; i < cntx->di; i++) { + if (tp[i] < 0.0) + err += 1000.0 * tp[i] * tp[i]; + else if (tp[i] > 1.0) + err += 1000.0 * (tp[i] - 1.0) * (tp[i] - 1.0); + + for (k = 0; k < 3; k++) + tmp[k] += tp[i] * (*cntx->ressur)[i][k]; + iw -= tp[i]; + } + for (k = 0; k < 3; k++) + tmp[k] += iw * (*cntx->ressur)[i][k]; + + /* Compute error */ + for (k = 0; k < 3; k++) { + double tt = tmp[k] - cntx->val[k]; + err += tt * tt; + } +//printf("Returning %f from %f %f\n",err,tp[0],tp[1]); + return err; +} + +/* Compute pattern */ +/* return the delta to the target */ +double get_ccast_dith(double ipat[DISIZE][DISIZE][3], double val[3]) { + double itpat[DISIZE][DISIZE][3], tpat[DISIZE][DISIZE][3]; + double irtpat[DISIZE][DISIZE][3], rtpat[DISIZE][DISIZE][3]; /* resulting for tpat */ + double berr = 0.0; + int n, k; + int x, y; + int i, j; + int ii; + struct { + int x, y; + } order[16] = { +// Dispersed: + { 3, 1 },{ 1, 3 },{ 1, 1 },{ 3, 0 },{ 3, 3 },{ 1, 2 },{ 3, 2 },{ 2, 0 }, + { 1, 0 },{ 0, 3 },{ 0, 1 },{ 2, 1 },{ 2, 2 },{ 0, 0 },{ 0, 2 },{ 2, 3 } +// Clustered: +// { 0, 0 },{ 0, 1 },{ 1, 1 },{ 1, 0 },{ 2, 0 },{ 3, 0 },{ 3, 1 },{ 2, 1 }, +// { 2, 2 },{ 3, 2 },{ 3, 3 },{ 2, 3 },{ 1, 3 },{ 1, 2 },{ 0, 2 },{ 0, 3 } + }; + int cix = 0; + int nsur = 8, ncomb = 4; + double sur[8][3]; /* RGB surrounding values to use */ + double ressur[8][3]; /* resulting RGB surrounding values */ + int bcc[8]; /* Best combination */ + double bw[8]; /* Best weight */ + int biw[8]; /* Best integer weight/16 */ + double dval[3]; /* Dithered value */ + double err[3], werr; + double errxs; + /* Tuning params */ + int nitters = 300; /* No itters */ + int rand_count = 150; + double rand_start = 4.5; /* Ramp with itters */ + double rand_end = 0.2; + double rand_pow = 1.5; + double mxerrxs = 2.5; /* accumulated error reset threshold */ + unsigned int randv = 0x1234; + + /* 32 bit pseudo random sequencer based on XOR feedback */ + /* generates number between 1 and 4294967295 */ +#define PSRAND32(S) (((S) & 0x80000000) ? (((S) << 1) ^ 0xa398655d) : ((S) << 1)) + + /* Locate the 8 surrounding RGB verticies */ + for (n = 0; n < 8; n++) { + for (k = 0; k < 3; k++) { + if (n & (1 << k)) + sur[n][k] = ceil(val[k]); + else + sur[n][k] = floor(val[k]); + } + +//printf("Input sur %d: %f %f %f\n",n,sur[n][0], sur[n][1], sur[n][2], sur[n][3]); + /* Figure out what RGB values to use to surround the point, */ + /* and what actual RGB values to expect from using them. */ + quant_rgb(n, ressur[n], sur[n]); +//printf("Quant sur %d: %f %f %f\n",n,sur[n][0], sur[n][1], sur[n][2], sur[n][3]); +//printf(" ressur %d: %f %f %f\n",n,ressur[n][0], ressur[n][1], ressur[n][2], ressur[n][3]); +// printf("\n"); + } + + /* Reduce this to unique surrounders */ + for (nsur = 0, i = 0; i < 8; i++) { + + /* Check if the i'th entry is already in the list */ + for (j = 0; j < nsur; j++) { + for (k = 0; k < 3; k++) { + if (ressur[i][k] != ressur[j][k]) + break; + } + if (k < 3) + continue; /* Unique */ + break; /* Duplicate */ + } + if (j < nsur) /* Duplicate */ + continue; + + /* Copy i'th to nsur */ + for (k = 0; k < 3; k++) { + sur[nsur][k] = sur[i][k]; + ressur[nsur][k] = ressur[i][k]; + } + nsur++; + } + +#ifdef DIAGNOSTICS + if (vv) { + printf("There are %d unique surrounders:\n",nsur); + for (n = 0; n < nsur; n++) { + printf("sur %f %f %f\n",ressur[n][0], ressur[n][1], ressur[n][2], ressur[n][3]); + } + } +#endif + + /* Use an optimzer to set the initial values using all the unique */ + /* surrounders. */ + { + double s[8]; + optcntx cntx; + + ncomb = nsur; + for (n = 0; n < nsur; n++) { + bcc[n] = n; + bw[n] = 1.0/nsur; + s[n] = 0.1; + } + + cntx.di = nsur-1; + cntx.val = val; + cntx.ressur = &ressur; + + powell(NULL, cntx.di, bw, s, 1e-4, 1000, optfunc, &cntx, NULL, NULL); + + /* Compute baricentric values */ + bw[nsur-1] = 0.0; + for (n = 0; n < (nsur-1); n++) { + if (bw[n] < 0.0) + bw[n] = 0.0; + else if (bw[n] > 1.0) + bw[n] = 1.0; + bw[nsur-1] += bw[n]; + } + if (bw[nsur-1] > 1.0) { /* They summed to over 1.0 */ + for (n = 0; n < (nsur-1); n++) + bw[n] *= 1.0/bw[nsur-1]; /* Scale them down */ + bw[nsur-1] = 1.0; + } + bw[nsur-1] = 1.0 - bw[nsur-1]; /* Remainder */ + } + + /* Check the result */ +#ifdef DIAGNOSTICS + if (vv) { + double tmp[3], err; + + /* Compute interpolated result */ + for (k = 0; k < 3; k++) + tmp[k] = 0.0; + for (n = 0; n < ncomb; n++) { + for (k = 0; k < 3; k++) + tmp[k] += bw[n] * ressur[bcc[n]][k]; + } + /* Compute error */ + err = 0.0; + for (k = 0; k < 3; k++) { + tmp[k] -= val[k]; + err += tmp[k] * tmp[k]; + } + err = sqrt(err); + for (n = 0; n < ncomb; n++) + printf("Comb %d weight %f rgb %f %f %f\n",bcc[n],bw[n],ressur[bcc[n]][0],ressur[bcc[n]][1],ressur[bcc[n]][2]); + printf("Error %f %f %f rms %f\n",tmp[0], tmp[1], tmp[2], err); + printf("\n"); + } +#endif + + /* Compute the number of pixels for each surounder value */ + { + int sw[8], rem; + + /* Sort the weightings from smallest to largest */ + for (n = 0; n < 8; n++) + sw[n] = n; + + for (i = 0; i < (ncomb-1); i++) { + for (j = i+1; j < ncomb; j++) { + if (bw[sw[j]] < bw[sw[i]]) { + int tt = sw[i]; /* Swap them */ + sw[i] = sw[j]; + sw[j] = tt; + } + } + } + + /* Compute the nearest integer weighting out of 16 */ + rem = 16; + for (i = 0; i < (ncomb-1) && rem > 0; i++) { + n = sw[i]; + biw[n] = (int)(16.0 * bw[n] + 0.5); + rem -= biw[n]; + if (rem <= 0) + rem = 0; + } + for (; i < ncomb; i++) { + n = sw[i]; + biw[n] = rem; + } +#ifdef DIAGNOSTICS + if (vv) { + for (n = 0; n < ncomb; n++) + printf("Comb %d iweight %i rgb %f %f %f\n",bcc[n],biw[n],ressur[bcc[n]][0],ressur[bcc[n]][1],ressur[bcc[n]][2]); + } +#endif + } + + /* Set the initial pattern according to the integer weighting */ + for (cix = 0, n = 0; n < ncomb; n++) { + for (i = 0; i < biw[n]; i++) { + x = order[cix].x; + y = order[cix].y; + cix++; + for (k = 0; k < 3; k++) { + tpat[x][y][k] = itpat[x][y][k] = sur[bcc[n]][k]; + rtpat[x][y][k] = irtpat[x][y][k] = ressur[bcc[n]][k]; + } + } + } + +#ifdef DIAGNOSTICS + /* Check initial pattern error */ + if (vv) { + printf("Input pat:\n"); + for (x = 0; x < DISIZE; x++) { + for (y = 0; y < DISIZE; y++) { + if (y > 0) + printf(", "); + printf("%3.0f %3.0f %3.0f",rtpat[x][y][0], rtpat[x][y][1], rtpat[x][y][2]); + } + printf("\n"); + } + } +#endif + + upsample(dval, rtpat); + + werr = 0.0; + for (k = 0; k < 3; k++) { + err[k] = dval[k] - val[k]; + if (fabs(err[k]) > werr) + werr = fabs(err[k]); + } + +#ifdef DIAGNOSTICS + if (vv) { + printf("Target %f %f %f -> %f %f %f\n", val[0], val[1], val[2], dval[0], dval[1], dval[2]); + printf("Error %f %f %f werr %f\n", err[0], err[1], err[2], werr); + } +#endif + + berr = werr; + for (x = 0; x < DISIZE; x++) { + for (y = 0; y < DISIZE; y++) { + for (k = 0; k < 3; k++) + ipat[x][y][k] = tpat[x][y][k]; + } + } + + /* Improve fit if needed */ + /* This is a bit stocastic */ + errxs = 0.0; + for (ii = 0; ii < nitters; ii++) { /* Until we give up */ + double corr[3]; /* Correction direction needed */ + double bdot; + int bx, by; + + double wycc, mm; + double cell[3]; /* Cell being modified value */ + double ccell[3]; /* Corrected cell */ + double pcell[3]; /* Proposed new cell value */ + + for (k = 0; k < 3; k++) + corr[k] = val[k] - dval[k]; +#ifdef DIAGNOSTICS + if (vv) + printf("corr needed %f %f %f\n", corr[0], corr[1], corr[2]); +#endif + + /* Scale it and limit it */ + for (k = 0; k < 3; k++) { + double dd = 16.0 * corr[k]; + if (dd >= 1.0) + dd = 1.0; + else if (dd <= -1.0) + dd = -1.0; + else + dd = 0.0; + corr[k] = dd; + } + + if (corr[0] == 0.0 && corr[1] == 0 && corr[2] == 0.0) { +#ifdef DIAGNOSTICS + if (vv) + printf("No correction possible - done\n"); +#endif + break; + } + +#ifdef DIAGNOSTICS + if (vv) + printf("scaled corr %f %f %f\n", corr[0], corr[1], corr[2]); +#endif + + /* Search dither cell and surrounder for a combination */ + /* that is closest to the change we want to make. */ + bdot = 1e6; + bx = by = n = 0; + for (x = 0; x < DISIZE; x++) { + double rlevel = rand_start + (rand_end - rand_start) + * pow((ii % rand_count)/rand_count, rand_pow); + + for (y = 0; y < DISIZE; y++) { + for (i = 0; i < ncomb; i++) { + double dot = 0.0; + for (k = 0; k < 3; k++) + dot += (ressur[bcc[i]][k] - rtpat[x][y][k]) * corr[k]; + + /* Ramp the randomness up */ +// dot += d_rand(0.0, 0.1 + (2.5-0.1) * ii/nitters); +// dot += d_rand(-rlevel, rlevel); + /* use a deterministic random element, so that */ + /* the dither patterns are repeatable. */ + randv = PSRAND32(randv); + dot += rlevel * 2.0 * ((randv - 1)/4294967294.0 - 0.5); + + if (dot <= 0.0) + dot = 1e7; + else { + dot = (dot - 1.0) * (dot - 1.0); + } +//printf("dot %f from sur %f %f %f to pat %f %f %f\n", dot, ressur[bcc[i]][0], ressur[bcc[i]][1], ressur[bcc[i]][2], rtpat[x][y][0], rtpat[x][y][1], rtpat[x][y][2]); + + if (dot < bdot) { + bdot = dot; + bx = x; + by = y; + n = i; + } + } + } + } + +#ifdef DIAGNOSTICS + if (vv) { + printf("Changing cell [%d][%d] %f %f %f with dot %f\n",bx,by,rtpat[bx][by][0],rtpat[bx][by][1],rtpat[bx][by][2],bdot); + printf(" to sur %d: %f %f %f\n",n, ressur[bcc[n]][0], ressur[bcc[n]][1], ressur[bcc[n]][2]); + } +#endif + + /* Substitute the best correction for this cell */ + for (k = 0; k < 3; k++) { + tpat[bx][by][k] = sur[bcc[n]][k]; + rtpat[bx][by][k] = ressur[bcc[n]][k]; + } + +#ifdef DIAGNOSTICS + if (vv) { + printf("Input pat:\n"); + for (x = 0; x < DISIZE; x++) { + for (y = 0; y < DISIZE; y++) { + if (y > 0) + printf(", "); + printf("%3.0f %3.0f %3.0f",rtpat[x][y][0], rtpat[x][y][1], rtpat[x][y][2]); + } + printf("\n"); + } + } +#endif + + upsample(dval, rtpat); + + werr = 0.0; + for (k = 0; k < 3; k++) { + err[k] = dval[k] - val[k]; + if (fabs(err[k]) > werr) + werr = fabs(err[k]); + } + + if (werr > berr) { + errxs += werr - berr; + } + + /* New best */ + if (werr < berr) { + berr = werr; + errxs = 0.0; + for (x = 0; x < DISIZE; x++) { + for (y = 0; y < DISIZE; y++) { + for (k = 0; k < 3; k++) { + ipat[x][y][k] = tpat[x][y][k]; + + itpat[x][y][k] = tpat[x][y][k]; + irtpat[x][y][k] = rtpat[x][y][k]; + } + } + } + } + +#ifdef DIAGNOSTICS + if (vv) { + printf("Target %f %f %f -> %f %f %f\n", val[0], val[1], val[2], dval[0], dval[1], dval[2]); + printf("Error %f %f %f werr %f\n", err[0], err[1], err[2], werr); + } +#endif + + if (berr < 0.11) { +#ifdef DIAGNOSTICS + if (vv) + printf("best error %f < 0.11 - give up\n",berr); +#endif + break; + } + + /* If we're not making progress, reset to the last best */ + if (errxs > mxerrxs) { +#ifdef DIAGNOSTICS + if (vv) + printf("Restarting at ii %d \n",ii); +#endif + errxs = 0.0; + for (x = 0; x < DISIZE; x++) { + for (y = 0; y < DISIZE; y++) { + for (k = 0; k < 3; k++) { + tpat[x][y][k] = itpat[x][y][k]; + rtpat[x][y][k] = irtpat[x][y][k]; + } + } + } + } + } + +#ifdef DIAGNOSTICS + if (vv) { + printf("Returning best error %f pat:\n",berr); + for (y = 0; y < DISIZE; y++) { + for (x = 0; x < DISIZE; x++) { + if (x > 0) + printf(", "); + printf("%3.0f %3.0f %3.0f",ipat[x][y][0], ipat[x][y][1], ipat[x][y][2]); + } + printf("\n"); + } + } +#endif + + return berr; +} + +/* ====================================================================================== */ + +#ifdef STANDALONE_TEST + +int +main(int argc, + char *argv[] +) { + double val[3], out[3], err; + double ipat[DISIZE][DISIZE][3]; + double aerr, acount, xerr; + int x, y; + int i, j; + int k, nn; + + printf("Hi there\n"); + + rand32(time(NULL)); + +#ifdef TEST_POINT + for (x = 0; x < DISIZE; x++) { + for (y = 0; y < DISIZE; y++) { + ipat[x][y][0] = 0.0; + ipat[x][y][1] = 0.0; + ipat[x][y][2] = 0.0; + } + } + + ipat[5][4][0] = 255.0; + ipat[5][4][1] = 255.0; + ipat[5][4][2] = 255.0; + + upsample(NULL, ipat); + +#else + +#ifdef NEVER + +// val[0] = 201.500000; +// val[1] = 115.533403; +// val[2] = 76.300000; + +// val[0] = 255.000000; +// val[1] = 115.533403; +// val[2] = 255.000000; + +// val[0] = 221.689875; +// val[1] = 29.593255; +// val[2] = 140.820878; + +// val[0] = 212.377797; +// val[1] = 228.338903; +// val[2] = 70.153296; + +// val[0] = 231.554511; +// val[1] = 0.000000; +// val[2] = 51.958048; + +// val[0] = 255.000000; +// val[1] = 144.768052; +// val[2] = 179.737212; + +// val[0] = 194.854956; +// val[1] = 41.901887; +// val[2] = 20.434793; + +// val[0] = 250.100121; +// val[1] = 83.484217; +// val[2] = 42.867603; + +// val[0] = 255.000000; +// val[1] = 255.000000; +// val[2] = 228.534759; + + // 1.71 -> 1.58, rand 2.2 +// val[0] = 255.000000; +// val[1] = 176.894769; +// val[2] = 8.932806; + + // 1.54 -> 0.762592, rand 0.3 +// val[0] = 216.873703; +// val[1] = 250.908094; + + // 1.05 +// val[0] = 167.284458; +// val[1] = 248.945210; +// val[2] = 199.023452; + + // 1.07 +// val[0] = 211.045184; +// val[1] = 27.825141; +// val[2] = 63.883148; + + // 1.928 +// val[0] = 255.000000; +// val[1] = 0.439284; +// val[2] = 210.928135; + + // 1.278 +// val[0] = 218.693614; +// val[1] = 222.890101; +// val[2] = 174.779727; + + // 1.334501 +// val[0] = 253.931573; +// val[1] = 230.278945; +// val[2] = 185.677389; + +// printf("In RGB %f %f %f\n",val[0],val[1],val[2]); +// ccast2YCbCr(NULL, out, val); +// printf("YCbCr %f %f %f\n",out[0],out[1],out[2]); +// YCbCr2ccast(NULL, out, out); +// printf("RGB %f %f %f\n",out[0],out[1],out[2]); + + + vv = 1; + err = get_ccast_dith(ipat, val); + + printf("Got pat with err %f\n",err); + +#else + aerr = 0.0; + acount = 0.0; + xerr = 0.0; + for (nn = 0; nn < 200000; nn++) { + + for (k = 0; k < 3; k++) { + val[k] = d_rand(-5.0, 255.0 + 5.0); + if (val[k] < 0.0) + val[k] = 0.0; + else if (val[k] > 255.0) + val[k] = 255.0; + } + + err = get_ccast_dith(ipat, val); + + if (err >= 1.5 || + ( err >= 1.0 + && val[0] != 0.0 && val[0] != 255.0 + && val[1] != 0.0 && val[1] != 255.0 + && val[2] != 0.0 && val[2] != 255.0)) { + printf("Target RGB %f %f %f, err %f\n", val[0], val[1], val[2],err); +// vv = 1; +// comput_pat(ipat, val); +// break; + } + + aerr += err; + acount++; + if (err > xerr) + xerr = err; + } + + aerr /= acount; + printf("After %d trials, aerr = %f, maxerr = %f\n",nn,aerr,xerr); +#endif +#endif + + return 0; +} + +#endif /* STANDALONE_TEST */ |