I imaged the Cygnus-Cepheus region of the Milky Way characterized by bright emission nebulae, countless stars and dark clouds of interstellar dust. Deneb with NGC 7000 North America and its neighbour, the Pelican, and gamma Cygni with the nebulae rules the upper right corner of the frame, while on the left the much fainter IC 1396 holds the Elephant’s Trunk. Downwards from the center the Cocoon Nebula ( IC 5146 / Caldwell 19) is also visible, amongst other fainter and less prominent deep sky objects.
This time I used the cheapest lens I have, the Canon EF 50mm f/1.8 II in manual focus mode, which is held tight and in focus by some hard wire I put on it. Although dialed to F/4, it performed pretty well, given the circumstances. In order to avoid having bad corners, I made a mosaic with big overlaps. So the HEQ5 mount held the Canon 1100D mod camera on a ball head, with the lens. 50×3 minutes, ISO 800, F/4. I also used the healing program – source code below.
<!-- script to fill the blanks of input.jpg by extrapolating the context of the blank, saving the output as output*.jpg --> <div align="center"> <?php report("=============starting the script============="); $i = imagecreatefromstring(file_get_contents('input.jpg')); report("created the input image"); //settings $GLOBALS['minlumi'] = 5; $GLOBALS['maxlumi'] = 140; $GLOBALS['max_damage'] = 250; $GLOBALS['csillaglumi'] = 150; $GLOBALS["kill_highlight_radius"] = 2; //2 or 3 $stages_to_save = 25; set_time_limit(60000);//majdnem 24 ora :P ini_set('memory_limit', '2048M'); //2 giga, szoval legyszives ignore_user_abort(true); //======================================================================== function report($s){ $s = $s.'<br />'; $s = str_replace("<br /><br />", "<br />", $s); $s = date('Y.m.d. H:i:s ').$s; echo $s; $s = str_replace("<br />", "\r\n", $s)."\r\n"; $s = str_replace("\r\n\r\n", "\r\n", $s); file_put_contents('log.txt', $s, FILE_APPEND | LOCK_EX); } //======================================================================== function numberaskilo($i){ while (strlen($i) < 3){ $i = "0".$i; } return $i; } //======================================================================== function int2rgb($i){ if (is_array($i)){ return $i; } $r = $i >> 16; $g = ($i >> 8) %256; $b = $i % 256; return array($r, $g, $b); } //======================================================================== function rgb2int($r, $g=false, $b=false){ if (is_array($r)){ $b = $r[2]; $g = $r[1]; $r = $r[0]; } return $r * 256*256 + $g*256 + $b; } //======================================================================== function luminanceof($i_or_rgb){ if (!is_array($i_or_rgb)){ $i_or_rgb = int2rgb($i_or_rgb); } return floor(($i_or_rgb[0] + $i_or_rgb[1]*2 + $i_or_rgb[2]) / 4); } //======================================================================== function imagesetpixel_($i, $tx, $ty, $p){ if (($tx >= 0) && ($tx < imagesx($i)) && ($ty >= 0) && ($ty < imagesy($i))){ imagesetpixel($i, $tx, $ty, $p); }; } //======================================================================== function imagecolorat_($i, $tx, $ty){ if (($tx >= 0) && ($tx < imagesx($i)) && ($ty >= 0) && ($ty < imagesy($i))){ return imagecolorat($i, $tx, $ty); }; return 0; } //======================================================================== function maxcolororluminance($pix){ return luminanceof($pix); //// $pix = int2rgb($pix); $pix[] = floor(($pix[0] + $pix[1] + $pix[1] + $pix[2]) / 4); return max($pix); } //======================================================================== function heal_pixel_if_possible($i, $x, $y){ $xy = $x.'_'.$y; $pix = imagecolorat($i, $x, $y); if (maxcolororluminance($pix) >= $GLOBALS['minlumi']){ return false; }; $u = array(); for ($tx = -1; $tx < 2; $tx++){ for ($ty = -1; $ty < 2; $ty++){ if (($tx==0)&&($ty==0)){ // _self }else{ $p = imagecolorat_($i, $tx+$x, $ty+$y); $l = maxcolororluminance($p); if (($l < $GLOBALS['maxlumi']) && ($l >= $GLOBALS['minlumi'])){ $u[] = int2rgb($p); } }; } } if (count($u) >= $GLOBALS['mincontext']){ $uj = array(0,0,0); foreach ($u as $j){ for ($q=0; $q<3; $q++){ $uj[$q] = $uj[$q] + $j[$q]; }; } for ($q=0; $q<3; $q++){ $uj[$q] = floor($uj[$q] / count($u)); }; imagesetpixel($i, $x, $y, rgb2int($uj)); return true; } } //======================================================================== function handle_this_pixel(&$i, &$x, &$y, &$healed, &$save_stage_at_x_heals, &$st){ if (!file_exists("run.txt")){ imagejpeg($i, "output_8_premature.jpg", 95); die(); } if (heal_pixel_if_possible($i, $x, $y)){ $healed++; if ($healed % $save_stage_at_x_heals == 0){ imagejpeg($i, 'output_3_stage_'.numberaskilo($st).'.jpg', 95); $st++; } }; }; //======================================================================== function kill_starmap(&$i, &$star_map, $radius = -1){ if ($radius == -1){ $radius = $GLOBALS["kill_highlight_radius"]; }; foreach ($star_map as $star){ $min = -$radius; $max = $radius; for ($rx = $min; $rx <= $max; $rx++){ for ($ry = $min; $ry <= $max; $ry++){ if ( (($rx == $min) OR ($rx == $max)) AND (($ry == $min) OR ($ry == $max)) ){ //this is a corner, but lets make the hole a bit round }else{ imagesetpixel_($i, $star[0]+$rx, $star[1]+$ry, 0); } } } } } //======================================================================== function kill_off_the_highlights(&$i){ report("killing off the highlights"); $star_map = array(); for ($x = 0; $x < imagesx($i); $x++){ for ($y = 0; $y < imagesy($i); $y++){ $pix = imagecolorat($i, $x, $y); if (maxcolororluminance($pix) > $GLOBALS['csillaglumi']){ $star_map[] = array($x, $y); }; } } kill_starmap($i, $star_map); imagejpeg($i, "input_2_nohighlights.jpg", 100); report('done killing off the highlights'); }; //======================================================================== function kill_off_remaining_starlike_areas(&$i){ ////ha minden iranyba ugyanaz vagy kisebb, akkor jelolt $lumidelta = 25; $max_coldelta = 45; $radius = 3; $kill = array(); $oszto = 10; $progress = round(imagesx($i) / $oszto); $ko = 0; for ($x =0; $x < imagesx($i); $x++){ if (($x+1) % $progress == 0){ $ko++; file_put_contents("input_4_no_smallerstars_".numberaskilo($ko)."_of_".numberaskilo($oszto).".txt", 100); } if (!file_exists('run.txt')){ die("premature exit"); } for ($y = 0; $y < imagesy($i); $y++){ $p = imagecolorat($i, $x, $y); if ($p > 0){ $rgb = int2rgb($p); $atlag = floor(($rgb[0] + $rgb[1]*2 + $rgb[2])/4); $coldelta = 0; for ($j =0; $j<=2; $j++){ $coldelta = max($coldelta, abs($rgb[$j] - $atlag)); } //based on hue, this could be a star, check its context if ($coldelta < $max_coldelta){ $context = array(); $context_is_lighter = false; for ($tx = -$radius; $tx <= $radius; $tx++){ for ($ty = -$radius; $ty <= $radius; $ty++){ if ((abs($tx)==$radius)AND(abs($ty)==$radius)){ //round the corners }else{ $k = imagecolorat_($i, $x+$tx, $y+$ty); $k_rgb = int2rgb($k); $k_atlag = floor(($k_rgb[0] + $k_rgb[1]*2 + $k_rgb[2])/4); if ($k_atlag > $atlag){ $context_is_lighter = true; } $context[] = $k; } } } $fainter = 0; $black = 0; if (!$context_is_lighter){ $context_looks_good = 0; foreach ($context as $c) if (($c!=0)OR(true)) { if ($c ==0 ){ $black++; } $c_rgb = int2rgb($c); $c_atlag = floor(($c_rgb[0] + $c_rgb[1]*2 + $c_rgb[2])/4); $c_coldelta = 0; for ($j =0; $j<=2; $j++){ $c_coldelta = max($c_coldelta, abs($c_rgb[$j] - $c_atlag)); } $is_fainter = ($c_atlag < $atlag-$lumidelta); if ($is_fainter){ $fainter++; } if (((abs($c_coldelta - $coldelta) < 15) AND (abs($c_atlag - $atlag) < 5)) OR ($is_fainter)){ $context_looks_good++; } } if ((abs(count($context) - $context_looks_good) < max(2, count($context) / 4)) AND ($fainter > 0) AND ($black < count($context) / 3)){ $kill[] = array($x, $y); } }; }//pixel is grey enough }//pixel not black } } kill_starmap($i, $kill, $radius); imagejpeg($i, "input_6_no_smallerstars.jpg", 100); } //======================================================================== function try_loading_a_cache_if_exists(&$i){ $icv = 'input_9_carved.jpg'; //remove this cache, start from scratch if (file_exists($icv)){ unlink($icv); } if (!file_exists($icv)){ report('image input loaded, no cache<br />'); kill_off_the_highlights($i); // kill_off_remaining_starlike_areas($i); report('saving the carved version<br />'); imagejpeg($i, $icv, 100); foreach (glob("*.jpg") as $filename){ echo '<img src="'.$filename.'?r='.mt_rand().'" />'; } //die(); }else{ report('image outpIt loaded from cache<br />'); imagedestroy($i); $i = imagecreatefromstring(file_get_contents($icv)); } } function filter_lighterthanoriginal(&$i){ //apply a "lighter than" filter, assuming the "to be replaced" areas were black $o = imagecreatefromstring(file_get_contents("input.jpg")); for ($x = 0; $x< imagesx($o); $x++){ for ($y =0; $y< imagesy($o); $y++){ $pixo = imagecolorat($o, $x, $y); $pixi = imagecolorat($i, $x, $y); if (luminanceof($pixi) > luminanceof($pixo)){ imagesetpixel($o, $x, $y, $pixi); } }; }; imagejpeg($o, 'output_z_final.jpg', 100); } //================================== main ================================== try_loading_a_cache_if_exists($i); //count the pixels to heal report('starting to count the pixels that need to be healed'); $pixels_to_heal = 0; $skip_y = array(); for ($y = imagesy($i)-1; $y > -1; $y--){ $th = 0; for ($x = imagesx($i)-1; $x > -1; $x--){ $pix = imagecolorat($i, $x, $y); if (maxcolororluminance($pix) < $GLOBALS['minlumi']){ $pixels_to_heal++; $th++; } } if ($th==0){ $skip_y[] = $y; report('nothing to heal in line '.$y.', adding to ignore list'); } } report('counted '.$pixels_to_heal.' pixels to heal, and save in '.$stages_to_save.' stages.<br />'); report(count($skip_y).' lines already being ignored'); $save_stage_at_x_heals = floor($pixels_to_heal / max($stages_to_save, 1))+1; //iterate and heal $healed = 0; $maxx = imagesx($i); $maxy = imagesy($i); //$maxx = 300; //$maxy = 300; //$iterations = 10; $st = 0; $lumi_delta = 255 - $GLOBALS["maxlumi"]; $healed_in_this_round = 0; $GLOBALS['maxlumi_orig'] = $GLOBALS["maxlumi"]; $skip_y_orig = $skip_y; $st2 = 0; $range_sx = array(); for ($sx = 0; $sx < imagesx($i); $sx = $sx + $GLOBALS['max_damage']){ $range_sx[] = $sx; }; shuffle($range_sx); $range_sy = array(); for ($sy = 0; $sy < imagesy($i); $sy = $sy + $GLOBALS['max_damage']){ $range_sy[] = $sy; }; shuffle($range_sy); //for random pairs of areas $pairs = array(); foreach ($range_sy as $sy){ foreach ($range_sx as $sx){ $pairs[] = array($sx, $sy); } }; shuffle($pairs); for ($main_iteration = 0; $main_iteration < 2; $main_iteration++){ foreach ($pairs as $pair){ $sx = $pair[0]; $sy = $pair[1]; $GLOBALS['mincontext'] = 5; //start high then fall down $GLOBALS["maxlumi"] = $GLOBALS["maxlumi_orig"]; $startx = $sx; $starty = $sy; $endy = min(imagesy($i), $starty + $GLOBALS['max_damage']); $endx = min(imagesx($i), $startx + $GLOBALS['max_damage']); $skip_y = $skip_y_orig; $to_heal_in_iteration = 1;//dummy $max_iterations = 50; // 10 still leaves holes $old_healed = $healed; for ($iterations = 0; $iterations < $max_iterations; $iterations++) if ($to_heal_in_iteration > 0){ $h1 = $healed; report("starting to heal [$startx, $starty, $endx, $endy]. Already healed = ".$healed.' of '.$pixels_to_heal.', '. $healed_in_this_round.' in the last round. Mincontext now = '.$GLOBALS['mincontext'].'<br />'); //checking lines that are ready $to_heal_in_iteration = 0; for ($y =$starty; $y<$endy; $y++) if (!in_array($y, $skip_y)){ $to_heal = 0; for ($x = $startx; $x<$endx; $x++){ $pix = imagecolorat($i, $x, $y); if (maxcolororluminance($pix) < $GLOBALS['minlumi']){ $to_heal++; $to_heal_in_iteration++; } } if ($to_heal == 0){ $skip_y[] = $y; report('added line '.$y.' to those that are ready and can be ignored<br />'); } }; $xrange = range($startx, $endx-1); shuffle($xrange); $yrange = range($starty, $endy-1); shuffle($yrange); $method = $iterations; //egyszer igy, egyszer ugy // don't rerun empty lines report('starting to handle pixels'); if ($method % 2 == 1){ report('method 1 running<br />'); foreach($yrange as $y) if (!in_array($y, $skip_y)){ foreach($xrange as $x){ handle_this_pixel($i, $x, $y, $healed, $save_stage_at_x_heals, $st); } } }else{ report('method 2 running<br />'); foreach($xrange as $x){ foreach($yrange as $y) if (!in_array($y, $skip_y)){ handle_this_pixel($i, $x, $y, $healed, $save_stage_at_x_heals, $st); } } } report('done'); //checking if the process' tolerance is low enough $healed_in_this_round = $healed - $h1; if ($healed_in_this_round < 100){ if ($GLOBALS['mincontext'] == 3){ report('few pixels healed, mincontext already small so increasing lumi tolerance<br />'); $GLOBALS['maxlumi'] = min(255, floor($GLOBALS['maxlumi']+$lumi_delta / 10)); }; if ($GLOBALS['mincontext'] > 3){ report('few pixels healed so decreased mincontext from '.$GLOBALS['mincontext'].'<br />'); $GLOBALS['mincontext']--; }; } /* if ($iterations > 1){ ////not doing this with the smaller areas if ($GLOBALS['mincontext'] > 4){ report('decreased mincontext from '.$GLOBALS['mincontext'].'<br />'); $GLOBALS['mincontext']--; } } */ if ($iterations > 3){ if ($GLOBALS['mincontext'] > 3){ report('decreased mincontext from '.$GLOBALS['mincontext'].'<br />'); $GLOBALS['mincontext']--; } } }; $st2++; $basename_oh = 'outpot_2_asregion_'.numberaskilo($st2); if ($old_healed != $healed){ imagejpeg($i, $basename_oh.'.jpg'); }else{ file_put_contents($basename_oh.'.txt', 'placeholder'); } };//for pairs };//main_iteration imagejpeg($i, 'output_8_before_lighterthan.jpg', 100); filter_lighterthanoriginal($i); // output a blinking interface to reveal the differences echo '<img id = "img1" src="input.jpg" width="800" />'; echo '<img id = "img2" src="output_z_final.jpg?'.mt_rand().'" width = "800" style="display:none"/>'; ?> </div> <script> setInterval(function (){ var a = document.getElementById("img1"); var b = document.getElementById("img2"); if (a.style.display!="none"){ a.style.display = "none"; b.style.display = ""; }else{ a.style.display = ""; b.style.display = "none"; } }, 1000); </script>





