画像処理事始


はじめに

無料で自由に利用できる、高機能な画像処理パッケージ OpenCV が提供されていますので、あえて画像処理に
関するプログラムを提供する必要は無いかもしれません。 ですが、C言語を使って、画像処理を学習したい方が
利用出来る様に、簡単な雛形を用意してみました。
C言語を使ってプログラムを書く場合は、ハードウエアの知識が有ればより理解しやすいのですが、特に知識が
無くても開発はできます。 多分知識の差は、コンパイラの最適化にヒントを提供できるかどうかだと思います。

 ・ C言語を使う上で押えておきたいH/Wの知識
 ・ 画像処理用のCプログラムの雛形
に関する情報を提供できればと思っております。
補足事項:以下のプログラムで利用できる BMPファイルは 24or32 bit 無圧縮のWindows形式のみ

サンプルプログラム #1 のソースコードと実行形式  

(Windows版
実行形式を含む)
 2011/03/12
ファイル名 機能 nd5sum
bmpLoad.zip bmpファイル表示プログラム e85dfd24512abf6ba52ae9aa25806024
imageProcessing.zip
imageProcessing.zip
画像処理の雛形プログラム c5edca6bc97ea0231d277af10c9c936c
05362ae58e191fb525f7e65090d8d97a
nega.zip
nega.zip
ネガ画像作成プログラム 1bca225202f38add5896a99a00e818e6
a26fcbc9c7cf8194d34e977e91ee63ee
ave3x3.zip
ave3x3.zip
平滑化フィルタプログラム 1328be48f9e30870013494c2291f8d0e
bce0137ec6caa3dce07536390d1e4534

説明に先立ち、まずサンプルプログラムを用意しました。

   bmpLoad.zip
   ・画像処理結果として作成されたBMPファイルの目視確認用プログラム (ファイル名の表示も必要な場合)
    "Drag & Drop の利用方法"で説明したGUIプログラムの、DragAndDropExArg.c をベースに、画像の読み込みと
    表示機能を追加したものです。 プログラムは、C言語で記述され、コメントはSJISで記載されています。
    実行形式は、Windows XP SP3 環境での動作を確認しています。 本プログラムのみ Windows 専用
    BMPファイル自体の構成に関しては、 BMP ファイルの構造に関する資料 を参照して下さい。

   imageProcessing.zip
   ・画像処理用のプログラムの雛形(入力されたカラーBMPの複製を作成)
    24/32ビットのBMPファイルを読み込み、画像を1次元の配列としてアクセス可能にし、同時に処理結果を格納する
    1次元の配列を生成して、画像処理プログラム(サブルーチン)を呼び出します。
    画像処理プログラムの先頭部で、画像と処理結果を格納する1次元配列に対して、2次元配列としてのアクセスを
    可能にする、2次元配列用のインデックスを生成します。
    サブルーチン内では、入力画像の各画素データを、処理結果を格納する配列にコピーします。 
    サブルーチンの終了ステータスを 0 (正常) で終了すると、処理結果を32ビットのBMPファイルとして保存します。
    実行形式は、Windows XP SP3 環境での動作を確認しています。

   nega.zip
   ・画像処理用の雛形を元に、入力されたカラーBMPのネガ画像を作成するプログラム
    24/32ビットのBMPファイルを読み込み、画像を1次元の配列としてアクセス可能にし、同時に処理結果を格納する
    1次元の配列を生成して、画像処理プログラム(サブルーチン)を呼び出します。
    画像処理プログラムの先頭部で、画像と処理結果を格納する1次元配列に対して、2次元配列としてのアクセスを
    可能にする、2次元配列用のインデックスを生成します。
    サブルーチン内では、入力画像の各画素データの、ネガ(反転)データを処理結果を格納する配列に記録します。 
    サブルーチンの終了ステータスを 0 (正常) で終了し、処理結果を32ビットのBMPファイルとして保存します。
    実行形式は、Windows XP SP3 環境での動作を確認しています。

   ave3x3.zip
   ・画像処理用の雛形を元に、入力されたカラーBMPの3x3画素の平滑画像を作成するプログラム
    24/32ビットのBMPファイルを読み込み、画像を1次元の配列としてアクセス可能にし、同時に処理結果を格納する
    1次元の配列を生成して、画像処理プログラム(サブルーチン)を呼び出します。
    画像処理プログラムの先頭部で、画像と処理結果を格納する1次元配列に対して、2次元配列としてのアクセスを
    可能にする、2次元配列用のインデックスを生成します。
    サブルーチン内では、入力画像のR,G,Bの各チャンネル毎に、各画素とその周辺の8画素(計9画素)の平均値を、
    計算して、処理結果を格納する配列に記録します。 (sobel、Laplacianフィルターやコンボリューションの参考例)
    サブルーチンの終了ステータスを 0 (正常) で終了し、処理結果を32ビットのBMPファイルとして保存します。
    実行形式は、Windows XP SP3 環境での動作を確認しています。

