ガンマ補正(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現像のプログラミングについて説明してきました。これで皆さんは圧縮(ひず)みの無い非圧縮のが手に入れることが出来るようになったと思います。ある意味、やっと画像処理のスタートラインに立てたと思ってください。

 

 

カラーマトリックス補正(program4)

  • 2020.06.30 Tuesday
  • 16:00

 デモザイクの次はカラーマトリックス補正です。カラーマトリックス補正は、R,G,Bのデータが揃っていないと掛けられないのでデモザイク処理後になります。カラーマトリックスの値もホワイトバランス同様にExifデータに書かれている値を使いますが、メーカーによってはカラーマトリックスの値が載っていない場合もあります。その場合はカラーマトリックス補正を掛けなくても良いようです。また、小数点で記述してある場合もありますが、その時はプログラムを小数点対応に書き直してください。

 

●カラーマトリックス補正(program4)のプログラミング

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

 

  カラーマトリックス補正(program4.cpp)

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

 * Calculate program4 (main file)

 * @file     program4.cpp

 * @author Akihiro Okumura

 * @date    2020.01.03

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

 

#include "program4.h"

 

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

 * Main function

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

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

{

                   int                                i = 1;

                   const char *program_name ="program4";

                   char           *file_i = NULL;           // input file

                   char           *file_o = NULL;          // output file

                   int                                matrix[10] = {1};          // color_matrix_int

 

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

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

 

                   for (int l = 0; l < 10; l++){

                                     matrix[l] = ( argc > i )? atoi(argv[i]) : 1;

                                     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, matrix)) {

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

                   }

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

 

                   return 0;

}

 

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

 *  main function of calculation

 *

 * @param inFile                          : [in] inputfile name

 * @param outFile                        : [in] outputfile name

 * @retval 0                                                      : success

 * @retval except 0                        : error code

 *

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

int main_process(char *infile, char *outfile, const char *program_name, int matrix[10])

{

                   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);

 

                   // color_matrix

                   fprintf(stderr, "process¥n");

                   color_matrix(rdatain, gdatain, bdatain, rdataout, gdataout, bdataout, width, height, bits, matrix);

 

                   // 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;

}

 

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

 * color_matrix

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

void color_matrix(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 matrix[10])

{

                   int              hp, vp;

                   int              pos;

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

                   int              r, g, b;

 

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

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

                                                        pos = vp*width + hp;

                                                        r = rdatain[pos];

                                                        g = gdatain[pos];

                                                        b = bdatain[pos];

                                                        rdataout[pos] = (unsigned short)clip((matrix[0] * r + matrix[1] * g + matrix[2] * b + matrix[9]/2)/matrix[9], 0, maxlevel);

                                                        gdataout[pos] = (unsigned short)clip((matrix[3] * r + matrix[4] * g + matrix[5] * b + matrix[9]/2)/matrix[9], 0, maxlevel);

                                                        bdataout[pos] = (unsigned short)clip((matrix[6] * r + matrix[7] * g + matrix[8] * b + matrix[9]/2)/matrix[9], 0, maxlevel);

                                     }        // hp loop end

 

                   }        // vp loop end

 

  return;

}

 

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 (program4.cpp) *****/

 

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

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

 * Calculate program4 (header file)

 * @file     program4.h

 * @author Akuhiro Okumura

 * @date    2020.01.03

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

 

#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 matrix[10]);

 

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 color_matrix(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 matrix[10]);

 

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

 

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

 

●program4のコンパイル

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

1Ubuntuを起動します。

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

 

●program4の実行

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

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

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

 ホワイトバランスと同様にRAWファイルをexiftooExifデータを調べます。α7siiの場合は、Color Matrixの項目がカラーマトリックスの値となります。マトリックスが整数なので、分母はG1024の値を使います。

  Exifデータ(カラーマトリックス

注)ソニーのα7siiで撮影したRAWExifデータです。

 

3.program4.exe <カラーマトリックス係数1〜9> <分母のG> <変換前の画像名>  <変換後の画像名>⏎とタイプしてプログラムを実行させます。<変換前の画像名>は、program3で処理したデモザイク後の画像を使います。

$ ./program4.exe 1331 -177 -130 -35 1213 -154 -36 -40 1100 1024 DSC00100_dm.ppm DSC00100_cm.ppm

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

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

  カラーマトリックス補正(program4)の処理結果

 少しですが、色が鮮明になりました。ゲインを上げて見ると違いが分かります。

 

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

デモザイク(program3)

  • 2020.06.29 Monday
  • 10:09

 ホワイトバランス補正が終わったら、次はデモザイクです。デモザイクのアルゴリズムは、最も簡単で基本的なデモザイクのバイリニアA(Interface誌2020年7月号特集 AI時代の画像処理教科書参照)を実装することにします。デモザイクはCFA(カラーフィルターアレイ)の配列に依存しますが、最もポピュラーな左上の(0,0)の座標がRRGGB配列にしています。配列が合わないようでしたら、プログラムを書き直すか、convertなどで画像を水平または垂直に1画素シフトすれば4通りの配列には対応出来ます。(斜めベイヤー配列などの特殊な配列は別途プログラミングする必要があります。)

 

デモザイク(program3)のプログラミング

 program2と同様に、program1とは別のprogram3というフォルダを作り、program1program1.cpp,program1.h,ppm.cpp,ppm.h,Makefileをコピーし、program1.cpp,program1.h, Makefileのファイル名と中身に記述してあるprogram1program3に全て変更。program3.cppprogram3.hを赤字のように変更します。

  デモザイク(program3.cpp

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

 * Calculate program3 (main file)

 * @file     program3.cpp

 * @author Akihiro Okumura

 * @date    2020.01.03

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

 

#include "program3.h"

 

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

 * Main function

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

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

{

                   int                                i = 1;

                   const char *program_name ="program3";

                   char           *file_i = NULL;           // input file

                   char           *file_o = NULL;          // output file

 

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

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

 

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

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

 

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

                   if (0 != main_process(file_i, file_o, program_name)) {

                                     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              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);

 

 

                   // demosaic

 

                   fprintf(stderr, "process¥n");

                   demosaic(rdatain, gdatain, bdatain, rdataout, gdataout, bdataout, width, height, bits);

 

                   // 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;

}

 

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

 * demosaic

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

void demosaic(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)

{

                   // cfa define

                   const int    CFAColor[4] = {0,1,2,3};                // cfa color dim -1:null 0:red 1:green1 2:green2 3:blue

                   int              hp, vp;

                   int              pos;

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

                   int              xpos1, ypos1;

                   int              pos1;

                   int              i;

 

                   double       dg, dr, db;

 

                   int              pd, cfa_color;

                   const int    xd[9] = { -1, 0, 1, -1, 0, 1, -1, 0, 1 };

                   const int    yd[9] = { -1, -1, -1, 0, 0, 0, 1, 1, 1 };

                   const double                r_filter[4][9] = {

                                     { 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0 },

                                     {0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.0},

                                     {0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0},

                                     {0.25, 0.0, 0.25, 0.0, 0.0, 0.0, 0.25, 0.0, 0.25}};

 

                   const double                g_filter[4][9] = {

 

                                     { 0.0, 0.25, 0.0, 0.25, 0.0, 0.25, 0.0, 0.25, 0.0 },

                                     {0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0},

                                     {0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0},

                                     {0.0, 0.25, 0.0, 0.25, 0.0, 0.25, 0.0, 0.25, 0.0}};

                   const double                b_filter[4][9] = {

                                     { 0.25, 0.0, 0.25, 0.0, 0.0, 0.0, 0.25, 0.0, 0.25 },

                                     {0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0},

                                     {0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.0},

                                     {0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0}};

 

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

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

                                                        pos = vp*width + hp;

                                                        pd = cfa_phase(hp, vp);

                                                        cfa_color = CFAColor[pd];

                                                        dr = 0.0;

                                                        dg = 0.0;

                                                        db = 0.0;

                                                        for (i = 0; i < 9; i++){

                                                                           xpos1 = hp + xd[i];

                                                                           ypos1 = vp + yd[i];

                                                                           if ( xpos1 >= 0 && xpos1 < width && ypos1 >= 0 && ypos1 < height ){

                                                                                             pos1 = ypos1*width + xpos1;

                                                                                         dr += (double)rdatain[pos1] * r_filter[cfa_color][i];

                                                                                              dg += (double)gdatain[pos1] * g_filter[cfa_color][i];

                                                                                              db += (double)bdatain[pos1] * b_filter[cfa_color][i];

                                                                              }

                                                         }

                                                        rdataout[pos] = clip(ifix(dr), 0, maxlevel);

                                                        gdataout[pos] = clip(ifix(dg), 0, maxlevel);

                                                        bdataout[pos] = clip(ifix(db), 0, maxlevel);

                                     }        // hp loop end

                   }        // vp loop end

 

                   return;

}

 

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

{

                   int              ans;

                   ans = a;

                   if(ans >= maxlevel) ans = maxlevel;

                   if(ans <= minlevel) ans = minlevel;

                   return       ans;

}

 

int cfa_phase(int hp, int vp)

 

{

                   const int    CFAPhase[4] = { 0, 1, 2, 3 };

                   int phase = CFAPhase[hp%2+ 2*(vp%2)];

                   return phase;

}

 

int ifix(double  vsum)

{

                   if(vsum > 0.0)        return((long)(vsum + 0.5));

                   else                  return((long)(vsum - 0.5));

}

 

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

 

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

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

 * Calculate program3 (header file)

 * @file     program3.h

 * @author Akuhiro Okumura

 * @date    2020.01.03

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

 

#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);

 

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 demosaic(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 clip(int a, int minlevel, int maxlevel);

int cfa_phase(int hp, int vp);

int ifix(double  vsum);

 

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

 

●program3のコンパイル

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

1Ubuntuを起動します。

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

 

●program3の実行

 program3.exe   <変換前の画像名>  <変換後の画像名>⏎とタイプしてプログラムを実行させます。<変換前の画像名>は、program2で処理したホワイトバランス後の画像を使います。

$ ./program3.exe DSC00100_wb.ppm DSC00100_dm.ppm

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

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

  デモザイク(program3)の処理結果

 暗いですが、ちゃんと色は付いてきました。ジッパーノイズや偽色があるのは、原始的なアルゴリズムなので仕方ありません。

 

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

ホワイトバランス補正(program2)

  • 2020.06.28 Sunday
  • 17:32

 カメラのオートホワイトバランスを取っても、全画面のヒストグラムや画面中のグレーを探すなどいろいろなアルゴリズムが存在します。ここでは、RAWExifデータに書かれているホワイトバランスの値からRAWデータにホワイトバランス補正をかけるプログラミングして見ます。

 

ホワイトバランス補正(program2)のプログラミング

 まず、program1とは別のprogram2というフォルダを作り、program1program1.cpp,program1.h,ppm.cpp,ppm.h,Makefileをコピーし、program1.cpp,program1.h, Makefileのファイル名と中身に記述してあるprogram1program2に全て変更します。

 次にprogram2.cpp program2.hを赤字のように変更します。

  ホワイトバランス補正(program2.cpp)​

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

 

#include "program2.h"

 

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

 * Main function

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

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

{

 

                   int                                i = 1;

 

                   const char *program_name ="program2";

                   int                                wbbc[6] = {1024, 1024, 1024, 0, 0, 0};                                  // whitebalance[r, g, b, br, bg, bb]

                   char           *file_i = NULL;           // input file

                   char           *file_o = NULL;          // output file

 

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

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

 

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

                   i++;

                   wbbc[1] = ( argc > i )? atoi(argv[i]) : 1024;

 

                   i++;

 

                   wbbc[2] = ( argc > i )? atoi(argv[i]) : 1024;

                   i++;

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

                   i++;

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

                   i++;

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

                   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, wbbc)) {

                                     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 wbbc[6])

{

                   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);

 

 

                   // wbalance

 

                   fprintf(stderr, "process¥n");

                   wbalance(rdatain, gdatain, bdatain, rdataout, gdataout, bdataout, width, height, bits, wbbc);

 

                   // 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;

}

 

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

 * wbalance

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

void wbalance(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 wbbc[6])

