作成開始日 2014.05.22
最終更新日 2014.06.03
8×8という分割数に深い意味はない。 分割数が少なければ精度が落ち、多ければ速度が落ちる。そのバランスで選んだ。 それに、8×8=64桁だと、テキストエディタの1行(80桁)に収まって便利。
GBMSIZE -w 8 -h 8 myimg.jpg myimg.pgm,ascii当初はBMP形式のグレイスケール画像への変換を考えていたが、 グレイスケールBMPはパレットによる濃淡管理をしていて、 各ドットのデータがそのまま濃淡値を表現しているわけではない。 その点、PGMにはパレット管理の発想がなく、 各ドットのデータは単純に濃淡を表現している。 こちらの方が遥かに扱いやすい。
さらに、PGMは通常のバイナリ形式だけでなく、テキスト形式でも表現できる。 これならば、テキストエディタで中味が確認できるし、スクリプトでも扱いやすい。 GBMはこのテキスト形式のPGMもサポートしている(「,ascii」オプション)。 カレントのJPG画像から8×8のPGMを作成するには、次のようにすれば良い。
rc=SysFileTree('*.jpg',img,'FO') Do n=1 to img.0 fname=FILESPEC('N',img.n) PARSE var fname body '.' ext fpgm=body'.pgm' SAY fname '@gbmsize -w 8 -h 8' img.n fpgm',ascii' Endなお、ImageMagickでもconvertに「-compress none」オプションを付ければ、テキスト形式のPGMを作成することはできる。ただし、データ部分が8桁×8行ではなく、12桁×5行+4桁という表記になるので少々扱い難い。
P2 ←ファイル形式:P2=グレイスケール/テキスト 8 8 ←画像サイズ:8×8 255 ←階調:0〜255の256階調=8bit/pixel 234 061 014 053 054 032 200 086 ←以下、各ドットの濃淡値 048 220 047 034 046 192 204 255 172 198 040 200 113 221 202 204 204 089 051 095 059 180 214 227 191 031 061 114 075 040 194 195 056 038 245 025 073 040 214 072 077 028 095 183 045 123 223 194 021 199 202 149 245 250 214 203このように、先頭3行を読み飛ばせば、そのまま各ドットの濃淡値が得られる。 ただし、各ドットは8ビット(256階調)で表現されるため、16進数でも2桁になる。 PGM自体は4ビットモードをサポートしているが、GBMは8ビット/16ビットのみ。 そこで、各濃淡値を16で割って4ビットに変換する必要がある。 その上で16進数1桁に変換して、64ドットの濃淡を64桁の16進数に連結する。
PGM2HEX: PROCEDURE /* テキスト形式用 */ tmp=ARG(1) /* 引数はPGMファイル名 */ rc=STREAM(tmp,'C','O') Do n=1 to 3; dmy=LINEIN(tmp); END; /* ヘッダのスキップ */ hex='' Do While LINES(tmp)>0 st=LINEIN(tmp) PARSE VAR st b.1 b.2 b.3 b.4 b.5 b.6 b.7 b.8 Do n=1 to 8 d=TRUNC(b.n/16) h=D2X(d) hex=hex||h End End rc=STREAM(tmp,'C','C') RETURN hexこれによって、例えば上記のPGMファイルは;
E30332C53D222CCFAC2C7DCCC5353BDEB13742CC32F142D4415B27DC1CC9FFDCのような16進文字列に変換できる。 これを濃淡コードと呼ぶことにする。
diff=0 DO m=1 TO 64 ch1=SUBSTR(hex1,m,1) ch2=SUBSTR(hex2,m,1) d=ABS(X2D(ch1)-X2D(ch2)) IF d>1 THEN diff=diff+1 END SELECT WHEN diff=0 THEN SAY 'ほぼ同一' WHEN diff<20 THEN SAY '似てる' WHEN diff<30 THEN SAY '少し似てる' OTHERWISE SAY '別物' ENDのような感じになる。 ポイントは、各ドットの差の大きさを考慮に入れないこと。 差が閾値(例えば±1)を超えたドットは、差の大きさに拘らず1カウントとする。 一部分の差異が全体の類似度に影響を与えては、正しい判断ができない。 一部分が極端に異なっていても、他の部分が一致すれば類似画像である。
gbmconv: can't read bitmap data of 0003.png: can't read file同じファイルを今度はImageMagickで処理しようとすると、次のような警告メッセージが出るが、処理自体は続行される。
Ignoring incorrect gAMA value when sRGB is also present.このgAMAとsRGBというチャンク(ヘッダ部にある情報)に不整合が起きているらしい。これに限らず、PNGのgAMAチャンク不正はかなり一般的な問題のようだ(特にMacのPhotoshopで作成した画像で多く発生するらしい)。ただし、これらは表示時のγ補正に関るもので、データ内容の根本に関る問題ではない。そもそもgAMAチャンクなどなくてもかまわないらしい。したがって、ImageMagickのように処理を続行しても構わない。
が、GBMは律義にも?エラー発生で処理を中止してしまう。これはけっこう困る。少なくとも私が所有しているPNG画像の数%程度はこのエラーが発生するからだ。無視できる量ではない。ひょっとすると、GBMでもエラーを無視して処理を続行するオプションがあるのかも知れないが、発見できなかった。
convert -geometory 8x8! -compress none 0003.png 0003.pgmこの「-compress none」オプションがテキスト化を意味するようだ。そして、この処理の 結果として得られる0003.pgmは;
P2 8 8 255 251 242 242 251 251 175 200 238 251 234 245 252 242 138 130 205 227 212 252 252 234 117 125 163 163 178 242 245 245 184 138 157 175 227 223 251 216 212 163 183 230 251 251 245 212 212 194 205 200 227 227 230 194 178 167 205 130 148 216 216 184 157 157 200この形式はちょっと扱いにくい。
convert -geometory 8x8! -comment "" img.jpg img.pgm
PGM2HEX: PROCEDURE /* バイナリ形式用 */ gbmf=ARG(1) rc=STREAM(gbmf,'C','O') rc=STREAM(gbmf,'C','seek =12') /* ヘッダをスキップ */ hex='' Do 64 /* 回数は決め打ち;複数ページ画像対策 */ ch=CHARIN(gbmf) hex=hex||LEFT(C2X(ch),1) /* 16進2桁に変換して1桁目だけを使用 */ End rc=STREAM(gbmf,'C','C') RETURN hexこちらの方が遥かにスッキリしたアルゴリズムで、処理も高速だと思われる。ちなみに、GBMで作成した濃淡コードと、ImgeMagickで作成した濃淡コードは全く互換性がない。恐らく、リサイズのアルゴリズムが異なるからだろう。混在不可。
SIMISED.CMD | 濃淡コード作成プログラム |
SIMISEF.CMD | 類似画像検索プログラム |
▼データファイル
SIMISE.DIR | 検索対象ディレクトリ・リスト |
▼外部サブルーチン
SETVAR.CMD | 共用変数設定 |
GETIMGFL.CMD | 所定のディレクトリ内から画像ファイルのみを検索して配列に入れる |
PGM2HEX.CMD | 8×8のPGMファイルから濃淡コードを作成する |
READDIRL.CMD | ディレクトリ名一覧を読み込む(コメント対応/存否確認付) |
▼動作環境
ImageMagick 4.2.2 | Hobbesから入手 |
GBM 1.76 | Hobbesから入手 |
GBMRX 1.16 | Hobbesから入手 |
▼検索ディレクトリの設定
検索対象としたいディレクトリをSIMISE.DIRに書き込む。
E:\MyImage E:\MyCG #G:\Photoo ディレクトリ名は各自の環境に合わせて変更のこと。 なお、サブディレクトリも検索対象になる。
▼濃淡コードの作成
コマンドラインからSIMISEDを実行する。
上記で指定されたディレクトリごとに、濃淡コード$pgm.datが作成される。
ファイルの出入りがあった場合には、同じ手順で濃淡コードを作り直す。
その場合、更新分のみが作成される。
注意: 同一ディレクトリ・同一ファイル名で、中身の異なるファイルに 入れ代わった場合は更新検出不可能。
▼画像の検索
コマンドラインでSIMISEFを実行する。
構文)SIMISEF ファイル名 用例)SIMISEF G:\DOWNLOAD\cg0123.jpg類似画像が見つかると、SIMISE.HTMというファイルにHTML形式で結果が書き込まれる。
[ 08 ]E:\MyCG\x2020.jpg[画像] [ 24 ]E:\MyImage\9999.jpg[画像] ………先頭の数字は相違度で、数字が小さいほど類似性が高い。 相違度の範囲は0〜64だが、初期設定では相違度25までの画像をピックアップする (閾値はSIMISEFのthreshold=25の行で指定している)。
類似性が高い場合(相違度10未満)は赤で、 類似性が低い場合(相違度20以上)は灰色で表示される。 [画像]をクリックすると、当該画像が表示される。
@内容と縦横比がまったく同じで、サイズや画像形式のみが異なるファイルはほぼ確実に検出できる。たとえば、画像の内容が全く同じならば、800×600のJPG画像でも1024×768のPNG画像でも、相違度0で検出可能。
Aゲームなどの差分画像もかなりの確率で検出できる。たとえば、顔の表情だけが異なるような画像であれば、ほぼ確実に検出可能。ただし、人物部分が同じで、背景が異なるような画像の検出は困難。
B構図が似た画像もかなり検出できる。たとえば、背景が淡い色で、人物が右上から左下に掛けて対角線上に配置されているような画像は、ものすごく沢山検出される。
反面、判別基準が濃淡分布だけであるため、色に関してはまったく判別できない。淡いピンクも薄いブルーも同一の扱いとなってしまう。また、縦横比の異なる画像は検出できない。たとえば、横長画像を縦長に回転させたり、左右をカットしたような場合は検出不可能。これは原理上のものなので仕方がない。