サンプルプログラム #2 のソースコードと実行形式  

(Windows版
実行形式を含む)
 2011/03/14
ファイル名 機能 nd5sum
color2gray.zip
color2gray.zip
カラー画像を濃淡画像に変換 87357dae1b49eacdcd828c190d5cd498
8ab666ad4e08189f14b0e22b75f9872e
sobel.zip
sobel.zip
Sobel フィルタプログラム 1898ae27f6c633a6d0b2e70185836f03
3fb8682ad3ac91f904801d12785119bb
laplacian.zip
laplacian.zip
Laplacianフィルタプログラム 1cf7c9fd88c409bcc9c2950d049918bf
88de45ea2d39ae81a6f972121bbf1184

説明に先立ち、まずサンプルプログラムを用意しました。


   color2gray.zip
   ・画像処理用の雛形を元に、入力されたカラーBMPから濃淡画像を作成するプログラム
    24/32ビットのBMPファイルを読み込み、画像を1次元の配列としてアクセス可能にし、同時に処理結果を格納する
    1次元の配列を生成して、画像処理プログラム(サブルーチン)を呼び出します。
    画像処理プログラムの先頭部で、画像と処理結果を格納する1次元配列に対して、2次元配列としてのアクセスを
    可能にする、2次元配列用のインデックスを生成します。
    サブルーチン内では、入力画像の各画素データ(R、G、B)から、濃淡画像データ(変換式参照)を作成し、結果を
    出力用の配列に記録します。 出力は32ビットR、G、B形式、各色要素に同じ値を指定して濃淡画像を表記する
     変換式: 0.299*R + 0.587*G + 0.114*B ⇒ Y  (高速整数演算の場合: y = (306*r + 601*g + 117*b)>>10)
    サブルーチンの終了ステータスを 0 (正常) で終了し、処理結果を32ビットのBMPファイルとして保存します。
    実行形式は、Windows XP SP3 環境での動作を確認しています。

   Sobel.zip
   ・画像処理用の雛形を元に、入力されたカラーBMPから濃淡画像を作成し、Sobel フィルターを施すプログラム
    24/32ビットのBMPファイルを読み込み、画像を1次元の配列としてアクセス可能にし、同時に処理結果を格納する
    1次元の配列を生成して、画像処理プログラム(サブルーチン)を呼び出します。
    画像処理プログラムの先頭部で、画像と処理結果を格納する1次元配列に対して、2次元配列としてのアクセスを
    可能にする、2次元配列用のインデックスを生成します。
    サブルーチン内では、入力画像のR,G,Bの値から、濃淡情報を生成します。 この濃淡データに対して、 Soble の
    オペレーションを行い、処理結果の最小値を0に、最大値を255になる様に変換します。
    出力用配列のRGB値に変換した値(0 ~ 255)を記録します。 
    サブルーチンの終了ステータスを 0 (正常) で終了し、処理結果を32ビットのBMPファイルとして保存します。
    実行形式は、Windows XP SP3 環境での動作を確認しています。

   Laplacian.zip
   ・画像処理用の雛形を元に、入力されたカラーBMPから濃淡画像を作成し、Laplacian フィルターを施すプログラム
    24/32ビットのBMPファイルを読み込み、画像を1次元の配列としてアクセス可能にし、同時に処理結果を格納する
    1次元の配列を生成して、画像処理プログラム(サブルーチン)を呼び出します。
    画像処理プログラムの先頭部で、画像と処理結果を格納する1次元配列に対して、2次元配列としてのアクセスを
    可能にする、2次元配列用のインデックスを生成します。
    サブルーチン内では、入力画像のR,G,Bの値から、濃淡情報を生成します。 この濃淡データに対して、 Soble の
    オペレーションを行い、処理結果の最小値を0に、最大値を255になる様に変換します。
    これはサンプル処理なので、ガンマ補正(γ=0.6) も行います。(本来の処理では不要だが学習用) まず、
    変換に使用するL:UT(lookup table)を作成します。入力値(0 ~ 255)、出力値(0 ~ 255)で、変換テーブルがγ。 
    Laplacian値を、0 ~ 255の範囲に変換後、ガンマー変換用のLUTを使ってカンマ補正し、出力配列に記録します。 
    サブルーチンの終了ステータスを 0 (正常) で終了し、処理結果を32ビットのBMPファイルとして保存します。
    実行形式は、Windows XP SP3 環境での動作を確認しています。

