📄 hot.c
字号:
/* * hot.c - Scan an image for pixels with RGB values that will give * "unsafe" values of chrominance signal or composite signal * amplitude when encoded into an NTSC or PAL colour signal. * (This happens for certain high-intensity high-saturation colours * that are rare in real scenes, but can easily be present * in synthetic images.) * * Such pixels can be flagged so the user may then choose other * colours. Or, the offending pixels can be made "safe" * in a manner that preserves hue. * * There are two reasonable ways to make a pixel "safe": * We can reduce its intensity (luminance) while leaving * hue and saturation the same. Or, we can reduce saturation * while leaving hue and luminance the same. A #define selects * which strategy to use. * * Note to the user: You must add your own read_pixel() and write_pixel() * routines. You may have to modify pix_decode() and pix_encode(). * MAXPIX, WID, and HGT are likely to need modification. *//* * Originally written as "ikNTSC.c" by Alan Wm Paeth, * University of Waterloo, August, 1985 * Updated by Dave Martindale, Imax Systems Corp., December 1990 *//* * Compile-time options. * * Define either NTSC or PAL as 1 to select the colour system. * Define the other one as zero, or leave it undefined. * * Define FLAG_HOT as 1 if you want "hot" pixels set to black * to identify them. Otherwise they will be made safe. * * Define REDUCE_SAT as 1 if you want hot pixels to be repaired by * reducing their saturation. By default, luminance is reduced. * * CHROMA_LIM is the limit (in IRE units) of the overall * chrominance amplitude; it should be 50 or perhaps * very slightly higher. * * COMPOS_LIM is the maximum amplitude (in IRE units) allowed for * the composite signal. A value of 100 is the maximum * monochrome white, and is always safe. 120 is the absolute * limit for NTSC broadcasting, since the transmitter's carrier * goes to zero with 120 IRE input signal. Generally, 110 * is a good compromise - it allows somewhat brighter colours * than 100, while staying safely away from the hard limit. */#define NTSC 1#define PAL 0#define FLAG_HOT 0#define REDUCE_SAT 0#define CHROMA_LIM 50.0 /* chroma amplitude limit */#define COMPOS_LIM 110.0 /* max IRE amplitude */#if NTSC/* * RGB to YIQ encoding matrix. */double code_matrix[3][3] = { 0.2989, 0.5866, 0.1144, 0.5959, -0.2741, -0.3218, 0.2113, -0.5227, 0.3113,};#define PEDESTAL 7.5 /* 7.5 IRE black pedestal */#define GAMMA 2.2#endif /* NTSC */#if PAL/* * RGB to YUV encoding matrix. */double code_matrix[3][3] = { 0.2989, 0.5866, 0.1144, -0.1473, -0.2891, 0.4364, 0.6149, -0.5145, -0.1004,};#define PEDESTAL 0.0 /* no pedestal in PAL */#define GAMMA 2.8#endif /* PAL */#define SCALE 8192 /* scale factor: do floats with int math */#define MAXPIX 255 /* white value */#define WID 1024 /* FB dimensions */#define HGT 768typedef struct { unsigned char r, g, b;} Pixel;int tab[3][3][MAXPIX+1]; /* multiply lookup table */double chroma_lim; /* chroma limit */double compos_lim; /* composite amplitude limit */long ichroma_lim2; /* chroma limit squared (scaled integer) */int icompos_lim; /* composite amplitude limit (scaled integer) */double pix_decode(), gc(), inv_gc();int pix_encode(), hot();main(){ Pixel p; int row, col; build_tab(); for (col=0; col<WID; col++) { for(row=0; row<HGT; row++) { read_pixel(row, col, &p); if (hot(&p)) { write_pixel(row, col, &p); } } }}/* * build_tab: Build multiply lookup table. * * For each possible pixel value, decode value into floating-point * intensity. Then do gamma correction required by the video * standard. Scale the result by our fixed-point scale factor. * Then calculate 9 lookup table entries for this pixel value. * * We also calculate floating-point and scaled integer versions * of our limits here. This prevents evaluating expressions every pixel * when the compiler is too stupid to evaluate constant-valued * floating-point expressions at compile time. * * For convenience, the limits are #defined using IRE units. * We must convert them here into the units in which YIQ * are measured. The conversion from IRE to internal units * depends on the pedestal level in use, since as Y goes from * 0 to 1, the signal goes from the pedestal level to 100 IRE. * Chroma is always scaled to remain consistent with Y. */build_tab(){ register double f; register int pv; for (pv = 0; pv <= MAXPIX; pv++) { f = SCALE * gc(pix_decode(pv)); tab[0][0][pv] = (int)(f * code_matrix[0][0] + 0.5); tab[0][1][pv] = (int)(f * code_matrix[0][1] + 0.5); tab[0][2][pv] = (int)(f * code_matrix[0][2] + 0.5); tab[1][0][pv] = (int)(f * code_matrix[1][0] + 0.5); tab[1][1][pv] = (int)(f * code_matrix[1][1] + 0.5); tab[1][2][pv] = (int)(f * code_matrix[1][2] + 0.5); tab[2][0][pv] = (int)(f * code_matrix[2][0] + 0.5); tab[2][1][pv] = (int)(f * code_matrix[2][1] + 0.5); tab[2][2][pv] = (int)(f * code_matrix[2][2] + 0.5); } chroma_lim = (double)CHROMA_LIM / (100.0 - PEDESTAL); compos_lim = ((double)COMPOS_LIM - PEDESTAL) / (100.0 - PEDESTAL); ichroma_lim2 = (int)(chroma_lim * SCALE + 0.5); ichroma_lim2 *= ichroma_lim2; icompos_lim = (int)(compos_lim * SCALE + 0.5);}inthot(p)Pixel *p;{ register int r, g, b; register int y, i, q; register long y2, c2; double pr, pg, pb;#if REDUCE_SAT double py;#endif register double fy, fc, t, scale;#if !FLAG_HOT static int prev_r = 0, prev_g = 0, prev_b = 0; static int new_r, new_g, new_b;#endif extern double pow(), hypot(); r = p->r; g = p->g; b = p->b; /* * Pixel decoding, gamma correction, and matrix multiplication * all done by lookup table. * * "i" and "q" are the two chrominance components; * they are I and Q for NTSC. * For PAL, "i" is U (scaled B-Y) and "q" is V (scaled R-Y). * Since we only care about the length of the chroma vector, * not its angle, we don't care which is which. */ y = tab[0][0][r] + tab[0][1][g] + tab[0][2][b]; i = tab[1][0][r] + tab[1][1][g] + tab[1][2][b]; q = tab[2][0][r] + tab[2][1][g] + tab[2][2][b]; /* * Check to see if the chrominance vector is too long or the * composite waveform amplitude is too large. * * Chrominance is too large if * * sqrt(i^2, q^2) > chroma_lim. * * The composite signal amplitude is too large if * * y + sqrt(i^2, q^2) > compos_lim. * * We avoid doing the sqrt by checking * * i^2 + q^2 > chroma_lim^2 * and * y + sqrt(i^2 + q^2) > compos_lim * sqrt(i^2 + q^2) > compos_lim - y * i^2 + q^2 > (compos_lim - y)^2 * */ c2 = (long)i * i + (long)q * q; y2 = (long)icompos_lim - y; y2 *= y2; if (c2 <= ichroma_lim2 && c2 <= y2) /* no problems */ return 0; /* * Pixel is hot, choose desired (compilation time controlled) strategy */#if FLAG_HOT /* * Set the hot pixel to black to identify it. */ p->r = p->g = p->b = 0;#else /* FLAG_HOT */ /* * Optimization: cache the last-computed hot pixel. */ if (r == prev_r && g == prev_g && b == prev_b) { p->r = new_r; p->g = new_g; p->b = new_b; return 1; } prev_r = r; prev_g = g; prev_b = b; /* * Get Y and chroma amplitudes in floating point. * * If your C library doesn't have hypot(), just use * hypot(a,b) = sqrt(a*a, b*b); * * Then extract linear (un-gamma-corrected) floating-point * pixel RGB values. */ fy = (double)y / SCALE; fc = hypot((double)i / SCALE, (double)q / SCALE); pr = pix_decode(r); pg = pix_decode(g); pb = pix_decode(b); /* * Reducing overall pixel intensity by scaling * R, G, and B reduces Y, I, and Q by the same factor. * This changes luminance but not saturation, since saturation * is determined by the chroma/luminance ratio. * * On the other hand, by linearly interpolating between the * original pixel value and a grey pixel with the same * luminance (R=G=B=Y), we change saturation without * affecting luminance. */#if !REDUCE_SAT /* * Calculate a scale factor that will bring the pixel * within both chroma and composite limits, if we scale * luminance and chroma simultaneously. * * The calculated chrominance reduction applies to the * gamma-corrected RGB values that are the input to * the RGB-to-YIQ operation. Multiplying the * original un-gamma-corrected pixel values by * the scaling factor raised to the "gamma" power * is equivalent, and avoids calling gc() and inv_gc() * three times each. */ scale = chroma_lim / fc; t = compos_lim / (fy + fc); if (t < scale) scale = t; scale = pow(scale, GAMMA); r = pix_encode(scale * pr); g = pix_encode(scale * pg); b = pix_encode(scale * pb);#else /* REDUCE_SAT */ /* * Calculate a scale factor that will bring the pixel * within both chroma and composite limits, if we scale * chroma while leaving luminance unchanged. * * We have to interpolate gamma-corrected RGB values, * so we must convert from linear to gamma-corrected * before interpolation and then back to linear afterwards. */ scale = chroma_lim / fc; t = (compos_lim - fy) / fc; if (t < scale) scale = t; pr = gc(pr); pg = gc(pg); pb = gc(pb); py = pr * code_matrix[0][0] + pg * code_matrix[0][1] + pb * code_matrix[0][2]; r = pix_encode(inv_gc(py + scale * (pr - py))); g = pix_encode(inv_gc(py + scale * (pg - py))); b = pix_encode(inv_gc(py + scale * (pb - py)));#endif /* REDUCE_SAT */ p->r = new_r = r; p->g = new_g = g; p->b = new_b = b;#endif /* FLAG_HOT */ return 1;}/* * gc: apply the gamma correction specified for this video standard. * inv_gc: inverse function of gc. * * These are generally just a call to pow(), but be careful! * Future standards may use more complex functions. * (e.g. SMPTE 240M's "electro-optic transfer characteristic"). */doublegc(x)double x;{ extern double pow(); return pow(x, 1.0 / GAMMA);}doubleinv_gc(x)double x;{ extern double pow(); return pow(x, GAMMA);}/* * pix_decode: decode an integer pixel value into a floating-point * intensity in the range [0, 1]. * * pix_encode: encode a floating-point intensity into an integer * pixel value. * * The code given here assumes simple linear encoding; you must change * these routines if you use a different pixel encoding technique. */doublepix_decode(v)int v;{ return (double)v / MAXPIX;}intpix_encode(v)double v;{ return (int)(v * MAXPIX + 0.5);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -