image source; source.open("img002.png"); textbuffer output; output.open("output.txt"); output.clear(); double r_max = 0; double r_min = 256; double b_max = 0; double b_min = 256; double g_max = 0; double g_min = 256; for x from 0 to source.width for y from 0 to source.height { color col = source.getColor(x,y); if (col.r < r_min) r_min = col.r; if (col.r > r_max) r_max = col.r; if (col.b < b_min) b_min = col.b; if (col.b > b_max) b_max = col.b; if (col.g < g_min) g_min = col.b; if (col.g > g_max) g_max = col.b; } output.append(format("%f-%f %f-%f %f-%f\n", r_min, r_max, b_min, b_max, g_min, g_max)); double r_diff = r_max - r_min; double b_diff = b_max - b_min; double g_diff = g_max - g_min; int count[16,16,16]; for x from 0 to source.width for y from 0 to source.height { color col = source.getColor(x,y); double r = (col.r - r_min)/r_diff; double b = (col.b - b_min)/b_diff; double g = (col.g - g_min)/g_diff; count[round(r*16),round(g*16),round(b*16)]++; } int total_points = source.height * source.width; int colour_for[16,16,16]; color colour_for_nr[5]; colour_for_nr[0] = Color(128, 128, 128); double center_r[5]; double center_g[5]; double center_b[5]; int mass[5]; int collected = 0; colour_for[15,15,15] = 1; collected += count[15,15,15]; colour_for_nr[1] = Color(255, 255, 255); center_r[1] = 15*15.0; center_g[1] = 15*15.0; center_b[1] = 15*15.0; colour_for[0,0,0] = 2; collected += count[0,0,0]; colour_for_nr[2] = Color(0, 0, 0); center_r[2] = 0.0; center_g[2] = 0.0; center_b[2] = 0.0; int nr_colours = 2; while (collected * 100 < total_points * 85) { int max; int max_r; int max_g; int max_b; for r from 0 to 16 for g from 0 to 16 for b from 0 to 16 if (colour_for[r,g,b] == 0 && count[r,g,b] > max) { max = count[r,g,b]; max_r = r; max_g = g; max_b = b; } output.append(format("next max %d at %d,%d,%d: ", max, max_r, max_g, max_b)); double min_dist = -1.0; int min_dist_colour; for r from 0 to 16 for g from 0 to 16 for b from 0 to 16 if (colour_for[r,g,b] != 0) { int dist = (r-max_r)*(r-max_r) + (g-max_g)*(g-max_g) + (b-max_b)*(b-max_b); if (min_dist == -1 || dist < min_dist) { min_dist = dist; min_dist_colour = colour_for[r,g,b]; } } if ((min_dist != -1 && min_dist <= 6.0) || nr_colours == 4) { output.append(format(" at distance %lf from %d\n", sqrt(1.0*min_dist), min_dist_colour)); colour_for[max_r, max_g, max_b] = min_dist_colour; int old_mass = mass[min_dist_colour]; int new_mass = count[max_r, max_g, max_b]; center_r[min_dist_colour] = (center_r[min_dist_colour]*old_mass + (1.0*max_r)*new_mass)/(old_mass + new_mass); center_g[min_dist_colour] = (center_g[min_dist_colour]*old_mass + (1.0*max_g)*new_mass)/(old_mass + new_mass); center_b[min_dist_colour] = (center_b[min_dist_colour]*old_mass + (1.0*max_b)*new_mass)/(old_mass + new_mass); mass[min_dist_colour] += new_mass; } else { nr_colours++; output.append(format(" new colour %d\n", nr_colours)); color new_col = Color(16*max_r, 16*max_g, 16*max_b); if (max_r + max_g + max_b >= 42) new_col = Color(255, 255, 255); else if (max_r + max_g + max_b <= 4) new_col = Color(0, 0, 0); colour_for_nr[nr_colours] = new_col; center_r[nr_colours] = 1.0*max_r; center_g[nr_colours] = 1.0*max_g; center_b[nr_colours] = 1.0*max_b; mass[nr_colours] = count[max_r, max_g, max_b]; colour_for[max_r, max_g, max_b] = nr_colours; } collected += count[max_r, max_g, max_b]; } image target; target.open("result.png"); target.new(source.width, source.height); for x from 0 to source.width for y from 0 to source.height { color col = source.getColor(x,y); double r = (col.r - r_min)/r_diff; double b = (col.b - b_min)/b_diff; double g = (col.g - g_min)/g_diff; int col_nr = colour_for[round(r*16),round(g*16),round(b*16)]; if (col_nr != 0) target.setColor(x, y, colour_for_nr[col_nr]); else target.setColor(x, y, Color(128,128,128)); } bool fill_grey = false; // remove shadow for x from 0 to source.width { int grey = -1; for ym from 0 to source.height { int y = source.height - 1 - ym; color tcol = target.getColor(x,y); color col = source.getColor(x,y); if (tcol.r == 255 && tcol.g == 255 && tcol.b == 255) grey = 255; else if (tcol.r == 128 && tcol.g == 128 && tcol.b == 128) { if (col.r + col.g + col.r > 195+158+158) { target.setColor(x, y, Color(255,255,255)); grey = round((col.r + col.g + col.b)/3); } else if (grey != -1) { double new_grey = (col.r + col.g + col.b)/3; if ( new_grey < grey + 10 && new_grey - 35 < col.r && col.r < new_grey + 35 && new_grey - 35 < col.g && col.g < new_grey + 35 && new_grey - 40 < col.b && col.b < new_grey + 40) { target.setColor(x, y, Color(255,255,255)); grey = round(new_grey); } else grey = -1; } if (fill_grey && grey == -1) { double distb = col.r*col.r + col.b*col.b + col.g*col.g; double distg = (col.r-center_r[3]*16)*(col.r-center_r[3]*16) + (col.g-center_g[3]*16)*(col.g-center_g[3]*16) + (col.b-center_b[3]*16)*(col.b-center_b[3]*16); target.setColor(x, y, distb < distg ? Color(0,0,0) : colour_for_nr[3]); } } else grey = -1; } } int ytop = 0; bool go = true; while (go && ytop < source.height) { for x from 0 to source.width { color col = target.getColor(x, ytop); if (col.r != 255 || col.g != 255 || col.b != 255) go = false; } if (go) ytop = ytop + 1; } int ybot = source.height-1; go = true; while (go && ybot > 0) { for x from 0 to source.width { color col = target.getColor(x, ybot); if (col.r != 255 || col.g != 255 || col.b != 255) go = false; } if (go) ybot = ybot - 1; } int ymid = (ytop + ybot)/2; int yscale = ymid - ytop; output.append(format("ytop = %d, ybot = %d, ymid = %d, yscale = %d\n", ytop, ybot, ymid, yscale)); int xlft = 0; go = true; while (go && xlft < source.width) { for y from 0 to source.height { color col = target.getColor(xlft, y); if (col.r != 255 || col.g != 255 || col.b != 255) go = false; } if (go) xlft = xlft + 1; } int xrht = source.width-1; go = true; while (go && xrht > 0) { for y from 0 to source.height { color col = target.getColor(xrht, y); if (col.r != 255 || col.g != 255 || col.b != 255) go = false; } if (go) xrht = xrht - 1; } int xmid = (xlft + xrht)/2; int xscale = xmid - xlft; output.append(format("ytop = %d, ybot = %d, ymid = %d, yscale = %d\n", xlft, xrht, xmid, xscale)); // adjust center double pi = atan2(-1.0, 0.0); int try_x[9]; int try_y[9]; int try_sx[9]; int try_sy[9]; try_x[1] = 1; try_x[2] = -1; try_y[3] = 1; try_y[4] = -1; try_sx[5] = 1; try_sx[6] = -1; try_sy[7] = 1; try_sy[8] = -1; int best_direction = 20; int adjusts = 0; while (best_direction != 0 && adjusts < 20) { adjusts = adjusts + 1; double best_square_sum = 0.0; best_direction = -1; for direction from 0 to 9 { int xmid_d = xmid + try_x[direction]; int ymid_d = ymid + try_y[direction]; int xscale_d = xscale + try_sx[direction]; int yscale_d = yscale + try_sy[direction]; double square_sum = 0; for y from 0 to 320 { double xs = (xscale_d * (469 - y)) / 480; double ys = (yscale_d * (469 - y)) / 480; int yellow = 0; int white = 0; for x from 0 to 1800 { double a = x * pi / 900; color col = source.getInterpolatedColor(xmid_d - xs*cos(a), ymid_d - ys*sin(a)); double r = (col.r - r_min)/r_diff; double b = (col.b - b_min)/b_diff; double g = (col.g - g_min)/g_diff; int col_nr = colour_for[round(r*16),round(g*16),round(b*16)]; if (col_nr == 1) white = white + 1; else if (col_nr == 3) yellow = yellow + 1; } if ((y % 20) < 4) square_sum += yellow * yellow; else square_sum += (1800 - yellow + white) * (1800 - yellow + white); y = y + 1; } output.append(format("%d %4d %4d %4d %4d %10f\n", direction, xmid_d, ymid_d, xscale_d, yscale_d, square_sum)); if (square_sum > best_square_sum) { best_square_sum = square_sum; best_direction = direction; } } output.append(format("d = %d\n", best_direction)); xmid += try_x[best_direction]; ymid += try_y[best_direction]; xscale += try_sx[best_direction]; yscale += try_sy[best_direction]; } for an from 0 to 1000 { double a = an * pi / 500; target.setColor(round(xmid + xscale*sin(a)), round(ymid + yscale*cos(a)), Color(0, 0, 255)); } // Find start line double darkest = -1.0; double start_angle = 0; for x from 0 to 3600 { double a = x * pi / 1800; double dark = 0; for y from 310 to 990 { double xs = (xscale * y) / 1000; double ys = (yscale * y) / 1000; color col = source.getInterpolatedColor(xmid + xs*sin(a), ymid + ys*cos(a)); dark += col.r + col.g + col.b; } if (darkest < 0 || dark < darkest) { darkest = dark; start_angle = a; } } output.append(format("Start angle = %f\n", start_angle)); image target2; target2.open("result2.png"); int dsteps = 3600; int rsteps = 480; target2.new(dsteps, rsteps); int prev_yellow = 0; for y from 0 to rsteps { double xs = (xscale * (rsteps - y)) / rsteps; double ys = (yscale * (rsteps - y)) / rsteps; int white = 0; int yellow = 0; for x from 0 to dsteps { double a = start_angle - x * pi * 2 / dsteps; color col = source.getInterpolatedColor(xmid + xs*sin(a), ymid + ys*cos(a)); double r = (col.r - r_min)/r_diff; double b = (col.b - b_min)/b_diff; double g = (col.g - g_min)/g_diff; int col_nr = colour_for[round(r*16),round(g*16),round(b*16)]; if (col_nr == 1) white = white + 1; else if (col_nr == 3) yellow = yellow + 1; target2.setColor(x, y, col); } prev_yellow = yellow; } image target3; target3.open("result3.png"); target3.new(3600, 160); for x from 0 to 3600 { double a = start_angle - x * pi / 1800; double sina = sin(a); double cosa = cos(a); for t from 0 to 16 { color col; for y from 17 to 29 { double xs = (xscale * (480 - y - t*20)) / 480; double ys = (yscale * (480 - y - t*20)) / 480; col += source.getInterpolatedColor(xmid + xs*sina, ymid + ys*cosa); } for y from 0 to 4 target3.setColor(x, t*10 + y, col); double r = (col.r - r_min)/r_diff; double b = (col.b - b_min)/b_diff; double g = (col.g - g_min)/g_diff; int col_nr = colour_for[round(r*16),round(g*16),round(b*16)]; if (col_nr != 0) col = colour_for_nr[col_nr]; else if (col.r + col.g + col.r > 195+158+158) col = Color(255,255,255); else col = Color(128,128,128); for y from 4 to 10 target3.setColor(x, t*10 + y, col); } } color yellow = colour_for_nr[3]; color grey = Color(128,128,128); for t from 0 to 16 { for x from 0 to 3600 { color col = target3.getColor(x, t*10 + 6); if (x < 28) { for y from 6 to 10 target3.setColor(x, t*10 + y, yellow); } else if (col == grey) { int nx = x+1; bool go = true; bool found_white = false; while (go && nx < 3600) { col = target3.getColor(nx, t*10 + 5); if (col == Color(255,255,255)) { found_white = true; go = false; } else if (col == yellow) go = false; else nx = nx + 1; } if (!go) { if (found_white) { for y from 6 to 10 target3.setColor(x, t*10 + y, yellow); for xi from x+1 to nx for y from 6 to 10 target3.setColor(xi, t*10 + y, Color(255,255,255)); go = true; int mx = nx+1; while (go && mx < 3600) { col = target3.getColor(mx, t*10 + 5); if (col == yellow) go = false; else mx = mx + 1; } for xi from nx+1 to mx-1 for y from 6 to 10 target3.setColor(xi, t*10 + y, Color(255,255,255)); for y from 6 to 10 target3.setColor(mx-1, t*10 + y, yellow); output.append(format("track %2d sound from %4d to %4d\n", t, x+1, mx)); } else { for xi from x to nx for y from 6 to 10 target3.setColor(xi, t*10 + y, yellow); } } } } }