読者です 読者をやめる 読者になる 読者になる

HDR写真 港夜景

 自作ソフトでHDR写真。RAWデータから露出を変えて生成した3枚の写真から合成しています。もっとRAWデータで撮っておけばよかったかなとちょっとだけ思いました。

120727_HDRMinato
 Olympus OM-D E-M5 + MZD 45mm, f1.8 自作のHDR画像生成ソフトで処理

ソフト改良

 自作ソフト、無駄な計算が多かったので見直して高速化しました。多分3倍くらいは早くなります。興味ある人は続きを読むをクリックして下さい

PImage img0;
PImage img1;
PImage img2;

float lum;
float lum_sum;
int sum_numb;

final int scope = 200; // 1 to picture width
final int scope_speed = 20; // 1 to scope
final int average_speed = 2; // 0 to picture width
final float a = 0.27;
final float gamma_u = 0.5;
final float gamma_n = 1;
final float gamma_o = 0.5;
final float color_gain = 2.2;
final float delta = 0.01;
float[] lut_u = new float[256];
float[] lut_n = new float[256];
float[] lut_o = new float[256];

void setup() {
  size(10, 10);

  println("select under exposed photo.");
  String imgPath = selectInput();
  img0 = loadImage(imgPath);

  println("select normal exposed photo.");
  imgPath = selectInput();
  img1 = loadImage(imgPath);

  println("select over exposed photo.");
  imgPath = selectInput();
  img2 = loadImage(imgPath);

  size(img0.width, img0.height);
  

  for (int i = 0; i < 256; i++){
    lut_u[i] = 255*pow(((float)i/255),(1/gamma_u));
  }

  for (int i = 0; i < 256; i++){
    lut_n[i] = 255*pow(((float)i/255),(1/gamma_n));
  }

  for (int i = 0; i < 256; i++){
    lut_o[i] = 255*pow(((float)i/255),(1/gamma_o));
  }
}

void draw(){
  image(img0, 0, 0);

  // Making HDRImage-----
  float[] hdr_img_r = new float[img0.height*img0.width];
  float[] hdr_img_g = new float[img0.height*img0.width];
  float[] hdr_img_b = new float[img0.height*img0.width];

  img0.loadPixels();
  img1.loadPixels();
  img2.loadPixels();

  for(int i = 0; i < img0.width*img0.height; i++){
    color tmp_color0 = img0.pixels[i];
    color tmp_color1 = img1.pixels[i];
    color tmp_color2 = img2.pixels[i];

    hdr_img_r[i] =
      lut_u[(int)red(tmp_color0)] + lut_n[(int)red(tmp_color1)] + lut_o[(int)red(tmp_color2)];
    hdr_img_g[i] =
      lut_u[(int)green(tmp_color0)] + lut_n[(int)green(tmp_color1)] + lut_o[(int)green(tmp_color2)];
    hdr_img_b[i] =
      lut_u[(int)blue(tmp_color0)] + lut_n[(int)blue(tmp_color1)] + lut_o[(int)blue(tmp_color2)];

    hdr_img_r[i] = hdr_img_r[i]/3*color_gain;
    hdr_img_g[i] = hdr_img_g[i]/3*color_gain;
    hdr_img_b[i] = hdr_img_b[i]/3*color_gain;
  }

  for(int y = 0; y < img0.height; y++){
    for(int x = 0; x < img0.width; x++){
      int pos = x + y*img0.width;
      color tmp_color = color(hdr_img_r[pos], hdr_img_g[pos], hdr_img_b[pos]);
      set(x, y, tmp_color);
    }
  }
  //----Making HDRImage

  //ToneMapping----
  color[] tmp_img = new color[img0.height*img0.width];
  int tmp = average_speed;
  float lum_sum_w = 0;

  float[] lum = new float[img0.height*img0.width];
  float[] lum_local = new float[img0.height*img0.width];
  float[] u = new float[img0.height*img0.width];
  float[] v = new float[img0.height*img0.width];

  for(int y = 0; y < img0.height; y++){
    for(int x = 0; x < img0.width; x++){
      int pos = x + y*img0.width;
      lum[pos] = 0.3*hdr_img_r[pos] + 0.59*hdr_img_g[pos] + 0.11*hdr_img_b[pos];
      lum_local[pos] = log((0.3*hdr_img_r[pos] + 0.59*hdr_img_g[pos] + 0.11*hdr_img_b[pos])/256+delta);
      u[pos] = -0.17*hdr_img_r[pos] - 0.33*hdr_img_g[pos] + 0.5*hdr_img_b[pos];
      v[pos] = 0.5*hdr_img_r[pos] -0.42*hdr_img_g[pos] - 0.08*hdr_img_b[pos];
    }
  }

  for(int y = 0; y < img0.height; y++){
    tmp = average_speed;
    for(int x = 0; x < img0.width; x++){
      int pos = x + y*img0.width;
      lum_sum = 0;
      sum_numb = 0;
      tmp++;
      if(tmp > average_speed){
        tmp = 0;
        for(int y_2 = y-scope; y_2 < y+scope; y_2 += scope_speed){
          for(int x_2 = x-scope; x_2 < x+scope; x_2 += scope_speed){
            if(y_2 >= 0 && y_2 < img0.height && x_2 >=0 && x_2 < img0.width){
              if(sqrt((x_2-x)*(x_2-x)+(y_2-y)*(y_2-y)) <= scope){
                sum_numb++;
                int pos_2 = x_2 + y_2*img0.width;
                lum_sum += lum_local[pos_2];
              }
            }
          }
        }
        lum_sum_w = exp(lum_sum/(float)sum_numb);
      }

      float lum_w = lum[pos]/lum_sum_w*a;
      float r = lum_w + 1.4*v[pos];
      float g = lum_w -0.34*u[pos] -0.71*v[pos];
      float b = lum_w + 1.77*u[pos];
      
      tmp_img[pos] = color(r,g,b);
    }
  }

  for(int y = 0; y < img0.height; y++){
    for(int x = 0; x < img0.width; x++){
      int pos = x + y*img0.width;
      set(x, y, tmp_img[pos]);
    }
  }
}


void keyPressed() { 
  // save image
  if(key == 'p' || key == 'P') {
    save("screenshot.jpg"); 
    println("screen saved."); 
  }

  // exit
  if(key == ' ') {
    exit();
  }
}