サンプルプログラム #3 のソースコードと実行形式  

(Windows版
実行形式を含む)
 2011/05/03
ファイル名 機能 nd5sum
labeling.zip
labeling.zip
二値画像の8連結ラベリング a6bebe2498c7c9972f18ae05b0b4e186
edfc0d58d957ea2cbf78cc7a8c096be6
labeling4.zip
labeling4.zip
二値画像の4連結ラベリング bc664e7176746eab9c9347dbc5d2da03
1a1aaa4e03aa6965d94a1ca621e33e33
labeling_x64.zip
labeling_x64.zip
二値画像のラベリング(x64版)
8連結,4連結の実行形式のみ
64ビット用バイナリ 2017/03/03 New
768d28a0cac805c2766239658772c1df

説明に先立ち、まずサンプルプログラムを用意しました。

このラベリングプログラムは、原理の理解を目的にした実装の為、複雑な画像のラベリングには時間を要します

   labeling.zip   (ラベリング処理の8連結、4連結共通コア部分)
   ・画像処理用の雛形を元に、入力されたBMP(二値画像)に対して、8連結のラベリング処理を行うをプログラム
    24/32ビットのBMPファイルを読み込み、画像を1次元の配列としてアクセス可能にし、同時に処理結果を格納する
    1次元の配列を生成して、画像処理プログラム(サブルーチン)を呼び出します。
    ラスタースキャン方式のラベリング処理では、処理対象画素の、上下左右1画素に対して連結性(8箇所)の評価
    をしますが、処理の重複(ラベリング処理の完了している画素の評価のみで良い)を除くと、4箇所の評価で完了
    します。 処理対象画素ラベル値の決定により、処理対象画素以前までは異なっている対象物と認識していた
    領域が、単一の対象物を構成する領域である事が判明する事があり、この場合にはどちらかのラベル番号に、
    統一(displacementにて対応 "この関数はインライン展開される")する必要が生じます。
    また、処理対象画素の周囲の画素を参照する事は、参照する画像の欠落する周辺部では処理が破綻する事を
    意味します。この問題は、無限の大きさを持つ背景の中に画像を配置すれば回避出来ますが、必要十分条件を
    満たす実装は、画像の上下左右に1画素分の背景を拡張し、ラベリング処理を本来に画像部に対してのみ行う
    方法です。画像の周辺部の処理では、本来欠落するデータを参照した場合に、背景データ(ハードウエア処理時
    も同様)を参照する事になり、単一のアルゴリズムで正しいラベリングが可能になります。
    入力画像の大きさが、縦横がそれぞれ、LX、LY の場合、LX+2、LY+2 の大きさのエリアを確保し、エリアの境界
    の値を全て、背景を表す値(0)にし、その内側に入力画像を展開します。展開後、画像データに対し、ラベリング
    処理を施し、結果を 関数名.cfg 関数名.lbl ファイルとして保存します。
    cfg、lbl ファイルの詳細は、"1B ラベルファイルの構成"を参照して下さい。
    ラベルデータは単なる自然数で可読性が劣るので、同時に擬似カラー化し、画像としての確認を可能にします。
    ラベルデータ(0~0xffffff)から擬似カラーデータ変換は可逆変換を採用していますので、擬似カラーデータから、
    ラベルデータ値を知る事が出来ます。変換方法は、擬似カラーデータをラベルデータに変換するプログラム
    unsigned int pseudoColor2Int( unsigned int v ) を使用してください。("1B ラベルファイルの構成"を参照)
    ラベルデータの形式に関しては、"1B ラベルファイルの構成"を参照してください。 またラベルデータを利用する
    例に関しては、"画像データとラベルデータの処理用サンプルプログラム(C言語)の実施例"を参照下さい。
    実行形式は、Windows XP SP3 環境での動作を確認しています。
    このラベリングソフトを使った処理手順のチュートリアル(md5sum: e96c4278e6716a121e7bc6a5f271f42e)
    "画像処理のための高速ラベリングソフト+α"のチュートリアル(詳細はこちらを参照して下さい)相当の処理

   labeling4.zip   (ラベリング処理の8連結、4連結共通コア部分)
   ・画像処理用の雛形を元に、入力されたBMP(二値画像)に対して、4連結のラベリング処理を行うをプログラム
    24/32ビットのBMPファイルを読み込み、画像を1次元の配列としてアクセス可能にし、同時に処理結果を格納する
    1次元の配列を生成して、画像処理プログラム(サブルーチン)を呼び出します。
    ラスタースキャン方式のラベリング処理では、処理対象画素の、上下左右1画素に対して連結性(4箇所)の評価
    をしますが、処理の重複(ラベリング処理の完了している画素の評価のみで良い)を除くと、2箇所の評価で完了
    します。 処理対象画素ラベル値の決定により、処理対象画素以前までは異なっている対象物と認識していた
    領域が、単一の対象物を構成する領域である事が判明する事があり、この場合にはどちらかのラベル番号に、
    統一(displacementにて対応 "この関数はインライン展開される")する必要が生じます。
    また、処理対象画素の周囲の画素を参照する事は、参照する画像の欠落する周辺部では処理が破綻する事を
    意味します。この問題は、無限の大きさを持つ背景の中に画像を配置すれば回避出来ますが、必要十分条件を
    満たす実装は、画像の上下左右に1画素分の背景を拡張し、ラベリング処理を本来に画像部に対してのみ行う
    方法です。画像の周辺部の処理では、本来欠落するデータを参照した場合に、背景データ(ハードウエア処理時
    も同様)を参照する事になり、単一のアルゴリズムで正しいラベリングが可能になります。
    入力画像の大きさが、縦横がそれぞれ、LX、LY の場合、LX+2、LY+2 の大きさのエリアを確保し、エリアの境界
    の値を全て、背景を表す値(0)にし、その内側に入力画像を展開します。展開後、画像データに対し、ラベリング
    処理を施し、結果を 関数名.cfg 関数名.lbl ファイルとして保存します。
    cfg、lbl ファイルの詳細は、"1B ラベルファイルの構成"を参照して下さい。
    ラベルデータは単なる自然数で可読性が劣るので、同時に擬似カラー化し、画像としての確認を可能にします。
    ラベルデータ(0~0xffffff)から擬似カラーデータ変換は可逆変換を採用していますので、擬似カラーデータから、
    ラベルデータ値を知る事が出来ます。変換方法は、擬似カラーデータをラベルデータに変換するプログラム
    unsigned int pseudoColor2Int( unsigned int v ) を使用してください。("1B ラベルファイルの構成"を参照)
    ラベルデータの形式に関しては、"1B ラベルファイルの構成"を参照してください。 またラベルデータを利用する
    例に関しては、"画像データとラベルデータの処理用サンプルプログラム(C言語)の実施例"を参照下さい。
    実行形式は、Windows XP SP3 環境での動作を確認しています。