{

                   int              hp, vp;

                   int              pos;

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

 

 

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

 

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

 

                                                        pos = vp*width + hp;

 

                                                        rdataout[pos] = (unsigned short)clip((rdatain[pos] - wbbc[3]) * wbbc[0]/wbbc[1] + wbbc[3], 0, maxlevel);

                                                        gdataout[pos] = (unsigned short)clip((gdatain[pos] - wbbc[4]) * wbbc[1]/wbbc[1] + wbbc[4], 0, maxlevel);

                                                        bdataout[pos] = (unsigned short)clip((bdatain[pos] - wbbc[5]) * wbbc[2]/wbbc[1] + wbbc[5], 0, maxlevel);

                                     }        // hp loop end

                   }        // vp loop end

 

                   return;

}

 

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 (program2.cpp) *****/

 

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

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

 * Calculate program2 (header file)

 * @file     program2.h

 * @author Akuhiro Okumura

 * @date    2020.01.02

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

 

#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 wbbc[6]);

 

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 wbalance(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 wbbc[6]);

 

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

 

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

 

●program2のコンパイル

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

1Ubuntuを起動します。

2Ubuntuのターミナルからディレクトリーを選択し、makeとタイプしてコンパイルします。

$ cd work/../program2

$ ls

Makefile  ppm.cpp  ppm.h  program2.cpp  program2.h

$ make

g++  -O3 -Wall -I/usr/local/include -DLINUX  -c -o program2.o program2.cpp

g++  -O3 -Wall -I/usr/local/include -DLINUX  -c -o ppm.o ppm.cpp

g++  -O3 -Wall -I/usr/local/include -DLINUX -o program2 program2.o ppm.o

$ ls

Makefile  ppm.cpp  ppm.h  ppm.o  program2  program2.cpp  program2.h  program2.o

$

という表示が出て、program2 ppm.o program2.oというファイルが出来ていれば成功です。

 

●program2の実行

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

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

2exiftoolを使ってホワイトバランスの値を調べます

 RAWファイルをexiftoolにかけて、下のようにRAWExifデータを見ることが出来ます。α7siiの場合は、WB RGGB Levels Autoの項目が、カメラが求めたオートホワイトバランス値、Black Levelがブラックレベルの値となります。

  Exifデータ(ホワイトバランス)

$ cd ../work

$ exiftool DSC00100.ARW

注)ソニーのα7siiで撮影したRAWExifデータです。

3.program2.exe  <WR> <WG> <WB> <BR> <BG> <BB> <変換前の画像名>  <変換後の画像名>⏎とタイプしてプログラムを実行させます。WG,WG,WBはR,G,Bそれぞれのホワイトバランスの値、BR,BG,BBはR,G,Bそれぞれのブラックレベルの補正値を入力します。

$ ./program2.exe 2616 1024 1580 512 512 512 DSC00100.ppm DSC00100_wb.ppm

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

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

  ホワイトバランス補正(program2)の処理結果​

赤っぽくなりましたが、これで正解のようです。

 

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

C/C++のコンパイル方法と基本プログラム(ゲイン補正)の作成

  • 2020.06.27 Saturday
  • 14:36

 ここでは、プログラム演習の基本となる画像ファイルを読み出して、画像処理(ここではゲイン補正)を行い、また画像ファイルに書き出すプログラムを作成します。また、コンパイルに必要なmakeファイルの作成やコンパイラーのインストールなども演習し、コンパイルしたバイナリーの実行まで行います。まずは、windows(またはUbuntumkdir)でprogram1というディレクトリーを以前作ったworkと同列に作り、その中に「PPMフォーマット」で作ったppm.cppppm.hをコピーして入れます。

 

