以下、図面を参照して本実施形態の一例を詳細に説明する。図1には、画像処理装置として機能することが可能なコンピュータ10が示されている。なお、このコンピュータ10は、複写機、プリンタ、ファクシミリ装置、これらの機能を兼ね備えた複合機、スキャナ、写真プリンタ等のように内部で画像処理を行う必要のある任意の画像取扱機器に組み込まれていてもよいし、パーソナル・コンピュータ(PC)等の独立したコンピュータであってもよく、更にPDA(Personal Digital Assistant)や携帯電話機等の携帯機器に組み込まれたコンピュータであってもよい。
コンピュータ10はCPU12、メモリ14、表示部16、操作部18、記憶手段としての記憶部20、画像データ供給部22及び画像出力部24を備えており、これらはバス26を介して互いに接続されている。コンピュータ10が上述した画像取扱機器に組み込まれている場合、表示部16や操作部18としては、画像取扱機器に設けられたLCD等から成る表示パネルやテンキー等を適用することができる。また、コンピュータ10が独立したコンピュータである場合、表示部16や操作部18としては、当該コンピュータに接続されたディスプレイやキーボード、マウス等を適用することができる。また、記憶部20としてはHDD(Hard Disk Drive)が好適であるが、これに代えてフラッシュメモリ等の他の不揮発性記憶手段を用いることも可能である。
また、画像データ供給部22は処理対象の画像データを供給できるものであればよく、例えば紙や写真フィルム等の記録材料に記録されている画像を読み取って画像データを出力する画像読取部、通信回線を介して外部から画像データを受信する受信部、画像データを記憶する画像記憶部(メモリ14又は記憶部20)等を適用することができる。また、画像出力部24は画像処理を経た画像データ又は該画像データが表す画像を出力するものであればよく、例えば画像データが表す画像を紙や感光材料等の記録材料に記録する画像記録部、画像データが表す画像をディスプレイ等に表示する表示部、画像データを記録メディアに書き込む書込装置、画像データを通信回線を介して送信する送信部を適用することができる。また、画像出力部24は画像処理を経た画像データを単に記憶する画像記憶部(メモリ14又は記憶部20)であっても構わない。
図1に示すように、記憶部20には、CPU12によって実行される各種のプログラムとして、メモリ14等のリソースの管理やCPU12によるプログラムの実行の管理、コンピュータ10と外部との通信等を司るオペレーティングシステム30のプログラム、コンピュータ10を本発明に係る画像処理装置として機能させるための画像処理プログラム群34、CPU12が上記画像処理プログラム群を実行することで実現される画像処理装置に対して所望の画像処理を行わせる各種のアプリケーション32のプログラム(図1ではアプリケーションプログラム群32と表記)が各々記憶されている。
画像処理プログラム群34は、前述した各種の画像取扱機器や携帯機器を開発する際の開発負荷を軽減したり、PC等で利用可能な画像処理プログラムを開発する際の開発負荷を軽減することを目的として、各種の画像取扱機器や携帯機器、PC等の各種機器(プラットフォーム)で共通に使用可能に開発されたプログラムである。画像処理プログラム群34によって実現される画像処理装置は、アプリケーション32からの画像処理指示書(実行する画像処理の内容を記述したファイルであって、本発明の画像処理情報に相当する。具体例は後述する)に従って構築指示に従い、画像処理を行う画像処理部を構築し、前記画像処理部によって画像処理を行うが(詳細は後述)、画像処理プログラム群34は、所望の画像処理を行う画像処理部(所望の構成の画像処理部)の構築を指示したり、構築された画像処理部による画像処理の実行を指示するためのインタフェースをアプリケーション32に提供している。このため、内部で画像処理を行う必要のある任意の機器を新規開発する等の場合にも、前記画像処理を行うプログラムの開発に関しては、当該機器で必要とされる画像処理を上記のインタフェースを利用して画像処理プログラム群34に行わせるアプリケーション32を開発するのみで済み、実際に画像処理を行うプログラムを新たに開発する必要が無くなるので、開発負荷を軽減することができる。
また、画像処理プログラム群34によって実現される画像処理装置は、前述のように、アプリケーション32からの画像処理指示書による構築指示に従い、画像処理部を構築し、構築した画像処理部によって画像処理を行うので、例えば画像処理対象の画像データの色空間や1画素当たりのビット数が不定であったり、実行すべき画像処理の内容や手順・パラメータ等が不定である場合にも、アプリケーション32が画像処理指示書により画像処理部の再構築を指示することで、画像処理装置(画像処理部)によって実行される画像処理を、処理対象の画像データ等に応じて柔軟に変更することができる。
以下、画像処理プログラム群34について説明する。本実施の形態では、画像処理プログラム群34は、オブジェクト指向プログラミング言語により実装されている。図1に示すように、画像処理プログラム群34は画像処理クラスライブラリ36と、処理構築部42のプログラムと、処理管理部46のプログラムと、指示書解釈実行部48のプログラムと、ジェネリックファクトリクラスライブラリ50と、形式変換クラスライブラリ54と、ファクトリ生成関数ライブラリ58と、に大別される。詳細は後述するが、本実施形態に係る処理構築部42は、アプリケーションからの指示により、例として図2に示すように、予め定められた画像処理を行う1つ以上の画像処理モジュール38Aと、個々の画像処理モジュール38Aの前段及び後段の少なくとも一方に配置され画像データを記憶するためのバッファを備えたバッファモジュール40と、がパイプライン形態又はDAG(Directed Acyclic Graph:有向非循環グラフ)形態で連結されて成る画像処理部80を構築する。なお、画像処理モジュール38Aには、実際に画像データに対して画像処理を行う画像処理エンジンを有さないモジュールであって、画像処理モジュール38Aの画像処理に必要な情報を提供するサポートモジュール38Bが接続される場合もある。本実施の形態では、画像処理モジュール38A及びサポートモジュール38Bを総称して処理モジュール38と呼称する。
画像処理部80を構成する個々の処理モジュール38の実体はCPU12によって実行されCPU12で予め定められた画像処理を行わせるためのプログラム、又は、CPU12によって実行されCPU12により図1に図示されていない外部の画像処理装置(例えば専用画像処理ボード等)に対する処理の実行を指示するためのプログラムであり、上述した画像処理クラスライブラリ36には、予め定められた互いに異なる画像処理(例えば入力処理やフィルタ処理、色変換処理、拡大・縮小処理、スキュー角検知処理、画像回転処理、画像合成処理、出力処理等)を行う複数種の画像処理モジュール38Aやサポートモジュール38Bが実体化される前の画像処理クラスのコード(プログラム)が各々登録されている。画像処理クラスを実体化したものが処理モジュール38である。なお、処理モジュール38をオブジェクトと呼称する場合もある。
個々の画像処理モジュール38Aは、図示は省略するが、画像データに対する画像処理を予め定められた単位処理データ量ずつ行う画像処理エンジンと、画像処理モジュール38Aの前段及び後段のモジュールとの画像データの入出力及び画像処理エンジンの制御を行う制御部から構成されている。個々の画像処理モジュール38Aにおける単位処理データ量は、画像の1ライン分、画像の複数ライン分、画像の1画素分、画像1面分等を含む任意のバイト数の中から、画像処理エンジンが行う画像処理の種類等に応じて予め選択・設定されており、例えば色変換処理やフィルタ処理を行う画像処理モジュール38Aでは単位処理データ量が1画素分とされ、拡大・縮小処理を行う画像処理モジュール38Aでは単位処理データ量が画像の1ライン分又は画像の複数ライン分とされ、画像回転処理を行う画像処理モジュール38Aでは単位処理データ量が画像1面分とされ、画像圧縮伸長処理を行う画像処理モジュール38Aでは単位処理データ量が実行環境に依存するNバイトとされている。
また、画像処理クラスライブラリ36には、画像処理エンジンが実行する画像処理の種類が同一でかつ実行する画像処理の内容が異なる画像処理モジュール38Aの画像処理クラスも登録されている(図1では、この種の画像処理モジュールを「モジュール1」「モジュール2」と表記して示している)。例えば拡大・縮小処理を行う画像処理モジュール38Aについては、入力された画像データを1画素おきに間引くことで50%に縮小する縮小処理を行う画像処理モジュール38A、入力された画像データに対して指定された拡大・縮小率で拡大・縮小処理を行う画像処理モジュール38A等の複数の画像処理モジュール38Aが各々用意されている。また、例えば色変換処理を行う画像処理モジュール38Aについては、RGB色空間をCMY色空間へ変換する画像処理モジュール38Aやその逆へ変換する画像処理モジュール38A、L*a*b*色空間等の他の色空間変換を行う画像処理モジュール38Aが各々用意されている。
また、画像処理モジュール38Aの制御部は、画像処理エンジンが単位処理データ量ずつ処理するために必要な画像データを入力するために、自モジュールの前段のモジュール(例えばバッファモジュール40)から画像データを単位読出データ量ずつ取得し、画像処理エンジンから出力される画像データを単位書込データずつ後段のモジュール(例えばバッファモジュール40)へ出力する(画像処理エンジンで圧縮等のデータ量の増減を伴う画像処理が行われなければ単位書込データ量=単位処理データ量となる)か、画像処理エンジンによる画像処理の結果を自モジュールの外部へ出力する(例えば画像処理エンジンがスキュー角検知処理等の画像解析処理を行う場合、画像データに代えてスキュー角検知結果等の画像解析処理結果が出力されることがある)処理を行うが、画像処理クラスライブラリ36には、画像処理エンジンが実行する画像処理の種類及び内容が同一で、上記の単位処理データ量や単位読出データ量、単位書込データ量が異なる画像処理モジュール38Aのクラスも登録されている。例えば、先程は画像回転処理を行う画像処理モジュール38Aにおける単位処理データ量を画像1面分と説明したが、同じ画像回転処理を行う画像処理モジュール38Aで単位処理データ量が画像の1ライン分又は画像の複数ライン分であるものが画像処理クラスライブラリ36に含まれていても良い。
また、前述したように、画像処理モジュール38Aの画像処理に必要なサポートモジュール38Bが画像処理モジュール38Aに接続される場合もある。例えば、画像処理モジュール38Aが画像データを読み出すモジュールであった場合に、どの画像データのファイルを読み出すのかを指定した文字列を提供するサポートモジュール38B等が挙げられる。サポートモジュール38Bは、バッファモジュール40に連結されることはない(図2(A)も参照。)。図1では図示は省略されているが、このサポートモジュール38Bのクラスも画像処理クラスとして画像処理クラスライブラリ36に登録される。
また、画像処理部80を構成する個々のバッファモジュール40は、コンピュータ10に設けられたメモリ14からオペレーティングシステム30を通じて確保されたメモリ領域で構成されるバッファと、バッファモジュール40の前段及び後段のモジュールとの画像データの入出力及びバッファの管理を行うバッファ制御部から構成されている。個々のバッファモジュール40のバッファ制御部もその実体はCPU12によって実行されるプログラムであり、画像処理クラスライブラリ36にはバッファ制御部のプログラムも登録されている(図1ではバッファ制御部のプログラムを「バッファモジュール」と表記して示している)。
また、アプリケーション32からの画像処理指示書による指示に従って画像処理部80を構築する処理構築部42は、図1に示すように複数種のモジュール生成部44(以下、クリエータ44と呼称する場合もある)から構成されている。複数種のモジュール生成部44は互いに異なる画像処理に対応しており、アプリケーション32からの画像処理指示書に応じて起動される(呼び出される)ことで、対応する画像処理を実現するための画像処理モジュール38A、サポートモジュール38B及びバッファモジュール40から成るモジュール群を生成(クラスを実体化)する処理を行う。なお、図1ではモジュール生成部44の一例として、画像処理クラスライブラリ36に登録されている個々の画像処理モジュール38Aが実行する画像処理の種類に対応するモジュール生成部44を示しているが、個々のモジュール生成部44に対応する画像処理は、複数種の画像処理モジュール38Aによって実現される画像処理(例えばスキュー角検知処理と画像回転処理から成るスキュー補正処理)であってもよい。必要とされる画像処理が複数種の画像処理を組み合わせた処理である場合、複数種の画像処理の何れかに対応するモジュール生成部44が順次起動される。順次起動されたモジュール生成部44により、必要とされる画像処理を行う画像処理部80が構築されることになる。本画像処理装置は、アプリケーション32が直接処理モジュール38を生成するのではなく、アプリケーション32の指示により図3のファクトリ70(本発明のラッパーに相当する)を生成してファクトリ70からモジュール生成部44を呼び出して処理モジュール38を生成する構成となっている。ファクトリ70は、モジュール生成部44に対するラッパーとしての機能を有し、モジュール生成部44で実行される関数(具象関数)の引数の違いがファクトリ70で吸収されるようにしている。
図3は、ファクトリ70に関するオブジェクト指向モデルを示すモデル図である。ここでは、オブジェクト指向の表記方法に則って、矩形の上段にクラス名を、下段にはメソッドを記載し、矢印により継承等を示した。また、ここでは、Scaleという拡大縮小処理を行う画像処理モジュール38Aを生成するモジュール生成部44を呼び出すファクトリ70を図示した。
図3に示すように、モジュール生成部44は、ファクトリ70により呼び出される。ファクトリ70は、ファクトリ生成関数60により生成される。ファクトリ70は、抽象ファクトリクラス51を継承する具象ファクトリクラス(ジェネリックファクトリクラス52)を実体化したものであり、モジュール生成部44を呼び出すとともに、該モジュール生成部44に対して、画像処理指示書で指定された引数(処理モジュール38が実行する関数で用いる値)を引き渡す機能を有する。ここで、画像処理モジュール38Aを生成するモジュール生成部44の各々が実行する関数名(例えば、Engine())は各々同じであるが、引数(引数の個数及び引数型の少なくとも一方)が異なっているものもある。また、サポートモジュール38Bを生成するモジュール生成部44の各々の関数名(例えば、Create())も互いに同じだが、引数(引数の個数及び引数型の少なくとも一方)が異なっているものもある(図5の各モジュール生成部44のメソッドも参照。)。従って、本実施の形態では、ファクトリ70の生成の際に、以下の工夫を施している。
ジェネリックファクトリクラス52では、引数の種類(以下、「引数型」と呼称する)が抽象化されて(図3に示すように、引数型が不定の「void*(voidポインタ)」としている)定義されている。引数型に応じて引数のサイズが定まるが、このように抽象化された状態では、引数型が不定なため、モジュール生成部44で解釈可能に具体化(具象化)する必要がある。従って、ジェネリックファクトリクラス52からファクトリ70を生成する際に、引数型を具体化して生成する。
また、本実施の形態では、ジェネリックファクトリクラス52では、使用する引数がどのようなサイズであってもよいように、各引数を、各引数の先頭アドレス値を格納したポインタの配列で取り扱うようにしている。しかしながら、モジュール生成部44が各引数をポインタ型で渡されたものを使用できるとは限らず、モジュール生成部44の種類によっては、参照型、或いは値型でないと使用できない場合もある。従って、モジュール生成部44に対しては、ポインタ渡し、値渡し、参照渡しなど、モジュール生成部44が取り扱い可能な形式で引数を渡す必要がある。以下、引数を渡すときの型を上記引数型と区別するため「形式」と呼称する。従って、モジュール生成部44で使用可能な形式でモジュール生成部44に引数を渡せるようにファクトリ70を生成する。
まず、引数型については、本実施の形態では、引数の個数分の配列要素(ポインタ)を有する配列構造を定義し、各配列要素に対して各引数の種類(引数型)を指定することにより具象引数型に変換する。図3に示す「EngineFactory4」という名称のファクトリ70では、Arg0〜Arg3までの4つの配列要素に対して、順にManager、Engine、Float、Floatの4つの引数型が指定されている。例えば、Managerは、処理管理、Engineは画像処理エンジン、Floatは、浮動小数点の変数を示す。
更に、モジュール生成部44に引数を渡す際には、ポインタで指定された各引数をモジュール生成部44に渡すときの形式(例えば、値、参照、ポインタ)に変換する必要があるが、この形式の変換には、形式変換クラス56が使用される。形式変換クラス56には、例えば、ポインタをポインタに変換する「ToPointer」、ポインタを参照に変換する「ToReference」、ポインタを値に変換する「ToValue」等がある。この形式変換クラス56が引数の配列要素の各々に対して指定された状態でファクトリ70が生成される。図3に示す「EngineFactory4」という名称のファクトリ70では、引数型「Manager」の引数に対して、「ToReference」の形式変換クラス56が指定され、引数型「Engineポインタ」の引数に対して、「ToValue」の形式変換クラス56が指定され、引数型「Float」の2つの引数に対して、「ToValue」の形式変換クラス56が指定されている。
図10に、ジェネリックファクトリクラス52のコーディング例を示す。図示したジェネリックファクトリクラス52は、引数が4個のファクトリ70のテンプレートとして用いられるものである。
符号100の部分で、ジェネリックファクトリクラス52のテンプレート引数が定義されている。具体的には、ジェネリックファクトリクラス52から呼び出されるモジュール生成部44をCreatorとし、更にそのモジュール生成部44の戻り値型をResultとし、4つの引数、及び各引数に対する形式変換クラス56(Resolver)が定義されている。符号102の部分で、このクラスが、EngineFactory4というクラス名のジェネリックファクトリクラス52であることが宣言される。符号104において、4つの具象引数のポインタの構造体が引数の配列として宣言されている。
符号110の部分では、仮想関数が宣言されている。符号112の部分では、引数の構造体の先頭アドレスに何も入っていなければ、NULLを返す、いわゆるエラー処理が行われる。符号114の部分では、符号104で宣言された構造体で表された引数の配列要素に引数型を定義して、抽象引数型ポインタのvoid*から、具象引数のポインタの構造体のポインタへ変換する処理が行われる。符号116及び符号118の部分で、ファクトリ70が実行する処理(モジュール生成部44の呼出、形式変換クラス56による形式変換処理)が宣言されている。
図11に、ファクトリ生成関数60のコーディング例を示す。符号200の部分で、load_ReadPNGFactoryという名称のファクトリ生成関数60が定義されており、符号202で、new演算子により、EngineFactory3というジェネリックファクトリクラス52をテンプレートクラスとしてオブジェクトが生成されるように記述されている。符号204には、3つの引数の引数型と形式とが定義されている。ファクトリ生成関数60は、ユーザにより作成されて、事前にファクトリ生成関数ライブラリ58に登録される。
なお、図1に示すように、ジェネリックファクトリクラス52は、ジェネリックファクトリクラスライブラリ50に登録されており、形式変換クラス56は、予め形式変換クラスライブラリ54に登録されている。また、ファクトリ生成関数60は、ファクトリ生成関数ライブラリ58に登録されている。
画像処理装置に新規の機能を追加する場合には、該機能を含む画像処理部70を構築する前に、事前に、該新規の機能を提供する処理モジュール38の画像処理クラスを画像処理クラスライブラリ36に追加登録し、処理構築部42にモジュール生成部44を追加登録し、これに対応するファクトリ生成関数60をファクトリ生成関数ライブラリ58に追加登録しておく必要がある。
ファクトリ70がモジュール生成部44を呼び出す(call)際には、ファクトリ70からモジュール生成部44に、引数型及び形式(形式変換クラス56)の指定により具象化された状態で引数が渡される。これにより、モジュール生成部44は、対応する画像処理クラスを実体化したオブジェクト(処理モジュール38)を生成する。
なお、ファクトリ70では、引数型及び形式を変換するだけであるため、Webサービスを利用することで新規機能追加を行う場合に比べて、(通信が発生しないため)呼出しオーバーヘッドは増加しない。
なお、画像処理モジュール38Aを生成するモジュール生成部44は、必要に応じて当該画像処理モジュール38Aの前段及び後段に連結するバッファモジュール40を生成する。最終的に、ファクトリ70により呼び出されたモジュール生成部44により生成された処理モジュール38及びバッファモジュール40が連結された画像処理部80が構築される。
そして、図1に示す処理管理部46は、上記構築された画像処理部80における画像処理の実行を制御したり、画像処理部80の各モジュールによるメモリ14や各種のファイル等のコンピュータ10のリソースの使用を管理したり、画像処理部80で発生したエラーを管理したりする。
本実施の形態では、処理構築部42によって構築される画像処理部80は、画像処理部80を構成する個々の画像処理モジュール38Aが、画像1面分よりも小さいデータ量を単位として後段へ画像データを引き渡しながら並列に画像処理を行うように動作する(ブロック単位処理と称する)ことも、前段の画像処理モジュール38が画像1面分の画像データに対する画像処理を完了した後に、後段の画像処理モジュール38が画像1面分の画像データに対する画像処理を行うように動作する(面単位処理と称する)ことも可能とされており、処理管理部46のプログラムとして、画像処理部80にブロック単位処理を行わせるためのプログラムと、画像処理部80に面単位処理を行わせるためのプログラムが各々用意されている。
ここで、処理管理部46の画像処理の実行制御について簡単に説明する。まず、ブロック単位処理を行う場合について説明する。ここでは、サポートモジュール38Bの説明は省略して一連の画像処理の流れに着目して説明する。処理管理部46は、構築された画像処理部80のうち最後段の画像処理モジュール38Aに処理要求を入力する(図4の(1)も参照)。図4に示す画像処理部80において、処理管理部46から最後段の画像処理モジュール38A4に処理要求が入力されると、画像処理モジュール38A4の制御部は前段のバッファモジュール403に読出要求を入力する(図4の(2)参照)。このとき、バッファモジュール403のバッファには画像処理モジュール38A4が読出可能な有効データ(画像データ)が記憶されていないので、バッファモジュール403のバッファ制御部は処理管理部46にデータ要求を入力する(図4の(3)参照)。
処理管理部46は、予め定められたテーブルに登録されている情報に基づいて、データ要求入力元のバッファモジュール40(ここではバッファモジュール403)の前段の画像処理モジュール38A(ここでは画像処理モジュール38A3)を認識し、認識した前段の画像処理モジュール38Aに処理要求を入力する(図4の(4)参照)。
画像処理モジュール38A3の制御部は、処理要求が入力されると前段のバッファモジュール402に読出要求を入力し(図4の(5)参照)、バッファモジュール402のバッファにも読出可能な画像データが記憶されていないので、バッファモジュール402のバッファ制御部は処理管理部46にデータ要求を入力する(図4の(6)参照)。処理管理部46は、バッファモジュール402からデータ要求が入力された場合も、その前段の画像処理モジュール38A2に処理要求を入力し(図4の(7)参照)、画像処理モジュール38A3の制御部は前段のバッファモジュール401に読出要求を入力する(図4の(8)参照)。また、バッファモジュール401のバッファにも読出可能な画像データが記憶されていないので、バッファモジュール401のバッファ制御部も処理管理部46にデータ要求を入力する(図4の(9)参照)。処理管理部46は、バッファモジュール401からデータ要求が入力された場合も、その前段の画像処理モジュール38A1に処理要求を入力する(図4の(10)参照)。
ここで、画像処理モジュール38A1の前段のモジュールは画像データ供給部22であるので、画像処理モジュール38A1の制御部は、画像データ供給部22にデータ要求を入力することで画像データ供給部22から単位読出データ量の画像データを取得し(図4の(11)参照)、取得した画像データに対して画像処理エンジンが画像処理を行うことで得られた画像データを、後段のバッファモジュール401のバッファに書き込む(図4の(12)参照)。なお、画像処理モジュール38A1の制御部は後段のバッファモジュール401のバッファへの画像データの書き込みを完了すると、処理管理部46へ処理完了通知を入力する。
処理管理部46は、処理完了通知元が画像処理部80の最後段の画像処理モジュール38Aか否か判定する。この場合は判定が否定され、何ら処理を行うことなく処理を終了する(画像処理モジュール38A2,38A3から処理完了通知が入力された場合についても同様)。
また、バッファモジュール401のバッファ制御部は、後段の画像処理モジュール38A2が読出可能な単位読出データ量以上の有効データが書き込まれると画像処理モジュール38A2に対して読出を要請し、これに伴い画像処理モジュール38A2の制御部は、バッファモジュール401のバッファから単位読出データ量の画像データを読み出し(図4の(13)参照)、取得した画像データに対して画像処理エンジンが画像処理を行うことで得られた画像データを、後段のバッファモジュール402のバッファに書き込む(図4の(14)参照)。バッファモジュール402のバッファ制御部は、後段の画像処理モジュール38A3が読出可能な単位読出データ量以上の有効データが書き込まれると画像処理モジュール38A3へ読出を要請し、画像処理モジュール38A3の制御部は、バッファモジュール402のバッファから単位読出データ量の画像データを読み出し(図4の(15)参照)、取得した画像データに対して画像処理エンジンが画像処理を行うことで得られた画像データを、後段のバッファモジュール403のバッファに書き込む(図4の(16)参照)。
更に、バッファモジュール403のバッファ制御部は、後段の画像処理モジュール38A4が読出可能な単位読出データ量以上の有効データが書き込まれると画像処理モジュール38A4に対して読出を要請し、これに伴い画像処理モジュール38A4の制御部は、バッファモジュール403のバッファから単位読出データ量の画像データを読み出し(図4の(17)参照)、取得した画像データに対して画像処理エンジンが画像処理を行うことで得られた画像データを、後段のモジュールである画像出力部24へ出力する(図4の(18)参照)。また、画像処理モジュール38A4の制御部は後段の画像出力部24への画像データの書き込みを完了すると、処理管理部46へ処理完了通知を入力する(図4の(19)参照)。処理管理部46は、最後段の画像処理モジュール38Aである画像処理モジュール38A4に処理要求を再度入力する。
この最後段の画像処理モジュール38A4への処理要求の再入力により、上述した処理シーケンスが再度繰り返され、処理対象の画像データに対し、画像処理が順次行われることになる。画像データ供給部22から供給される画像データが処理対象の画像データの末尾に達すると、個々の画像処理モジュール38Aから処理管理部46への全体処理終了通知の入力が、前段側の画像処理モジュール38Aから順次行われる。処理管理部46は、最後段の画像処理モジュール38Aから全体処理終了通知が入力されると、指示書解釈実行部48に対して画像処理の完了を通知し、画像処理の完了が通知された指示書解釈実行部48は、アプリケーション32に対して画像処理の完了を通知する。なお、一連の画像処理が完了すると、画像処理モジュール38A、サポートモジュール38B,及びバッファモジュール40は自モジュールを消去する消去処理を行う。これにより、使用されていたリソースが解放される。
また、面単位処理の場合には、基本的には、上記ブロック単位処理と同様に、前段のモジュールから後段のモジュールへ画像データが受け渡されて一連の画像処理が行われるが、以下の点が異なる。面単位処理では、最後段の画像処理モジュール38Aに入力された処理要求がより前段の画像処理モジュール38Aへ遡り、最前段の画像処理モジュール38Aに到達した後は、最前段の画像処理モジュール38Aに対してのみ処理要求を繰り返し入力し、当該画像処理モジュール38Aにおける処理対象の画像データ全体に対する画像処理が完了すると、次の画像処理モジュール38Aで処理対象の画像データ全体に対する画像処理を行わせ、この処理を後段の画像処理モジュール38Aに対して順に進めていくことで、一連の画像処理が行われる。面単位処理の詳細については説明を省略する。
図1に示す指示書解釈実行部48は、アプリケーション32から受け取った画像処理指示書を解釈して、この画像処理指示書の記述に応じた処理モジュール38が生成されて画像処理部80が構築され、処理管理部46により画像処理が実行されるように制御する。ここで、指示書解釈実行部48で行われる処理の流れについて、特にファクトリ70を生成する処理に着目して説明する。
図5は、指示書解釈実行部48の機能構成と、画像処理指示書の投入からモジュール生成部44が呼び出されるまでの流れを示す模式図である。
指示書解釈実行部48は、指示書解釈部48A、ファクトリ生成関数名生成部48B、関数呼出部48C、引数格納処理部48D、及び引数渡部48Eを含んで構成されている。指示書解釈部48Aは、アプリケーション32から受け取った画像処理指示書を解釈し、必要な情報を抽出する。図6に、画像処理指示書の具体例を示す。図示されるように、オブジェクト(処理モジュール38)の情報が処理の実行順に列挙されている。各処理モジュール38の情報として、画像処理指示書には、変数名、型名、引数個数、及び引数が対応づけられて記述されている。変数名は、オブジェクトの名称であり、オブジェクト毎に固有の識別情報として付与される。型名は、オブジェクトを生成するモジュール生成部44のクラス名である。なお、本実施の形態では、モジュール生成部44とファクトリ70とが1対1で対応づけられるため、この型名はファクトリ70の名称の一部としても使用され、またファクトリ生成関数60の関数名の一部としても使用される。引数個数は、オブジェクトの引数の個数を示す。そして、その引数個数分だけ引数が列挙されている。指示書解釈部48Aは、これら変数名、型名、引数個数、引数の各々を、処理モジュール38に関する情報として抽出する。
ファクトリ生成関数名生成部48Bは、指示書解釈部48Aで抽出された情報(本実施の形態では型名)に基づいて、予め定められたファクトリ生成関数名生成規則に従って、ファクトリ生成関数60の関数名を生成する。ここで生成された関数名が、ファクトリ70を生成する関数として呼び出すファクトリ生成関数60の名称となる。関数呼出部48Cは、ファクトリ生成関数名生成部48Bで生成された関数名が付与されたファクトリ生成関数60を呼び出す。引数格納処理部48Dは、指示書解釈部48Aにより抽出された引数個数及び引数に基づいて、引数個数分の配列要素を有する配列に引数を格納する処理を行う。引数渡部48Eは、引数格納処理部48Dで引数が格納された配列の先頭アドレスをファクトリ70に渡す。
なお、図5では、ファクトリ70やモジュール生成部44を、既存の機能と新規追加した機能とで分けて図示したが、いずれの場合も、ファクトリ生成関数60を呼び出してジェネリックファクトリクラス52からファクトリ70を生成し、ファクトリ70からモジュール生成部44を呼び出して処理モジュール38を生成することについては変わりない。
図7は、指示書解釈実行部48によって実行される処理の流れを示すフローチャートである。
指示書解釈実行部48は、(電子ファイル形式の)画像処理指示書を読込み、解析して、処理モジュール38の情報を順次抽出する(読み取る)。具体的には、まずステップS01では、画像処理指示書から全ての情報を読み取ったか、すなわち、画像処理指示書のファイルの終端を示す終端記号(EOF)を検出したか否かを判定する。ステップS01で否定判定した場合には、ステップS02に進む。ステップS02では、画像処理指示書から変数名を1つ読み取って、vnにセットする。ステップS03では、画像処理指示書から上記読み取った変数名に対応づけられた型名を読み取って、tnにセットする。
続いて、ステップS04で、予め定められたファクトリ生成関数名生成規則に従って、上記読み取られた型名tnから、ファクトリ生成関数60の関数名fcfnを生成する。なお、ファクトリ生成関数ライブラリ58に登録されているファクトリ生成関数60には、ファクトリ生成関数名生成規則で生成される関数名が予め付与されている。ステップS05では、関数名から該関数名が付与された関数が記憶された記憶領域のアドレスを取得する関数をシステムライブラリから呼び出し、上記生成された関数名fcfnが付与されたファクトリ生成関数60が格納されている記憶領域のアドレスfcfを取得する。
次に、ステップS06で、上記読み取った変数名に対応づけられた引数個数を画像処理指示書から読み取って、nにセットする。ステップS07で、引数文字列格納用の配列v(以下引数配列vと呼称する)、引数オブジェクト格納用マップ(キーが変数名、各配列要素の値がvoidポインタの連想配列)mapのデータをクリアし、ループカウンタiを0にする。ここで、引数配列vは、変数名vnに対応づけられて画像処理指示書に記述された引数を格納するための配列である。ただし、引数がオブジェクト(処理モジュール38)の変数名を示していた場合には、当該変数名を有するオブジェクトのアドレスが格納される。なお、連想配列mapは、モジュール生成部44により生成されたオブジェクト(処理モジュール38)のアドレスを格納するための配列である。
ステップS08では、「ループカウンタi<引数個数n」であるか否かを判定する。ここで、肯定判定した場合には、ステップS09に進む。ステップS09では、上記読み取った変数名に対応づけられた引数を1つ読み取って、anにセットする。
ステップS10では、引数anがmap配列のキーとして存在するか否かを判定する。ステップS10で肯定判定した場合には、引数anが、すでに生成されたオブジェクト(処理モジュール38)の名称であるため、ステップS11で、引数配列v[i]に、map中のanをキーとした値map[an]を格納する。一方、ステップS10で否定判定した場合には、引数anが、すでに生成されたオブジェクト(処理モジュール38)の名称ではないため、ステップS12で、新たに生成するオブジェクトの引数を表現している文字列anとして、引数配列v[i]に格納する。すなわち、ここでは、引数anが値である場合には、当該引数anを引数配列vに格納し、引数anが値ではなくオブジェクト(処理モジュール38)の変数名である場合には、引数配列vには、該オブジェクトのアドレスを格納するようにしている。ステップS13では、ループカウンタiに1を加算して、ステップS08に戻る。ステップS08〜ステップ13の処理は、上記変数名vnに対応づけられた全ての引数を読み取って、引数配列v[i]に格納し、ステップS08で否定判定されるまで繰り返される。
ステップS08で否定判定した場合には、ステップS14に進む。ステップS14では、ステップS05で取得したアドレスfcfに格納されているファクトリ生成関数60(ファクトリ生成関数fcfn)を呼び出し、ファクトリ70(ファクトリf)を生成させる。
ステップS15では、生成されたファクトリfに引数型不定のポインタ形式で引数を渡し(ここでは、引数配列vの先頭アドレスを渡す)、オブジェクト(処理モジュール38)objを生成させる。より具体的には、ファクトリfは、自身に対応するモジュール生成部44を呼び出し、引数配列vから引数型に応じて各引数を読み出し、指定された形式変換クラス56により形式変換を行ってモジュール生成部44に渡す。これにより、モジュール生成部44は、当該引数を使用するオブジェクト(処理モジュール38)を生成する。
ステップS16では、ファクトリfを削除する。
ステップS17では、変数名vnをキーとし、生成されたオブジェクトのアドレスを値とする配列要素を連想配列mapに登録する。すなわち、map[vn]にオブジェクトobjのアドレスを格納する。ステップS17の後は、ステップS01に戻る。
ステップS01で肯定判定した場合には、ステップS18に進む。ステップS18では、生成されたオブジェクトが連結されて構築された画像処理部80により画像処理が実行されるよう処理管理部46を起動する。これにより、画像処理が実行される。
ステップS19では、連想配列mapをクリアする。
ここで、ステップS01〜S03、S06、S09の処理が、指示書解釈部48Aの処理に相当し、ステップS04の処理が、ファクトリ生成関数名生成部48Bの処理に相当し、ステップS05、S14の処理が、関数呼出部48Cの処理に相当し、ステップS07〜S13、S17、及びS19の処理が、引数格納処理部48Dの処理に相当し、ステップS15における引数を渡す処理が引数渡部48Eの処理に相当する。なお、図5において、ステップS16、S18に相当する機能ブロックの図示は省略した。
ここで、図6に示した画像処理指示書を例に挙げて、上記フローチャートにおける処理を具体的に説明する。まず、図6に示される変数名で識別される各オブジェクトについて説明する。
inFileオブジェクト・・・Stringが型名として指定され、"/foo/bar/in.png"が引数として指定されており、変数名readの画像処理モジュール38A(readオブジェクト)のサポートモジュール38Bとして動作する。inFileオブジェクトは、readオブジェクトが読み込む画像データのファイルを指定する文字列(/foo/bar/in.png)を提供するオブジェクトである。
inStrmオブジェクト・・・FileInputStreamが型名として指定され、"inFile"が引数として指定されており、変数名readの画像処理モジュール38A(readオブジェクト)のサポートモジュール38Bとして動作する。引数"inFile"はinFileオブジェクトを指している。inStrmオブジェクトは、inFileオブジェクトにより提供された文字列で指定された読み出し元ファイルからデータを読み出す処理を行うオブジェクトである。
readオブジェクト・・・ReadPNGが型名として指定され、"inStrm"が引数として指定されており、画像データを読み込む画像処理モジュール38Aとして動作する。readオブジェクトは、inStrmオブジェクトを呼出し、該inStrmオブジェクトによって読み出されたデータを、PNGフォーマットの画像データとして読み込むオブジェクトである。
ratioオブジェクト・・・Floatが型名として指定され、"1.5"が引数として指定されており、変数名scaleの画像処理モジュール38A(scaleオブジェクト)のサポートモジュール38Bとして動作する。ratioオブジェクトは、scaleオブジェクトが拡大縮小処理を行う際の倍率を浮動小数点型の文字列で提供するオブジェクトである。
scaleオブジェクト・・・Scaleが型名として指定され、引数"read"と"ratio"が指定されており、画像データの拡大縮小を行う画像処理モジュール38Aとして動作する。scaleオブジェクトは、ratioオブジェクトによって提供された倍率(ここでは1.5)でreadオブジェクトによって読み込まれた画像データを拡大縮小(ここでは拡大)するオブジェクトである。
outFileオブジェクト・・・Stringが型名として指定され、"/tmp/out.jpg"が引数として指定されており、変数名writeの画像処理モジュール38A(writeオブジェクト)のサポートモジュール38Bとして動作する。outFileオブジェクトは、writeオブジェクトが画像データを書き込む際の書き込み先を指定する文字列(/tmp/out.jpg)を提供するオブジェクトである。
outStrmオブジェクト・・・FileOutputStreamが型名として指定され、"outFile"が引数として指定されており、変数名writeの画像処理モジュール38A(writeオブジェクト)のサポートモジュール38Bとして動作する。引数"outFile"はoutFileオブジェクトを指している。outStrmオブジェクトは、outFileオブジェクトにより提供された文字列で指定された書き込み先ファイルにデータを書き込む処理を行うオブジェクトである。
writeオブジェクト・・・WriteJPEGが型名として指定され、"scale"及び"outStrm"が引数として指定されており、画像データを書き込む画像処理モジュール38Aとして動作する。writeオブジェクトは、outStrmオブジェクトを呼出し、scaleオブジェクトによって拡大縮小処理された画像データを、JPEGフォーマットの画像データとしてoutFileオブジェクトによって指定された書き込み先ファイルに書き込むオブジェクトである。
このように画像処理の内容が記述された画像処理指示書が読み込まれた場合には、以下のように処理される。まず、ステップS02で、文字列”inFile”を画像処理指示書に記述された先頭のオブジェクトの変数名として読み取り、変数名vnにセットする。
ステップS03では、変数名inFileに対応づけられている文字列”String”を型名として読み取り、型名tnにセットする。
ステップS04では、型名tnに接頭文字列”load_”、接尾文字列”Factory”を付加した文字列”load_StringFactory”を、ファクトリ生成関数名fcfnにセットする。ここで、ファクトリ生成関数名生成規則は、「型名tnの接頭文字列”load_”、接尾文字列”Factory”を付加する」というものである。
ステップS05では、上記生成しファクトリ生成関数名(load_StringFactory)から当該関数名が付与されている関数のアドレスを取得する。
ステップS06では、変数名inFileに対応づけられている引数個数「1」を読み込み、引数個数nにセットする。
ステップS07で、引数配列v及び連想配列mapをクリアしてループカウンタiを0にセットした後、ステップS09では、文字列”/foo/bar/in.png”を読み取り、引数anにセットする。ステップS10において、引数anをキーとする配列要素が連想配列mapに存在していないため否定判定し、ステップS12で、引数anを引数配列v[0]にセットする。ステップS13では、iをインクリメントする。
オブジェクトinFileでは、引数は1つであるため、次のステップS08では否定判定され、ステップS14でファクトリfが生成されて、ステップS15でオブジェクトinFileが生成される。このオブジェクトのアドレスは、ステップS17で、map配列の変数名inFileをキーとする配列要素に格納される。
続いて、次のオブジェクトについて上記と同様に処理が繰り返される。すなわち、ステップS02で、文字列”inStrm”を読み取り、変数名vnにセットする。
ステップS03では、変数名inStrmに対応づけられている文字列”FileInputStream”を型名として読み取り、型名tnにセットする。
ステップS04では、型名tnに接頭文字列”load_”、接尾文字列”Factory”を付加した文字列”load_FileInputStreamFactory”を、ファクトリ生成関数名fcfnにセットする。
ステップS05では、上記生成しファクトリ生成関数名(load_FileInputStreamFactory)から当該関数名が付与されている関数のアドレスを取得する。
ステップS06では、変数名inStrmに対応づけられている引数個数「1」を読み込み、引数個数nにセットする。
ステップS07で、引数配列v及び連想配列mapをクリアしてループカウンタiを0にセットした後、ステップS09では、文字列”inFile”を読み取り、引数anにセットする。ステップS10において、引数an(ここではinFile)をキーとする配列要素が連想配列mapに存在しているため(上記ステップS17参照)肯定判定し、ステップS11で、map[inFile]の値(inFileオブジェクトのアドレス)を引数配列v[0]にセットする。ステップS13では、iをインクリメントする。
オブジェクトinStrmでは、引数は1つであるため、次のステップS08では否定判定され、ステップS14でファクトリfが生成されて、ステップS15でオブジェクトinStrmが生成される。このオブジェクトのアドレスは、ステップS17で、map配列の変数名inStrmをキーとする配列要素に格納される。
以降のオブジェクトについての処理も、上記と同様であるため、ここではこれ以上の説明を省略する。このように画像処理指示書の記述に従って、逐次オブジェクトが生成されていく。
図12(B)は、指示書解釈実行部48で実行される処理の流れを簡略化して記述したプログラム(メインプログラム)のコーディング例である。
図示されるように、符号400の部分で、ファクトリ生成関数60が実装されているライブラリ(ファクトリ生成関数ライブラリ58)を指定し、符号402の部分で、ファクトリ生成関数60の関数名を、ファクトリ生成関数名生成規則に従って生成する。
続いて、符号404で、ファクトリ生成関数ライブラリ58をオープンして、符号406の部分で、ファクトリ生成関数60のアドレスを取得し、符号408の部分で、該取得したアドレスを用いてファクトリ生成関数60を呼出してファクトリ70を生成する。
更に、符号410の部分で、引数の個数分だけ引数を読み取って配列に格納し、符号412の部分でオブジェクト(処理モジュール38)が生成されるように、ファクトリ70からモジュール生成部44を呼び出す。このとき、引数(args)がモジュール生成部44に渡されている。
すなわち、どのような機能を実行する場合でも、このメインプログラムを実行することで、処理モジュール38が生成されて画像処理部80が構築される。生成するモジュール生成部44毎に引数の引数型や形式が違っていても、テンプレートとして使用されるジェネリックファクトリクラス52には、この違いを吸収するよう抽象化された引数が定義されており、抽象化された引数がファクトリ70で具象化されるため、問題なくモジュール生成部44が呼び出される。また、ファクトリ70を生成するファクトリ生成関数60の関数名も、画像処理指示書から抽出した変数名から予め定められた規則に従って生成し、ファクトリ生成関数ライブラリ58には、当該関数名が付与されたファクトリ生成関数60を登録しておくことで、問題なくファクトリ生成関数60を呼び出すことができ、ファクトリ生成関数60の関数名もメインプログラムにおいて意識(記述)する必要がなくなる。
更に、新規に機能を追加する場合であっても、メインプログラムを修正する必要はない。事前に、新たに追加する処理モジュール38の画像処理クラスを画像処理クラスライブラリ36に登録しておき、該処理モジュール38を生成するためのモジュール生成部44を登録しておき、このモジュール生成部44を呼び出すファクトリ70を生成するためのファクトリ生成関数60を登録しておくことによって、同様に処理モジュール38が生成されて画像処理部80が構築される。従って、メインプログラムを修正する必要はなく、またメインプログラム側で各処理モジュール38に応じた引数を定義する必要もない。
ところが、ファクトリ70を介してモジュール生成部44を呼び出す構成とせずに、直接モジュール生成部44を呼び出す従来の構成とすると、メインプログラムにおいて、図12(A)に示すように、生成する処理モジュール38毎に、各モジュール生成部44に応じた引数型及び形式の各々に応じて各引数を定義してハードコーディングする必要があり、登録される処理モジュール38の数が多いほど、メインプログラムのハードコーディング量も多くなる。また機能追加する場合には、追加の度にプログラムを逐一修正する必要が生じる。具体的には、図12(A)の符号300で示した拡大縮小の画像処理モジュール38A(Scaleオブジェクト)についての記述を例に挙げて説明すると、引数である倍率の読み出し(符号301)、浮動小数点の引数型にするための変換(符号302)、3つの引数eng,m,m(ここで、engは画像処理エンジンを示す引数、2つのmは、浮動小数点で表した横の倍率と縦の倍率である)の指定(符号303)のそれぞれを記述する必要がある。このように、メインプログラムを、登録される画像処理クラス毎に各引数を具体化して記述しなくてはならなくなる。
なお、上記実施の形態では、関数名毎に異なるジェネリックファクトリクラス52を設ける例について説明した(例えば、メソッドとして定義される関数名(例えば、engine(),create()等)が異なる場合には、異なるジェネリックファクトリクラス52として定義した)が、例えば、関数名及び引数個数は同じであるが、引数型が互いに異なる複数の具象関数が規定されたモジュール生成部44について、当該複数の具象関数の1つが実行されるようにモジュール生成部44を呼び出すファクトリ70を生成することもできる。すなわち、ファクトリ70と具象関数とが1対1の関係となるようファクトリ70を生成する。
図8に示すように、処理Cで規定されるモジュール生成部44には関数名及び引数個数は等しいが、引数型及び形式が異なる3つの具象関数が定義されており、それぞれの具象関数に応じたファクトリ70が共通のジェネリックファクトリクラス52をテンプレートとして生成される。ファクトリC1は、抽象化された引数を、引数型がint、形式が値となるよう変換するファクトリ70であり、ファクトリC2は、引数型がint、形式がポインタとなるよう変換するファクトリ70であり、ファクトリC3は、引数型がdouble、形式が値となるよう変換するファクトリ70である。
また、ジェネリックファクトリクラス52は、引数の個数によらず1つのジェネリックファクトリクラス52を登録しておいてもよいが、引数の個数毎にジェネリックファクトリクラス52を用意して登録しておくようにしてもよい。上記実施の形態では、ジェネリックファクトリクラス52を引数の個数に応じて設けた場合を例に挙げたが、更にここで、図9を用いて、詳細に説明する。
図9(A)は、引数個数が1の場合のモデル図であり、図9(B)は、引数個数が2の場合のモデル図であり、図9(C)は、引数個数が3の場合のモデル図である。前述した図10において、引数4個のジェネリックファクトリクラス52の具体例(実装例)を示したが、引数の個数に応じたジェネリックファクトリクラス52を作成する場合には、ここで、符号100の部分のテンプレートクラスの宣言において、引数の個数に応じた定義を行い、符号102で引数の個数に応じた名称でジェネリックファクトリクラス52の宣言をしておき、符号106の部分においては、構造体を引数の個数に応じた配列個数にして定義し、符号118の部分において、引数の各々に対応させて形式変換クラス56を記述しておく。
ユーザは、呼び出すモジュール生成部44の引数の個数に応じたジェネリックファクトリクラス52を実体化してファクトリ70を生成するように、ファクトリ生成関数60を作成して事前に登録する。
なお、上記実施の形態では、各処理モジュール38に1つ以上の引数が指定される例について説明したが、これに限定されない。引数が指定されない処理モジュール38が存在していてもよい。引数が指定されない処理モジュール38としては、例えば、乱数でデータを生成する処理を行ったり、常に決められた定数を返す処理を行ったりするオブジェクトなどが考えられる。このように引数が指定されない処理モジュール38を生成するモジュール生成部44に対しては、引数を渡す必要がないため、引数個数が0のジェネリックファクトリクラス52(すなわち、引数を配列構造にして引数型を具象化したり、各引数に対して形式変換クラス56を指定する等の操作を含まないジェネリックファクトリクラス52)を用意して、ファクトリ70を生成するようにしてもよい。