ガンマ補正(program5)

  • 2020.07.01 Wednesday
  • 09:11

 最後にガンマ補正です。ここではゲイン調整とガンマの補正と黒レベル補正を行います。プログラムはsRGBにも対応できるようにしていますが、例では通常のγ=2.2で行っています。

 

ガンマ補正(program5)のプログラミング

 program4と同様に、program5のフォルダを作り、program1からprogram1.cpp,program1.h,ppm.cpp,ppm.h,Makefileをコピーし、ファイル名と中身の記述をprogram1からprogram5に全て変更。program5.cpp program5.hを赤字のように変更します。

  ガンマ補正(program5.cpp

/***************************************************

 * Calculate program5 (main file)

 * @file     program5.cpp

 * @author Akihiro Okumura

 * @date    2020.01.04

 ***************************************************/

 

#include "program5.h"

 

/*****************

 * Main function

 *****************/

int main(int argc, char *argv[])

{

                   int                                i = 1;

                   const char *program_name ="program5";

                   char           *file_i = NULL;           // input file

                   char           *file_o = NULL;          // output file

                   int                                black = 0;

                   int                                white = 255;

                   double       gain = 1.0;

                   double       gamma[5] = {2.4, 1.055, 0.055, 0.0031308, 12.92};

                   int                                o_black = 0;

                   int                                o_white = 255;

 

                   fprintf(stderr,"<< %s >>¥n", program_name);

                   fprintf(stderr,"2020.01.04 designed by A.Okumura¥n¥n");

 

 

                   black = ( argc > i )? atoi(argv[i]) : 0;

                   i++;

                   white = ( argc > i )? atoi(argv[i]) : 255;

                   i++;

                   o_black = ( argc > i )? atoi(argv[i]) : 0;

                   i++;

                   o_white = ( argc > i )? atoi(argv[i]) : 255;

                   i++;

                   gain = ( argc > i )? atof(argv[i]) : 1.0;

                   i++;

                   gamma[0] = ( argc > i )? atof(argv[i]) : 2.4;

                   i++;

                   gamma[1] = ( argc > i )? atof(argv[i]) : 1.055;

                   i++;

                   gamma[2] = ( argc > i )? atof(argv[i]) : 0.055;

                   i++;

                   gamma[3] = ( argc > i )? atof(argv[i]) : 0.0031308;

                   i++;

                   gamma[4] = ( argc > i )? atof(argv[i]) : 12.92;

                   i++;

                   file_i = argv[i++];                           // input file

                   file_o = argv[i++];                          // output file

 

                   /***** Main process *****/

                   if (0 != main_process(file_i, file_o, program_name, black, white, gain, gamma, o_black, o_white)) {

                                     return fprintf(stderr, "¥n! Calculation Failed !¥n¥n");

                   }

                   fprintf(stderr, "¥n!!!!! Calculation Succeeded !!!!!¥n¥n");

 

                   return 0;

}

 

/*****************************************************************

 *  main function of calculation

 *****************************************************************/

int main_process(char *infile, char *outfile, const char *program_name, int black, int white,

                   double gain, double gamma[5], int o_black, int o_white)

{

                   int              ppm_pn;

                   int              width, height;

                   int              bits;

                   // ppm header read

                   read_ppm_header(infile, &width, &height, &ppm_pn, &bits);

                   fprintf(stderr, "read ppm header¥n");

 

                   // size set

                   int              datasize = width * height;

 

                   // Memory allocate

                   unsigned short *rdatain = new unsigned short [datasize];

                   unsigned short *gdatain = new unsigned short [datasize];

                   unsigned short *bdatain = new unsigned short [datasize];

                   unsigned short *rdataout = new unsigned short [datasize];

                   unsigned short *gdataout = new unsigned short [datasize];

                   unsigned short *bdataout = new unsigned short [datasize];

 

                   // ppm data read

                   fprintf(stderr, "read ppm¥n");

                   read_ppm(infile, rdatain, gdatain, bdatain, width, height);

 

                   // gamma

                   fprintf(stderr, "process¥n");

                   f_gamma(rdatain, gdatain, bdatain, rdataout, gdataout, bdataout, width, height, bits,

                                      black, white, gain, gamma, o_black, o_white);

 

                   // ppm write

                   fprintf(stderr, "write ppm¥n");

                   write_ppm(outfile, rdataout, gdataout, bdataout, width, height, ppm_pn, bits, program_name);

 

                   delete [] rdatain;

                   delete [] gdatain;

                   delete [] bdatain;

                   delete [] rdataout;

                   delete [] gdataout;

                   delete [] bdataout;

 

                   return 0;

}

 

/*****************************************************************

 * gamma

 *****************************************************************/

void f_gamma(const unsigned short *rdatain, const unsigned short *gdatain, const unsigned short *bdatain,

                   unsigned short *rdataout, unsigned short *gdataout, unsigned short *bdataout,

                   int width, int height, int bits, int black, int white, double gain, double gamma[5],

                   int o_black, int o_white)

{

                   int              hp, vp;

                   int              pos;

                   int              maxlevel = (0x01 << bits) - 1;

                   double range = (double)(white - black);

                   double o_range = (double)(o_white - o_black);

 

                   for (vp = 0; vp < height; vp++){

                                     for (hp = 0; hp < width; hp++){

                                                        pos = vp*width + hp;

                                                        rdataout[pos] = (unsigned short)clip((int)((srgb_gamma((double)(rdatain[pos] - black) * gain / range, gamma) * o_range + 0.5) + (double)o_black), 0, maxlevel);

                                                        gdataout[pos] = (unsigned short)clip((int)((srgb_gamma((double)(gdatain[pos] - black) * gain / range, gamma) * o_range + 0.5) + (double)o_black), 0, maxlevel);

                                                        bdataout[pos] = (unsigned short)clip((int)((srgb_gamma((double)(bdatain[pos] - black) * gain / range, gamma) * o_range + 0.5) + (double)o_black), 0, maxlevel);

                                     }        // hp loop end

                   }        // vp loop end

 

  return;

}

 

 

double srgb_gamma(double data, double gamma[5])

{

                   double out;

 

                   if(data < gamma[3]){

                                     out = data * gamma[4];

                   } else {

                                     out = gamma[1] * pow(data, 1.0/gamma[0]) - gamma[2];                   

                   }

                   return out;

}

 

int clip(int a, int minlevel, int maxlevel)

{

                   int              ans;

                   ans = a;

                   if (ans >= maxlevel) ans = maxlevel;

                   if (ans <= minlevel) ans = minlevel;

                   return       ans;

}

 

/***** End of File (program5.cpp) *****/

 

  program5のヘッダーファイル(program5.h)

/***************************************************

 * Calculate program5 (header file)

 * @file     program5.h

 * @author Akuhiro Okumura

 * @date    2020.01.04

 ***************************************************/

 

#pragma once

 

#ifdef LINUX

#else

#pragma warning(disable:4996)   //                 fopen

#endif

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <math.h>

 

/***** prototype *****/

// main process

int main_process(char *infile, char *outfile, const char *program_name, int black, int white, double gain,

                   double gamma[5], int o_black, int o_white);

 

void read_ppm_header(char *file, int *width, int *height, int *ppm_pn, int *bits);

void read_ppm(char *file, unsigned short *r_data, unsigned short *g_data, unsigned short *b_data, int width, int height);

void write_ppm(char *file, unsigned short *r_data, unsigned short *g_data, unsigned short *b_data,

                   int width, int height, int ppm_pn, int bits, const char *program_name);

 

void f_gamma(const unsigned short *rdatain, const unsigned short *gdatain, const unsigned short *bdatain,

                   unsigned short *rdataout, unsigned short *gdataout, unsigned short *bdataout,

                   int width, int height, int bits, int black, int white, double gain, double gamma[5],

                   int o_black, int o_white);

 

double srgb_gamma(double data, double gamma[5]);

 

int clip(int a, int minlevel, int maxlevel);

 

/***** End of File (program5.h) *****/

 

●program5のコンパイル

 必要なファイルが揃ったら次にコンパイルです。

1Ubuntuを起動します。

2Ubuntuのターミナルからディレクトリーを選択し、makeとタイプしてコンパイルします。program5 ppm.o program5.oというファイルが出来ていれば成功です。

 

●program5の実行

 program5のコンパイルが終わったら、実行させます。

1.コンパイルして出来たprogram5workにコピーします。

2exiftoolを使ってExifデータからカラーマトリックスの値を調べます

 同様にExifデータを調べます。α7siiの場合は、White Levelの項目がホワイトレベルの値となります。α7sii14bitRAWデータなので最大値は16383でホワイトレベルは15360のようです。

  Exifデータ(ホワイトレベル

3.program5.exe <ブラックレベル> <ホワイトレベル> <出力ブラックレベル> <出力ホワイトレベル> <ゲイン> <γ> <γの引数1> <γの引数2> <γの引数3> <γの引数4> <変換前の画像名> <変換後の画像名>⏎とタイプしてプログラムを実行させます。<変換前の画像名>は、program4で処理したカラーマトリックス後の画像を使います。例では通常のγ=2.2に処理するため、γの引数はそれぞれ1 0 0 1を入力します。

$ ./program5.exe 512 15360 0 65536 1.0 2.2 1 0 0 1 DSC00100_cm.ppm DSC00100_gg.ppm

出力ファイルが出来ていれば、処理終了です。

DSC00100_gg.ppmをビューアーで見てみます。

  ガンマ補正(program5)の処理結果

γがかかり、14bitのデータも16bitに正規化されるので明るさも明るくなりました。これでRAW現像は完成です。dcrawのデフォルトの現像結果と比べると地味ですが、実際に人が見えているような映像はこんなものだと思います。インパクトのある画像にしたいのならば、編集ソフトなどで加工します。一般的に売られているディジタルカメラの画像は、現実の画からかなり加工されています。

 この内容は、「Interface誌2020年7月号特集 AI時代の画像処理教科書 第4の記事を、読者の便宜をはかるために加筆修正したものです。(同一内容ではない)、また、ここでのプログラムは、CQ出版社さんのダウンロードページの[7月号 AI時代の画像処理教科書][特集 第4章,第5章 画像処理プログラミング] [関連ファイル一式]からダウンロードできます。

 

●プログラミングのおわりに

 プログラミングでは、PPMフォーマットの説明とプログラミング、そしてRAW現像のプログラミングについて説明してきました。これで皆さんは圧縮(ひず)みの無い非圧縮のが手に入れることが出来るようになったと思います。ある意味、やっと画像処理のスタートラインに立てたと思ってください。

 

 

コメント
コメントする








    

calendar

S M T W T F S
   1234
567891011
12131415161718
19202122232425
262728293031 
<< July 2020 >>

selected entries

categories

archives

links

profile

search this site.

others

mobile

qrcode

powered

無料ブログ作成サービス JUGEM