●基本プログラム(ゲイン補正)の記述(program1.cpp)

 続いてmain関数の記述です。ppmフォーマットで入力してゲインx30して、ppmフォーマットに出力するプログラムとヘッダーファイルを書いてみます。メイン関数の中でppmフォーマットの関数を呼び出して使います。

  基本プログラム(ゲイン補正)の記述(program1.cpp

/***************************************************
 * Calculate program1(main file)
 * @file    program1.cpp
 * @brief    in ppm -> program1 -> out ppm
 * @author    Akihiro Okumura
 * @date    2020.01.02
 ***************************************************/

#include "program1.h"

/*****************
 * Main function
 *****************/
int main(int argc, char *argv[])
{
    int        i = 1;
    const char    *program_name ="program1";
    char    *file_i = NULL;    // input file
    char    *file_o = NULL;    // output file

    fprintf(stderr,"<< %s >>¥n", program_name);
    fprintf(stderr,"2020.01.02 designed by A.Okumura¥n¥n");

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

    /***** Main process *****/
    if (0 != main_process(file_i, file_o, program_name)) {
        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    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);

    // gain
    fprintf(stderr, "process¥n");
    gain(rdatain, gdatain, bdatain, rdataout, gdataout, bdataout, width, height, bits);

    // 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;
}

/*****************************************************************
 * gain
 *****************************************************************/
void gain(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    hp, vp;
    int    pos;
    int    maxlevel = (0x01 << bits) - 1;
    int    gain = 30;
 
    for (vp = 0; vp < height; vp++){
        for (hp = 0; hp < width; hp++){
            pos = vp*width + hp;
            rdataout[pos] = (unsigned short)clip(rdatain[pos] * gain, 0, maxlevel);
            gdataout[pos] = (unsigned short)clip(gdatain[pos] * gain, 0, maxlevel);
            bdataout[pos] = (unsigned short)clip(bdatain[pos] * gain, 0, maxlevel);
        }        // hp loop end
    }        // vp loop end

    return;
}

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 (program1.cpp) *****/

 

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

/***************************************************
 * Calculate program1(header file)
  * @file    program1.h
 * @brief    in ppm -> program1 -> out ppm
 * @author    Akuhiro Okumura
 * @date    2020.01.02
 ***************************************************/

#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);

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 gain(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 clip(int a, int minlevel, int maxlevel);

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

 

●program1のmakeファイルの記述​

 続いてMakefileの記述です。

  program1のMakefile

#
# Makefile
#
# @author    Akihiro Okumura
# @date        2020.01.02
#MACH := $(shell uname -s)

CC = g++
CFLAGS  = -O3 -Wall -I/usr/local/include -DLINUX
HDRS     =
CLIBS   =
CPPFLAGS = $(CFLAGS)

TARGET   = program1
INSTALLDIR = $(HOME)/bin.$(MACH)

all: $(TARGET)

SRCS =     program1.cpp ppm.cpp

OBJS = $(SRCS:%.cpp=%.o)

program1 :  $(OBJS)
     $(CC)  $(CFLAGS) -o $@ $(OBJS) $(LIBS)
     
program1.o :  program1.cpp
ppm.o :  ppm.cpp

clean:
     rm -f $(OBJS)

# end of Makefile

左端から空白のある行は、空白文字ではなく、タブ文字(Tab)なので注意してください。

 

●program1のコンパイル

これで、必要なファイルは全て揃いました。次にコンパイルです。

1Ubuntuを起動します。

2.Ubuntuのターミナルからディレクトリーを選択し、make⏎とタイプしてコンパイルします。

$ cd work/../program1

$ ls

Makefile  ppm.cpp  ppm.h  program1.cpp  program1.h

$ make

g++  -O3 -Wall -I/usr/local/include -DLINUX  -c -o program1.o program1.cpp

g++  -O3 -Wall -I/usr/local/include -DLINUX  -c -o ppm.o ppm.cpp

g++  -O3 -Wall -I/usr/local/include -DLINUX -o program1 program1.o ppm.o

$ ls

Makefile  ppm.cpp  ppm.h  ppm.o  program1  program1.cpp  program1.h  program1.o

$

という表示が出て、program1 ppm.o program1.oというファイルが出来ていれば成功です。エラーが出ている場合は、修正してエラーメッセージが消えてコンパイル出来るまで繰り返します。

 

●program1の実行

 dcrawから出力されたRAWデータにゲイン×30を掛けて見ます。dcrawから出力されるRAWデータはpgmフォーマットで出力されますが、pgmフォーマットで入力して、ppmフォーマットに出力するプログラムはちょっと面倒なので、convertpgmフォーマットからppmフォーマットに変換して使います。ちなみに、convertpgmフォーマットからppmフォーマットへの変換を行うと、グレーの値は、R,G,Bにそれぞれ同じ値がコピーされます。

1.コンパイルして出来たprogram1dcrawで作ったディレクトリー(work)にコピーします。

2Ubuntuのターミナルからディレクトリーを選択し、convertを使ってpgmppmに変換します。

$ cd ../work

$ convert DSC00100.pgm DSC00100.ppm

$ls

DSC00100.pgm

DSC00100.ppm

$

 

3./program1  <変換前の画像名>  <変換後の画像名>とタイプしてプログラムを実行させます。

メッセージが出力されて出力ファイルが出来ていれば、処理終了です。

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

  program1の処理結果

$ ./program1 DSC00100.ppm DSC00100_x30.ppm

<< program1 >>

2020.01.02 designed by A.Okumura

 

input file ("DSC00100.ppm")

Get PPM file infomation(width=4256, heigt=2848, bits=16)

read ppm header

read ppm

process

write ppm

 

!!!!! Calculation Succeeded !!!!!

$ls

DSC00100.ppm

DSC00100_x30.ppm

$

 

 

  元のRAW画像

元ののRAW画像より明るくなっていることが分かります。

 これで基本プログラムのprogram1は完成です。次の演習からは主にこのprogram1をコピーし修正して作成します。

 

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

PPMフォーマット

  • 2020.06.25 Thursday
  • 13:57

●PPMフォーマットとは

 8bit以上の階調が扱え、最も簡単でプログラミングし易い非圧縮の画像フォーマットとして、一般にはあまり知られていませんがPPMフォーマットという画像フォーマットがあります。このPPMフォーマットを使って16bit階調の画像データを画像ファイルに出力すれば、あとは前項で説明したconvertを使ってフォーマット変換すれば、下図にように非圧縮の16bit階調で様々な画像フォーマットに変換することが出来、とても便利です。画像処理のプログラミングで様々なフォーマットに対応させるのはとても面倒なのですが、PPMフォーマットにさえ対応すれば、後はconvertで変換出来るのです。

    多階調画像の出入口PPMフォーマット

 PPMフォーマットは、PNM (PPM / PGM / PBM)画像フォーマットの中の一つで、全体を総称して、PNM (Portable aNyMap)フォーマットと呼ばれるものですが、格納するフォーマットによって、呼び名が異なっています。モノクロ(白黒2色)の画像を格納する PBM (Portable BitMap)フォーマット、グレースケールの画像を格納するPGM (Portable GrayMap)フォーマット、フルカラーの画像を格納するPPM (Portable PixMap)フォーマット、という区別になっています。なお、アルファチャンネルには対応していません。それぞれは別の画像フォーマットというよりは、同一の画像フォーマットのモードが違うもの、といった方がしっくり来るのですが、拡張子もそれぞれ.ppm/.pgm/.pbmと分かれているのが通常です。全部を合わせた、pnmという拡張子も定義されていますが、あまり見かけたことはありません。また、このPNMを拡張したフォーマットで、アルファチャンネルにも対応したPAM (Portable Arbitrary Map)というフォーマットもあります。

 

●PPMフォーマット:ヘッダー

 まずは、このヘッダー領域のフォーマットについて説明します。

 ヘッダーは以下の様な構造になっています。

P<x>

# comment

<width> <height>

<max>

 

 はじめのPxと書いているところは、ファイル形式の種別を示すマジックナンバーとなっています。

        PNMフォーマットのマジックナンバー

マジックナンバー

フォーマット

拡張子

画像の種類

データ形式

P1

PBM

.pbm

モノクロ(白黒2色)

テキスト

P2

PGM

.pgm

グレースケール

テキスト

P3

PBM

.ppm

フルカラー

テキスト

P4

PBM

.pbm

モノクロ(白黒2色)

バイナリ-

P5

PGM

.pgm

グレースケール

バイナリ-

P6

PBM

.ppm

フルカラー

バイナリ-

 

 テキスト形式は、ASCII形式、バイナリー形式は、RAW形式と呼ばれることもあります。 テキストで記述された、ある意味で制約のゆるいフォーマットですが、このマジックナンバーだけは必ずファイルの先頭に記述する必要があります。

 続いて、マジックナンバーの次の行に書いている#から始まる行はコメントです。コメントは何もここにだけ現れるとは限らず、テキストの領域であればどこに現れてもよいことになっています。 極端な話では、ヘッダーだけでなく、テキスト形式の場合は画像データ中に現れても仕様違反ではありません。コメントの範囲を厳密に言うと、#で始まり、次の最初の改行、つまり¥nか、¥rが現れるまで、がコメントになります。コメントには画像を出力したツールの名前などが書かれていたりしています。

 コメントの次の行には画像の幅と高さを10進数で記述されています。多くの場合、幅と高さが1行の中に書かれ、間にスペースが挟まれていますが、前述のとおり、幅と高さの間に改行を入れたり、マジックナンバーと同じ行にあっても間違いではありません。

 そして最後に、輝度の最大値を10進数で記述します。この行は2値しか取らないPBM形式には不要なため存在しませんが、PGMフォーマットとPPMフォーマットは指定する必要があります。一般に利用されるRGB値などの最大値は、8bitの最大値である255ですが、この画像フォーマットでは任意の数字を指定出来ます。例えば9と書けば0910階調で表現することも出来ます。もともとは上限255、つまり8bitまでの対応となる仕様でしたが、現在、仕様が拡張され上限65535で、16bit階調を扱える仕様になっています。

 

●PPMフォーマット:画像データ

 ヘッダー情報に続いて配置されるのが画像データです。詳細は各画像フォーマット毎に説明して行きますが、共通しているのは、データの格納順は横書き文章と同一で、左上から右側へ走査しながら下に向かう形で格納されています。また、テキスト形式は1行の長さは70文字以下であることが推奨されています。ですが、実際には70文字以上あっても読み込んでくれるツールがほとんどです。

P1PBMフォーマット)

 白黒2色のテキスト形式。0が白、1が黒として、順にテキストで格納されます。 このフォーマットで混乱しやすいのが、ピクセルの表現に使用される文字は012種類しか無いため、区切り文字しての空白は必ずしも必要ありません。隙間なく01が連なっていてもよいし、間に空白があっても良いことになっています。読み込む側を作ることを考えると、どちらでも良いという曖昧な仕様はかえって面倒になります。

P2PGMフォーマット)

 グレースケールのテキスト形式。指定した最大値までの数値を10進数のテキストで順に格納します。数値の桁数は決まっていないため、数値と数値の間には区切り文字が必要になります。

