MagickCore(低レベル C API)
MagickCore API は、C 言語と ImageMagick 画像処理ライブラリの間の低レベルインターフェースで、ウィザードレベルのプログラマにのみ推奨されます。少数の不透明型とアクセサのみを使う MagickWand C API と違い、MagickCore ではほぼ専ら構造体メンバーに直接アクセスします。MagickCore の公開メソッドの説明は GitHub にあります:
- ImageMagick 環境の初期化・破棄
- 画像の構成(Constitute)
- 画像の合成
- 画像メソッド
- 画像チャンネルメソッド
- 画像の色数を数える
- カラーマップメソッド
- 色空間メソッド
- 画像の歪み
- 画像レイヤーの扱い
- 画像プロファイルの扱い
- 画像のユニーク色数を減らす
- 画像ヒストグラム
- ファジィ c-means しきい値処理で画像をセグメント化
- 画像のリサイズ
- 画像の変換
- 任意角度で画像をせん断・回転
- 画像の補正
- 効果を加える
- モルフォロジーの収縮・膨張・オープニング・クロージング
- 特殊効果を加える
- 画像を装飾する
- 画像属性の取得・設定
- 画像プロパティの取得・設定
- 画像統計の取得
- 画像特徴の取得
- 画像に注釈を付ける
- 画像に塗る
- 画像に描画する
- 画像サムネイルを作成
- 離散フーリエ変換(DFT)を計算
- 画像を再構成画像と比較
- コンピュータービジョン
- 画像を対話的に表示・編集
- 画像シーケンスを対話的にアニメーション
- 暗号化ピクセルとの相互変換
- 画像リストの扱い
- 画像ビューメソッド
- 画像ピクセルの取得・設定
- キャッシュビューの扱い
- ピクセル FIFO
- バイナリラージオブジェクトの読み書き
- ロード可能モジュール
- 画像のメッセージダイジェスト計算
- 画像レジストリ
- 例外の扱い
- メモリ確保
- リソース消費の監視・制限
- 画像操作の進捗監視
- バージョンと著作権の取得
- Mime メソッド
- 非推奨メソッド
- エラーと警告コード
MagickCore プログラムを書いたら、次のようにコンパイルします:
cc `MagickCore-config --cflags --cppflags` -O2 -o core core.c `MagickCore-config --ldflags --libs`
ImageMagick が既定のシステムパスにない場合は、PKG_CONFIG_PATH 環境変数を設定します:
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
手始めに、MagickCore API を利用する例 core.c を示します。GIF 画像を読み込み、サムネイルを作成し、PNG 形式でディスクに書き出します。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <MagickCore/MagickCore.h>
int main(int argc,char **argv)
{
ExceptionInfo
*exception;
Image
*image,
*images,
*resize_image,
*thumbnails;
ImageInfo
*image_info;
if (argc != 3)
{
(void) fprintf(stdout,"Usage: %s image thumbnail\n",argv[0]);
exit(0);
}
/*
Initialize the image info structure and read an image.
*/
MagickCoreGenesis(*argv,MagickTrue);
exception=AcquireExceptionInfo();
image_info=CloneImageInfo((ImageInfo *) NULL);
(void) strcpy(image_info->filename,argv[1]);
images=ReadImage(image_info,exception);
if (exception->severity != UndefinedException)
CatchException(exception);
if (images == (Image *) NULL)
exit(1);
/*
Convert the image to a thumbnail.
*/
thumbnails=NewImageList();
while ((image=RemoveFirstImageFromList(&images)) != (Image *) NULL)
{
resize_image=ResizeImage(image,106,80,LanczosFilter,exception);
if (resize_image == (Image *) NULL)
MagickError(exception->severity,exception->reason,exception->description);
(void) AppendImageToList(&thumbnails,resize_image);
DestroyImage(image);
}
/*
Write the image thumbnail.
*/
(void) strcpy(thumbnails->filename,argv[2]);
WriteImage(image_info,thumbnails,exception);
/*
Destroy the image thumbnail and exit.
*/
thumbnails=DestroyImageList(thumbnails);
image_info=DestroyImageInfo(image_info);
exception=DestroyExceptionInfo(exception);
MagickCoreTerminus();
return(0);
}
では、ウォンドビューを使ってアルゴリズムを並列実行し、デュアル・クアッドコア処理システムを活用しながら同じコントラスト強調を行います。sigmoidal-contrast.c モジュールは、画像を読み込み、シグモイド非線形コントラスト制御を適用し、前のコントラスト強調プログラムと同様に結果をディスクに書き出しますが、今度は並列に動作します(ImageMagick が OpenMP サポート付きでビルドされていることを前提とします)。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <MagickCore/MagickCore.h>
static MagickBooleanType SigmoidalContrast(ImageView *contrast_view,
const ssize_t y,const int id,void *context)
{
#define QuantumScale ((MagickRealType) 1.0/(MagickRealType) QuantumRange)
#define SigmoidalContrast(x) \
(QuantumRange*(1.0/(1+exp(10.0*(0.5-QuantumScale*x)))-0.0066928509)*1.0092503)
RectangleInfo
extent;
register IndexPacket
*indexes;
register PixelPacket
*pixels;
register ssize_t
x;
extent=GetImageViewExtent(contrast_view);
pixels=GetImageViewAuthenticPixels(contrast_view);
for (x=0; x < (ssize_t) (extent.width-extent.x); x++)
{
SetPixelRed(pixels,RoundToQuantum(SigmoidalContrast(GetPixelRed(pixels)));
SetPixelGreen(pixels,RoundToQuantum(SigmoidalContrast(GetPixelGreen(pixels)));
SetPixelBlue(pixels,RoundToQuantum(SigmoidalContrast(GetPixelBlue(pixels)));
SetPixelOpacity(pixels,RoundToQuantum(SigmoidalContrast(GetPixelOpacity(pixels)));
pixels++;
}
indexes=GetImageViewAuthenticIndexes(contrast_view);
if (indexes != (IndexPacket *) NULL)
for (x=0; x < (ssize_t) (extent.width-extent.x); x++)
SetPixelIndex(indexes+x,RoundToQuantum(SigmoidalContrast(GetPixelIndex(indexes+x))));
return(MagickTrue);
}
int main(int argc,char **argv)
{
#define ThrowImageException(image) \
{ \
\
CatchException(exception); \
if (contrast_image != (Image *) NULL) \
contrast_image=DestroyImage(contrast_image); \
exit(-1); \
}
#define ThrowViewException(view) \
{ \
char \
*description; \
\
ExceptionType \
severity; \
\
description=GetImageViewException(view,&severity); \
(void) fprintf(stderr,"%s %s %lu %s\n",GetMagickModule(),description); \
description=DestroyString(description); \
exit(-1); \
}
ExceptionInfo
*exception;
Image
*contrast_image;
ImageInfo
*image_info;
ImageView
*contrast_view;
MagickBooleanType
status;
if (argc != 3)
{
(void) fprintf(stdout,"Usage: %s image sigmoidal-image\n",argv[0]);
exit(0);
}
/*
Read an image.
*/
MagickCoreGenesis(*argv,MagickTrue);
image_info=AcquireImageInfo();
(void) CopyMagickString(image_info->filename,argv[1],MaxTextExtent);
exception=AcquireExceptionInfo();
contrast_image=ReadImage(image_info,exception);
if (contrast_image == (Image *) NULL)
ThrowImageException(contrast_image);
/*
Sigmoidal non-linearity contrast control.
*/
contrast_view=NewImageView(contrast_image);
if (contrast_view == (ImageView *) NULL)
ThrowImageException(contrast_image);
status=UpdateImageViewIterator(contrast_view,SigmoidalContrast,(void *) NULL);
if (status == MagickFalse)
ThrowImageException(contrast_image);
contrast_view=DestroyImageView(contrast_view);
/*
Write the image then destroy it.
*/
status=WriteImages(image_info,contrast_image,argv[2],exception);
if (status == MagickFalse)
ThrowImageException(contrast_image);
contrast_image=DestroyImage(contrast_image);
exception=DestroyExceptionInfo(exception);
image_info=DestroyImageInfo(image_info);
MagickCoreTerminus();
return(0);
}
MagickCoreTerminus() は、ImageMagick を使うアプリケーションのシャットダウン時にリソースをクリーンアップ・解放するための ImageMagick ライブラリの関数です。この関数は、シャットダウン処理中にアプリケーションプロセスの主スレッドで呼び出すべきです。ImageMagick 関数を使うスレッドがすべて終了した後にのみこの関数を呼び出すことが重要です。
ImageMagick は OpenMP(並列プログラミングの手法)を介して内部的にスレッドを使うことがあります。そのため、MagickCoreTerminus() を呼び出す前に、ImageMagick への関数呼び出しがすべて完了していることを確認することが重要です。これにより、この終了関数によって破棄されるリソースに OpenMP ワーカースレッドがアクセスする問題を防げます。
OpenMP が使われている場合(バージョン 5.0 以降)、OpenMP 実装自体が独自の方法でワーカースレッドの起動・停止やリソースの確保・解放を扱います。つまり、MagickCoreTerminus() を呼び出した後も、一部の OpenMP リソースやワーカースレッドが確保されたまま残ることがあります。これに対処するため、関数 omp_pause_resource_all(omp_pause_hard) を呼び出せます。OpenMP バージョン 5.0 で導入されたこの関数は、OpenMP が確保したリソース(スレッドやスレッド固有メモリなど)が解放されることを保証します。MagickCoreTerminus() の実行完了後にこの関数を呼び出すことを推奨します。