サンプルプログラム #4 のソースコードと実行形式  

(Windows版
実行形式を含む)
 2011/06/26
ファイル名 機能 nd5sum
bmpCalc1.zip BMP形式の画像間での演算 ae63df77d9024b17641a0ab39b776922
op4bmp.zip BMP形式の画像間での演算 49f1b1a07bceefc9a8bfa296b09661ae

説明に先立ち、まずサンプルプログラムを用意しました。


   op4bmp.zip
   ・カラーBMP画像間(画像同士又は、画像と数値)で算術或いは論理演算を行うプログラム
    動的2次元配列、動的3次元配列の確保を実装したインクルードファイル allocArray.h
    alloc2D、alloc3D、alloc2Darray、alloc3Darray、calloc2Darray、calloc3Darray、malloc2Darray、malloc3Darray、
    で確保した領域(へのポインタ)は、使用後 free() 関数を用いて開放してください。
    24/32ビットのBMPファイルを読み込み、カラー画像を2次元の配列としてアクセス可能にし、同時に処理結果を
    格納する2次元の配列を生成して、画像処理プログラム(サブルーチン)を呼び出します。
    動的2次元配列(2次元配列として管理するインデックス部とデータを格納するデータ領域)が生成されます。
    データを格納するデータ領域に直接アクセスする場合は、配列の最初のアドレス(&arry[0][0])から、横×縦個の
    連続したデータ並びとして参照します。単項演算では、入力画像の反転(ネガポジ)と特定の値の設定が行えます。
    画像間演算(画像同士の演算或いは、画像と数値の演算)には算術演算と論理演算の二種類があります。
    論理演算では、AND、OR、EXOR が行え、算術演算では、ADD、SUB、MUL、DIV の演算が行えます。
    数値を指定する場合は、0~255 0xff の範囲。 set コマンド用に数値のチェックは意図的行っていないので、
    利用時には注意してください。 ( set コマンドは、BGRA構成の画素を4バイト整数として見做して処理)
    カラー画像は、RGBそれぞれが符号なし 8 ビットなので、0~255 の値しか保持できません、乗算、加算処理時に
    結果が 255 を超えた場合は、255 がセットされます。減算処理時に値が負になった場合は、0 がセットされます。
    サブルーチンの終了ステータスを 0 (正常) で終了し、処理結果を32ビットのBMPファイルとして保存します。
    実行形式は、Windows XP SP3 環境での動作を確認しています。

    補足事項
    ポインターのサイズは、対象の如何に関わらず一律の大きさとなります。そのサイズは、システムがアクセスする
    事が可能な任意の場所を指定出来る大きさ(32ビット環境なら4バイト、64ビット環境なら8バイト)となります。
    void のポインタも、関数のポインタも、ポインタのポインタも大きさは同じです。