P3PPMフォーマット)

フルカラーのテキスト形式。指定した最大値までの数値で、RGBの順に10進数のテキストで順に格納します。数値の桁数は決まっていないため、数値と数値の間には区切り文字が必要になります。

P4PBMフォーマット)

 白黒2値のバイナリー形式。0が白、1が黒とするのはテキスト形式と同じですが、1bitで表現可能なので、上位ビットから順に、1byte8ピクセル分格納します。つまり、左から「白白白白黒黒黒黒」であれば、0x0Fと格納されます。また、画像の幅が8の倍数で無い場合は、最後の1byteに余地が残りますが、次の行のデータは詰め込みません。つまり、幅4の画像で「白白白白」、次の行が「黒黒黒黒」であれば0x0f1byteにまとめてしまうのではなく、0x00,0xf0と行ごとに分離します。

P5PGMフォーマット)

 グレースケールのバイナリー形式、指定した最大値までの数値を1ピクセル1byteで順に格納します。例えば最大値が15だとすると、1ピクセルを表現するのに4bitあればよく、 1byte2ピクセル分格納出来ますが、そのようなことは行わず、必ず1byteを使用します。 また、最大値が256以上の場合2byte必要になりますが、その場合はビッグエンディアンで格納されます。

P6PPMフォーマット)

 フルカラーのバイナリー形式、指定した最大値までの数値で、RGBの順に1byteずつ、1ピクセル3byteで順に格納します。P5と同じで3byte以下で表現出来る場合もまとめるようなことは行いません。また、最大値が256以上の場合も同様に、ビッグエンディアンの2byteで格納されます。

 

●PPMフォーマットの関数プログラム

 ここからはプログラム演習の始まりです。実際にプログラムを書いて見ましょう。ここでは、ppmフォーマットで入力してゲインx30して、ppmフォーマットに出力するプログラムを書いてみます。プログラムはMakefileを使う方法とVisual Studioを使う方法とどちらでもコンパイル出来るような書き方をしています。後で使い回しし易い様に関数(サブルーチン)で記述します。

 ただ、この関数は、ファイル操作の関数などを多く使っていて、C/C++として面倒な操作を沢山行っているためにC/C++の初心者には少し難しいと思います。C/C++を使った画像処理でハードルが高く、難しくしているのはこの画像ファイルの入出力部分で、多くの人が挫折しています。この画像処理アルゴリズムの開発とあまり関係のないこの部分の関数はブラックボックスにしてライブラリーとして扱えば良く、後で興味があったら勉強してみる程度で良いと思います。

ppmフォーマットの関数(サブルーチン)の記述

 ppmフォーマットの関数は、マジックナンバーP3P6ppmフォーマットなので、P3P68bit16bitまで対応出来るように記述しました。次にサンプルプログラム(関数)と、そのヘッダープログラムを載せます。このプログラムは演習のprogram110の全てに使います。拡張子は〜.cC言語の拡張子ですが、C++の拡張子〜.cppにした方が、Visual Studioの併用やC++のライブラリーなども使えるので後で便利です。なので実際はCで記述しているのですが〜.cppというC++の拡張子を使います。また、ヘッダーファイルの拡張子は、〜.hになります。

      PPMフォーマットの関数(ppm.cpp)

/***************************************************
 * ppm
 * @file    ppm.cpp
 * @author    Akihiro Okumura
 * @date    2020.03.04
 ***************************************************/

#include "ppm.h"

/*****************************************************************
 * read_ppm_header
 *****************************************************************/
