The Milky Way in Chepheus and Cygnus

The Milky Way in Chepheus and Cygnus

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.

 

2016.10.01. raw sample

2016.10.01. raw sample

corners…

corners…

the mosaic

the mosaic

colors

colors

cropping

cropping

before star-healing

before star-healing

stars handled

stars handled

handling: carving out the stars and their context

handling: carving out the stars and their context

FILLING THE VOIDS

FILLING THE VOIDS

no more luminous stars

no more luminous stars

combining the data

combining the data

The Milky Way in Chepheus and Cygnus – final picture

The Milky Way in Chepheus and Cygnus – final picture

<!-- 
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>
facebooktwittergoogle_plusredditpinterestlinkedinmail