// the derby program: unsharp mask by gaussian smoothing class Program { int image[600000]; int tempMask [100000]; int unsharpMask [100000]; int unsharpKernel[9]; int cols, rows; void read_file() { int r, c; callout ("ppm_open_for_read", "input.ppm"); cols = callout ("ppm_get_cols"); rows = callout ("ppm_get_rows"); for r = 0, rows { for c = 0, cols { image[3 * (r * 333 + c) + 0] = callout ("ppm_get_next_pixel_color"); image[3 * (r * 333 + c) + 1] = callout ("ppm_get_next_pixel_color"); image[3 * (r * 333 + c) + 2] = callout ("ppm_get_next_pixel_color"); } } callout ("ppm_close"); } void write_file() { int r, c; callout ("ppm_open_for_write", "output.ppm", cols, rows); for r = 0, rows { for c = 0, cols { callout ("ppm_write_next_pixel", image[3 * (r * 333 + c)], image[3 * (r * 333 + c) + 1], image[3 * (r * 333 + c) + 2]); } } callout ("ppm_close"); } void convert2HSV() { int row, col; for row = 0, rows { for col = 0, cols { int min, max; int delta; int h, s, v; // r = image[3 * (row * 333 + col) + 0]; // g = image[3 * (row * 333 + col) + 1]; // b = image[3 * (row * 333 + col) + 2]; if (image[3 * (row * 333 + col) + 0] > image[3 * (row * 333 + col) + 1]) { max = image[3 * (row * 333 + col) + 0]; min = image[3 * (row * 333 + col) + 1]; } else { max = image[3 * (row * 333 + col) + 1]; min = image[3 * (row * 333 + col) + 0]; } if (max < image[3 * (row * 333 + col) + 2]) { max = image[3 * (row * 333 + col) + 2]; } else { if (min > image[3 * (row * 333 + col) + 2]) { min = image[3 * (row * 333 + col) + 2]; } } delta = max - min; v = 4 * max; if (max == 0) { s = 0; } else { s = 1024 * delta / max; } if (delta == 0) { h = -1; } else { if (max == image[3 * (row * 333 + col) + 0] && image[3 * (row * 333 + col) + 1] >= image[3 * (row * 333 + col) + 2]) { h = 60 * (image[3 * (row * 333 + col) + 1] - image[3 * (row * 333 + col) + 2]) / delta; } else { if (max == image[3 * (row * 333 + col) + 0] && image[3 * (row * 333 + col) + 1] < image[3 * (row * 333 + col) + 2]) { h = 360 + 60 * (image[3 * (row * 333 + col) + 1] - image[3 * (row * 333 + col) + 2]) / delta; } else { if (max == image[3 * (row * 333 + col) + 1]) { h = 120 + 60 * (image[3 * (row * 333 + col) + 2] - image[3 * (row * 333 + col) + 0]) / delta; } else { h = 240 + 60 * (image[3 * (row * 333 + col) + 0] - image[3 * (row * 333 + col) + 1]) / delta; } } } } image[3 * (row * 333 + col) + 0] = h; image[3 * (row * 333 + col) + 1] = s; image[3 * (row * 333 + col) + 2] = v; } } } void convert2RGB() { int row, col; for row = 0, rows { for col = 0, cols { int r, g, b; int v; int j; int f, p, q, t; // h = image[3 * (row * 333 + col) + 0]; // s = image[3 * (row * 333 + col) + 1]; // v = image[3 * (row * 333 + col) + 2]; if (image[3 * (row * 333 + col) + 1] == 0) { r = image[3 * (row * 333 + col) + 2] / 4; g = image[3 * (row * 333 + col) + 2] / 4; b = image[3 * (row * 333 + col) + 2] / 4; } else { j = (image[3 * (row * 333 + col) + 0] / 60) % 6; f = image[3 * (row * 333 + col) + 0] % 60; p = image[3 * (row * 333 + col) + 2] * (1024 - image[3 * (row * 333 + col) + 1]) / (1024 * 4); q = image[3 * (row * 333 + col) + 2] * (1024 * 60 - image[3 * (row * 333 + col) + 1] * f) / (1024 * 60 * 4); t = image[3 * (row * 333 + col) + 2] * (1024 * 60 - image[3 * (row * 333 + col) + 1] * (60 - f)) / (1024 * 60 * 4); v = image[3 * (row * 333 + col) + 2] / 4; if (j==0) { r = v; g = t; b = p; } if (j==1) { r = q; g = v; b = p; } if (j==2) { r = p; g = v; b = t; } if (j==3) { r = p; g = q; b = v; } if (j==4) { r = t; g = p; b = v; } if (j==5) { r = v; g = p; b = q; } } image[3 * (row * 333 + col) + 0] = r; image[3 * (row * 333 + col) + 1] = g; image[3 * (row * 333 + col) + 2] = b; } } } void createUnsharpMask(int channel) { int kernel_sum; int center; int i, r, c, cc, rr; unsharpKernel[0] = 4433; unsharpKernel[1] = 54006; unsharpKernel[2] = 242036; unsharpKernel[3] = 399050; unsharpKernel[4] = 242036; unsharpKernel[5] = 54006; unsharpKernel[6] = 4433; center = 3; kernel_sum = 0; for i = 0, center * 2 + 1 { kernel_sum = kernel_sum + unsharpKernel[i]; } // convolve in x-direction for r = 0, rows { for c = 0, center { tempMask[r * 333 + c] = image[3 * (r * 333 + c) + channel]; } for c = center, cols - center { tempMask[r * 333 + c] = 0; for cc = -center, (center + 1) { tempMask[r * 333 + c] += (image[3 * (r * 333 + (c + cc)) + channel] * unsharpKernel[center + cc]); } tempMask[r * 333 + c] = tempMask[r * 333 + c] / kernel_sum; } for c = cols - center, cols { tempMask[r * 333 + c] = image[3 * (r * 333 + c) + channel]; } } unsharpKernel[center] = unsharpKernel[center] - kernel_sum; // convolve in y-direction for c = 0, cols { for r = 0, center { unsharpMask[r * 333 + c] = 0; } for r = center, rows - center { unsharpMask[r * 333 + c] = 0; for rr = -center, center + 1 { unsharpMask[r * 333 + c] = unsharpMask[r * 333 + c] + (tempMask[(r + rr) * 333 + c] * unsharpKernel[center + rr]); } unsharpMask[r * 333 + c] = unsharpMask[r * 333 + c] / kernel_sum; } for r = rows - center, rows { unsharpMask[r * 333 + c] = 0; } } } void sharpen(int channel, int amount, int channelOne) { int c, r; for c = 0, cols { for r = 0, rows { image[3 * (r * 333 + c) + channel] = image[3 * (r * 333 + c) + channel] * (channelOne + amount * unsharpMask[r * 333 + c]) / channelOne; if (image[3 * (r * 333 + c) + channel] >= channelOne) { image[3 * (r * 333 + c) + channel] = channelOne - 1; } } } } void main() { read_file(); callout("start_caliper"); convert2HSV (); createUnsharpMask (0); sharpen (0, -4, 360); createUnsharpMask (1); sharpen (1, -4, 1024); createUnsharpMask (2); sharpen (2, -4, 1024); convert2RGB (); callout("end_caliper"); write_file(); } }