void read_ppm_header(char *file, int *width, int *height, int *ppm_pn, int *bits)
{
    FILE *fp;

    if ( (fp = fopen( file, "rb" )) == NULL ){
        fprintf(stderr, "¥nCan't open inputfile %s¥n", file);
        fclose(fp);
        exit(0);
    }
    fprintf(stderr, "input file (¥"%s¥")¥n", file);

    char s[1024];
    int w, h;

    // P3・P6(ppm)のみ対応
    do {
        if (fgets(s, 1023, fp) == NULL){
            fclose(fp);
            exit(-1);
        }
    } while ( s[0] == '#' );

    if ( s[0] == 'P' && (s[1] == '3' || s[1] == '6') ){
        if ( s[1] == '3' ) *ppm_pn = 3;
        if ( s[1] == '6' ) *ppm_pn = 6;
    } else {
        return;
    }

    // サイズ(width, height)
    do {
        if (fgets(s, 1023, fp) == NULL){
            fclose(fp);
            exit(-1);
        }
    } while (s[0] == '#');
    sscanf( s, "%d %d", &w, &h);
    // 頭出し
    for ( int line=1; line <3; line++ ){
        if ( w == 0 && h == 0 ){
            do {
                if (fgets(s, 1023, fp) == NULL){
                    fclose(fp);
                    exit(-1);
                }
            } while (s[0] == '#');
            sscanf( s, "%d %d", &w, &h);
        }
    }
    *width = w;
    *height = h;

    // レベル最大値
    int data = 0;
    do {
        if (fgets(s, 1023, fp) == NULL){
            fclose(fp);
            exit(-1);
        }
    } while (s[0] == '#');
    sscanf( s, "%d", &data );
    *bits = 0;
    for (int i = 1; i <= 16; i++){
        if ((data >= (0x01 << (i-1))) && (data < (0x01 << i))){
            *bits = i;
        }
    }
    if (*bits == 0){
        fprintf( stderr, "warning : unknown level = %d¥n", data );
        fclose(fp);
        exit(0);
    }
    fprintf(stderr, "Get PPM file infomation(width=%d, heigt=%d, bits=%d)¥n", *width, *height, *bits);

    fclose(fp);
    return;
}

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

    if ( (fp = fopen( file, "rb" )) == NULL ){
        perror( file );
        exit(0);
    }

    char s[1024];
    int ppm_pn = 0;
    int w = 0;
    int h = 0;
    int bits = 0;

    // P3・P6(ppm)のみ対応
    do {
        if (fgets(s, 1023, fp) == NULL){
            fclose(fp);
            exit(-1);
        }
    } while (s[0] == '#');

    if ( s[0] == 'P' && (s[1] == '3' || s[1] == '6') ){
        if ( s[1] == '3' ) ppm_pn = 3;
        if ( s[1] == '6' ) ppm_pn = 6;
    } else {
        return;
    }
    // 頭出し
    for ( int line=1; line <3; line++ ){
        if ( w == 0 && h == 0 ){
            do {
                if (fgets(s, 1023, fp) == NULL){
                    fclose(fp);
                    exit(-1);
                }
            } while (s[0] == '#');
            sscanf( s, "%d %d", &w, &h);
        }
    }
    // レベル最大値
    int data = 0;
    do {
        if (fgets(s, 1023, fp) == NULL){
            fclose(fp);
            exit(-1);
        }
    } while (s[0] == '#');
    sscanf( s, "%d", &data );
    bits = 0;
    for (int i = 1; i <= 16; i++){
        if ((data >= (0x01 << (i - 1))) && (data < (0x01 << i))){
            bits = i;
        }
    }
    if (bits == 0){
        fprintf(stderr, "warning : unknown level = %d¥n", data);
        fclose(fp);
        exit(0);
    }

    int dno = width * height;
    int words;
    int frame_size;

    if ( ppm_pn == 3 ){
        unsigned short *r, *g, *b;
        int data[3];

        r = r_data;
        g = g_data;
        b = b_data;

        // フレーム読みだし
        for ( int i = 0; i < dno; i++ ){
            for ( int j = 0; j < 3; j++ ){
                if (fscanf(fp, "%s", s) == EOF){
                    fclose(fp);
                    exit(-1);
                }
                    
                //コメント行をスキップ
                while(s[0] == '#'){
                    if (fgets(s, sizeof(s), fp) == NULL){
                        fclose(fp);
                        exit(-1);
                    }
                    if (fscanf(fp, "%s", s) == EOF){
                        fclose(fp);
                        exit(-1);
                    }
                }
                data[j] = atoi(s);
            }

            //        fprintf( stderr, "%d %d %d¥n", data[0], data[1], data[2] );

            *r = (unsigned short)data[0];
            *g = (unsigned short)data[1];
            *b = (unsigned short)data[2];

            r++;
            g++;
            b++;
        }
    }
    if ( ppm_pn == 6 ){
        // フレーム読出し
        words = word_size( bits );
        frame_size = dno * 3 * words;
        if ( words == 1 ){
            unsigned short *ip;
            if ( libuf_init(frame_size) ){
                fclose(fp);
                exit(-1);
            }
            ip = libufp;
            if ((int)fread(ip, sizeof(unsigned char), frame_size, fp) != frame_size) {
                 fprintf(stderr, " ERROR2 (readf_ppm) : read file %s ¥n", file);
                fclose(fp);
                exit(-1);
            }
            unsigned short *r, *g, *b;
            unsigned char *d;

            r = r_data;
            g = g_data;
            b = b_data;
            d = (unsigned char *)libufp;

            // フレーム読みだし
            for ( int i=0; i<dno; i++ ){
                *r = (unsigned short)*d++;
                *g = (unsigned short)*d++;
                *b = (unsigned short)*d++;

                r++;
                g++;
                b++;
            }
        } else {
            unsigned short *ip;
            if ( libuf_init(frame_size) ){
                fclose(fp);
                exit(-1);
            }
            ip = libufp;
            if ((int)fread(ip, sizeof(unsigned short), frame_size/2, fp) != frame_size/2) {
                 fprintf(stderr, " ERROR2 (readf_ppm) : read file %s ¥n", file);
                fclose(fp);
                exit(-1);
            }

            unsigned short *r, *g, *b;
            unsigned short *d;

            r = r_data;
            g = g_data;
            b = b_data;
            d = libufp;

            // フレーム読みだし
            for ( int i=0; i<dno; i++ ){
                *r = endian(*d++);
                *g = endian(*d++);
                *b = endian(*d++);

                r++;
                g++;
                b++;
            }
        }
    }

    fclose(fp);
    return;
}