チュートリアル

ラベリングデータを利用した画像処理例
md5sum: e96c4278e6716a121e7bc6a5f271f42e Tutorial


次回予告

まずは、プログラムの公開を行います。
次回は、詳しく説明を行います。


補足事項

プログラムは、windows.h を必要としないように記述さえれていますが、以下のプログラムがパスする環境が必要です
#include <stdio.h>
#include <stdlib.h>

#pragma pack(push,1)
typedef struct PIXEL { unsigned char B, G, R, A; } PIXEL ;
#pragma pack(pop)

#pragma pack(push,2)
typedef struct HEADER {
    unsigned short bfType;          // 0x4D42 BMP identification 0x42='B', 0x4D='M'
    unsigned int   bfSize;          // ??  
    unsigned short bfReserved1;     //  0  
    unsigned short bfReserved2;     //  0  
    unsigned int   bfOffBits;       // 54  sizeof(HEADER)
    unsigned int   biSize;          // 40 sizeof(biSize ~ biClrImportant)
    signed int     biWidth;         // lx 
    signed int     biHeight;        // ly 
    unsigned short biPlanes;        //  1 
    unsigned short biBitCount;      // 32 
    unsigned int   biCompression;   //  0 
    unsigned int   biSizeImage;     // ?? 
    signed int     biXPelsPerMeter; //  0 
    signed int     biYPelsPerMeter; //  0 
    unsigned int   biClrUsed;       //  0 
    unsigned int   biClrImportant;  //  0 
} HEADER ;
#pragma pack(pop)

void environmentalConditionCheck()
{
    if( (sizeof(int)!=4) || (sizeof(PIXEL)!=4) || (sizeof(HEADER)!=54) ) {
        fprintf( stderr, "\nBad environmental condition.\n" ) ;
        fprintf( stderr, "\tsizeof(int)    must be  4 Byte. (%d)\n", sizeof(int) ) ;
        fprintf( stderr, "\tsizeof(PIXEL)  must be  4 Byte. (%d)\n", sizeof(PIXEL) ) ;
        fprintf( stderr, "\tsizeof(HEADER) must be 54 Byte. (%d)\n", sizeof(HEADER) ) ;
        exit(1) ;
    }
}

int main(){ environmentalConditionCheck(); return 0; }



go to TopPage go to CategoryTop