/*****************************************************************
 * write_ppm
 *****************************************************************/
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)
{
    FILE *fp;

    char header[21];
    char comment[1024];
    int max_code  = (0x01 << bits) - 1;
      
//    Open output Ppm File
    if (( fp = fopen( file, "wb" )) == NULL ){
        printf( "PPM File cannot not make¥n" );
        exit(1);
    }

//    PPM_FILE_HEADER
    snprintf( header, sizeof(header), "P%1d¥n", ppm_pn );
    fputs( header, fp );
    snprintf( comment, sizeof(comment), "# used: %s¥n", program_name );
    fputs( comment, fp );
    snprintf( comment, sizeof(comment), "# %s¥n", file );
    fputs( comment, fp );
    snprintf( header, sizeof(header), "%d %d¥n%d¥n", width, height, max_code );
    fputs( header, fp );

    int dno = width * height;
    int words;
    int frame_size;

    if ( ppm_pn == 3 ){
        unsigned short *r, *g, *b;
        int data[3];

        r = r_data;
        g = g_data;
        b = b_data;

        // フレーム書き込み
        for ( int i = 0; i < dno; i++ ){
            data[0] = (int)*r;
            data[1] = (int)*g;
            data[2] = (int)*b;

            fprintf( fp, "%d %d %d¥n", data[0], data[1], data[2] );

            r++;
            g++;
            b++;
        }
    }
    if ( ppm_pn == 6 ){
        words = word_size( bits );
        frame_size = dno * 3 * words;
        // フレーム書き込み
        if ( words == 1 ){
            unsigned short *r, *g, *b;

            r = r_data;
            g = g_data;
            b = b_data;

            unsigned char *ip;
            if ( libuf_init(frame_size) ){
                fclose(fp);
                exit(-1);
            }
            ip = (unsigned char *)libufp;    
            for ( int i = 0; i < dno; i++ ){
                *ip++ = (unsigned char)*r;
                *ip++ = (unsigned char)*g;
                *ip++ = (unsigned char)*b;

                r++;
                g++;
                b++;
            }
            ip = (unsigned char *)libufp;
            if ((int)fwrite(ip, sizeof(unsigned char), frame_size, fp) != frame_size) {
                 fprintf(stderr, " ERROR2 (writef_ppm) : write file %s ¥n", file);
                fclose(fp);
                exit(-1);
            }
        } else {
            unsigned short *r, *g, *b;

            r = r_data;
            g = g_data;
            b = b_data;

            unsigned short *ip;
            if ( libuf_init(frame_size) ){
                fclose(fp);
                exit(-1);
            }
            ip = libufp;    
            for ( int i = 0; i < dno; i++ ){
                *ip++ = endian(*r);
                *ip++ = endian(*g);
                *ip++ = endian(*b);

                r++;
                g++;
                b++;
            }
            ip = libufp;
            if ((int)fwrite(ip, sizeof(unsigned short), frame_size/2, fp) != frame_size/2) {
                 fprintf(stderr, " ERROR2 (writef_ppm) : write file %s ¥n", file);
                fclose(fp);
                exit(-1);
            }
        }
    }

    fclose(fp);
    return;
}

unsigned short endian( unsigned short d )
{
    unsigned short data = d;
    data = ((data << 8) | (data >> 8 ));
    return data;
}

int    word_size( int ws )
{
    int d;

    if ( ws <= 5 )
        d = ws;
    else 
        d = (ws+7)/8;     /* 8=1, 10=2, 16=2 */

    return d;
}

int libuf_init( int size )
{
    if (( libufp = (unsigned short *)realloc( libufp, size )) == NULL ){
        perror( "libuf_init" );
        return -1;
    }
    return 0;
}

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

 

   PPMフォーマットのヘッダーファイル(ppm.h)

/***************************************************
 * Calculate ppm(header file)
 * @file    ppm.h
 * @brief    in ppm -> ppm -> out ppm
 * @author    Akuhiro Okumura
 * @date    2020.03.04
 ***************************************************/

#ifdef LINUX
#else
#pragma warning(disable:4996)    //    fopen
#define snprintf    _snprintf
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

/***** struct *****/
unsigned short endian( unsigned short d );
int    word_size( int ws );
static unsigned short *libufp;
int libuf_init( int size );

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

 このppm.cppとppm.hはこの後のprogram1〜5全てに用います。

 

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

プログラミング演習

  • 2020.06.25 Thursday
  • 12:03

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

 ここでは、

・PPMフォーマットの説明とその関数プログラミング

・PPMフォーマットの関数を用いた基本プログラムの作成とそのコンパイル方法

・ホワイトバランス補正

・デモザイク

・カラーマトリックス補正

・ガンマ補正

についてです。

 カメラ信号処理を一つ一つプログラミングして行くことで、どのような処理を行って、どのように画が変わっていくかを演習して行きます。

 

      プログラミング演習

プログラム名

機能、目的

program1

ゲイン補正、基本プログラムの作成、コンパイル方法

program2

ホワイトバランス補正

program3

デモザイク

program4

カラーマトリックス補正

program5

ガンマ補正

 program2〜5はprogram1をコピーして作成します。program25を実行させることにより、実際のRAW現像を行うことになります。

Google Search Consoleの設定

  • 2020.06.04 Thursday
  • 10:14

ブログはhtmlファイルを入れたり、修正したりできないので、Google Search Consoleの設定の設定はできないと思っていたのですが、グッグって見ると出来るようです。トライしてみました。

 

ステップ1:まずはGoogle Search Consoleをアクセス

https://search.google.com/search-console/about?hl=ja

 

ステップ2:gmailのアカウントでログイン

 

ステップ3:プロパティを追加

 

ステップ4:URLプレフィックスにURLを登録

 

ステップ5:所有権の確認(HTMLタグの方法を選択)

HTMLファイルを使う方法とHTMLタグをHTMLファイルに書き加える方法があるが、ブログの場合は、HTMLファイルを入れられないので、HTMLタグの方法を選択

 

ステップ6:HTMLタグをコピー

 

ステップ7:ブログの管理者ページ

「HTMLを編集」をクリックして、編集と書いてありますが、テンプレートを使っている場合は編集できないので、テンプレートをコピーしてから編集します。

 

ステップ8:テンプレートをコピー、ブログデザインを変更

適応しているブログデザインを複製に「別名を入力」を入れてコピーを作成、作成したブログデザインを選択し、「選択したブログデザインを使用」をクリックしてブログデザインを変える。

 

ステップ9:HTMLを編集して、HTMLタグを書き加える。

<head> から</head>の間に、ステップ6の「HTMLタグをコピー」でコピーしたHTMLタグをコピーして書き加える。

 

ステップ10:Google Search ConsolenのHTMLタグのメニューで「確認」を押す

カメラの解像力

  • 2020.05.23 Saturday
  • 10:03

 近年のスマホの解像度と実際の画質を見ても、解像度(画素数)が実際の解像力を表していないのではないかと疑問に思っている人は多いのではないでしょうか?ここでは、あえて解像力(実際の解像力)と解像度(画素数)を切り分けて、カメラの解像力を決めている要因についてお話したいと思います。

 

        カメラの解像力

 

 上記のように、カメラの解像力は、画素数(解像度)だけでなくいろいろな要素で実際の解像力が決まってきます。下に表でまとめてみました。

 

       カメラの解像力を決める要因

構造

要因

説明

イメージセンサー

画素数(解像度)

解像度を決める基本的な要素であるが、解像力はこれだけでは決まらない。

センサーサイズ

(画素サイズ)

回折などの光学的な要因による解像力劣化に関しては、センサー(画素)の物理的な大きさが必要。感度に関しても大きい方が有利。

感度

画素サイズが最も大きな要因であるが、他にも開口率やカラーフィルターの透過率、オンチップマイクロレンズなども影響する。感度を表す指標としてはISO感度があるが、ゲインでも調整できるので、同じISO感度でもノイズの大きさは異なる。

光学ローパスフィルター

無い方が解像力が高いが、モアレや偽色などの劣化が起きやすくなる。

レンズ

フォーカス

基本的なことですが、フォーカスが合っていないと解像力は落ちる。

MTF

レンズの解像力を表す値の事。球面収差などが解像力の劣化を起こす。

f値(絞り)

レンズの明るさを示す値。レンズが明るい方(f値が低い)が解像力が高く、f値が大きい方が回折ボケの影響で解像力は低くなる。

被写界深度

フォーカスが合っているように見える範囲のこと。絞りの値(f値)によって浅くなったり深くなったりする。被写界深度が深くなり、フォーカスの合う範囲が広くなると解像力は落ちる傾向にある。

シャッター

シャッタースピード

(振動、ブレ)

撮影時の手振れや振動は動きボケとなり、解像力劣化にもなる。撮影時はしっかりした三脚や除振台などで撮影するか高速シャッター撮影が望ましい。

画像処理

デモザイク

デモザイクの性能によっても解像力に差がでる。偽色と解像力ではトレードオフの関係があり、高性能なデモザイク処理ではそのトレードオフの関係を改善している。

画像処理

シャープネスや超解像処理、ノイズ除去などによっても解像力(解像感)は変わってくるが、あくまでも波形の傾きを立たせるだけで、実際の解像度本数までは変わらない。

codec

codecでも圧縮率によっては影響して、高周波成分をカットするために解像力が劣化する。ノイズと組み合わさっての劣化も大きい。

 

 単純にフォーカスが合った部分の解像力を最も高く撮影したいのならば、カメラの選定や撮影方法は以下のようになります。

・画素数(解像度)…高いもの

・イメージセンサーサイズ…大きいもの(現時点では中判デジカメが最大)

・感度…画素サイズが大きく、裏面照射型CMOS、RYYG、白黒などが感度の高いセンサー

・光学ローパスフィルター…レスのもの

・レンズ…MTFが高いもの。単焦点レンズ。F値の小さい明るいレンズ

・画像処理…非圧縮RAW記録が出来るもの。高度なデモザイクや画像処理。

・撮影…レンズは開放、シャッタースピードは長く、ISO感度は低く、三脚を用いてマニュアルフォーカスで撮影。暗い場所では明るい照明を用いる。

 

 かなり巨大で高価なカメラをしっかりとした三脚を使って、プロの撮影現場なみの撮影設備が必要になります。

 

 被写界深度が問題で、遠くも近くも解像力を高く撮影したいとなると更に難しくなり、被写体の明るさなどによっても最適解が変わってしまいます。

 

 さらにドローンのように、動きや振動がある環境で、しかも重量制限から軽いカメラのみとなるとまた条件が異なり、また別な工夫が必要になるのかも知れません。

カメラの種類

  • 2020.05.17 Sunday
  • 12:06

 一言でカメラと言ってもいろいろあります。赤外線カメラなども含めるといろいろなカメラが世の中にあります。カラーで撮影できるディジタルカメラだけでもミラーレスだけでなく、シネマから産業用までいろいろあるのです。

 

 カラーで撮影できるディジタルカメラをまとめて見ました。

 

                          カメラの種類

                                                                                                 (カラー撮影)

カメラの種類

特徴

シネマカメラ

PLマウント(マウントがしっかりしている。フォーカスの距離が正確。ズームレンズは使わずレールを使う。)。業務用三脚。

放送局用カメラ

主にズームレンズを使用(生放送などではレンズは取り替えないため)。手振れなどを起こさないように重い。業務用三脚。

中判デジカメ

ブローニー版のデジカメ版。6cmのセンサーはまだ登場していないがオーバー35mmの53.9mm×40.4mmまでは登場している。

ディジタル一眼

各社バヨネット式マウント(脱着しやすいが、安定性と精度に問題)。35mmフルサイズのイメージセンサーまで搭載可能。

ミラーレス

ディジタル一眼に比べて、ミラーが無い分焦点距離を短く、小型化できる。厳密には、ディジタル一眼とレンズの互換性はない。

アクションカメラ

GoProなど超小型、超広角を売りにしたデジカメ。スマホとミラーレスの中間的存在で、ドローン用などにも使われる。

スマホ

8Kやクワッドベイヤー、RYYBなどの最新技術が使われているが、レンズの大きさやセンサーサイズなどの物理的な制約も大きいため、解像度や感度などの真の性能は不明。

監視カメラ

CマウントかCSマウントが基本。屋外や暗視にも対応するため高ダイナミックレンジと広角、長時間録画が特徴。

ドライブレコーダー

アクションカメラと同様に超広角で、監視カメラと同様の高ダイナミックレンジ、長時間録画が特徴。

産業用カメラ

録画機能のないカメラ。CマウントやSマウント(M12マウント)など様々な種類がある。Sマウントは4K以上でマウントの精度が問題になってきている。

とカラーで撮影できるだけでもいろいろありますね。