プロが教える店舗&オフィスのセキュリティ対策術

下記のプログラムはPGM画像に組織的ディザ法を行い、2値化を行うプログラムなのですがうまく作動しません。
どこがダメなのかわかる方回答お願いします。

また、PGMのフォーマットをP5しか読み込むことしか出来ないのですが、これを
P2のアスキーで読み込めるように変更できないでしょうか?




/* 組織的ディザ法のプログラム dither.c */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"mypgm.h"
#define BLOCK_SIZE 4 /* ブロックの横(=縦)画素数 */
#define NEW_LEVEL 16 /* 擬似階調数(= BLOCK_SIZE の2乗) */
#define MAXWIDTH 1000
#define MAXHEIGHT 1000

/* 原画像 image1[y][x] のディザ画像を作り image2[y][x] に代入 */
void make_dither_image( )
{
double width; /* 16段階画像の階調値の単位幅 */
int x,y,i,j,m,n;
int x_block = x_size1 / BLOCK_SIZE; /* 横のブロック数 */
int y_block = y_size1 / BLOCK_SIZE; /* 縦のブロック数 */
int gray_16 = (int)( image1[y][x] / width ); /* 新しい階調(16階調での値) */

/* Bayer 型ディザ行列 */
int dither_matrix [4][4] = {
{ 0, 8, 2, 10},
{12, 4, 14, 6},
{ 3, 11, 1, 9},
{15, 7, 13, 5}
};

/* 横,縦の画素数がBLOCK_SIZEの倍数であるかのチェック */
if ( x_size1 % BLOCK_SIZE != 0 || y_size1 % BLOCK_SIZE != 0 ){
printf("原画像の横・縦の画素数が不適切です.\n");
exit(1);
}

/* 16階調の画像を作る */ //一度、画像を16階調に変換して(正確にはディザブロック分の1)さらに2階調(白黒)に変換する。
width = MAX_BRIGHTNESS / (double)NEW_LEVEL;
x_size2 = x_size1; y_size2 = y_size1;
for (y = 0; y < y_size1; y ++ ){
for (x = 0; x < x_size1; x ++ ){
if ( gray_16 > NEW_LEVEL - 1 ) gray_16 = NEW_LEVEL - 1;
image2[y][x] = (unsigned char)gray_16;
}
}

/* ディザ画像を作る */
printf("ディザ画像を作ります.\n");
for (i = 0; i < y_block; i ++ ){
for (j = 0; j < x_block; j ++ ){
int x = BLOCK_SIZE * j;
int y = BLOCK_SIZE * i;
for (m = 0; m < BLOCK_SIZE; m ++ ){
for (n = 0; n < BLOCK_SIZE; n ++ ){
if ( image2[y + m][x + n] <= dither_matrix[m][n] ) image2[y + m][x + n] = 0;
else image2[y + m][x + n] = MAX_BRIGHTNESS;
}
}
}
}

}


【mypgm.h】
http://cis.k.hosei.ac.jp/~wakahara/mypgm.h

A 回答 (2件)

P2形式のPGMに対応したいのであれば、画像読み込みルーチンの方をP2に対応させる必要がありますが、


今回挙げられているディザ処理そのものは、今のままでまったく問題はありません。

画像読み込み部の対応ですが、ヘッダ部はP5もP2も同じです。
実データ読み取り部で、P2だった時は fgetc の代わりに、
---
int value;
fscanf(fp, "%d", &value);
image[y][x] = value;
---
といったコードにするだけでいけます。

あと、今回の質問とは直接関係ありませんが、
4×4のディザの階調数は16ではなく17です。(「1が0個」~「1が16個」の17通り)
今のコードだと、一番明るい白が輝度値15にしていますが、15の時は4x4の左下が0になってしまい、全面白ではなく、黒の点が出てきます

この回答への補足

mtaka2さん
回答ありがとうございます。
mtaka2さんの言われたとおりに
int value;
fscanf(fp, "%d", &value);
image[y][x] = value;

に変更いたしましたが、P2のPGMファイルを読み込むと
「ファイルのフォーマットがP5ではありません」
と出てきて、操作を終了してしまいます。

下記のプログラムを変えなければならないのでしょうか?
初心者のために答えがわかりません。教えていただけないでしょうか。

fgets(buffer, MAX_BUFFERSIZE, fp);
if (buffer[0] != 'P' || buffer[1] != '5')
{
printf("  ファイルのフォーマットがP5ではありません\n\n");
exit(1);

補足日時:2008/10/23 22:38
    • good
    • 0

・P2(テキスト)形式のpgmは、ファイルの先頭(1行目)が「P2」で始まります。


・P5(バイナリ)形式のpgmは、ファイルの先頭(1行目)が「P5」で始まります。

> if (buffer[0] != 'P' || buffer[1] != '5')
このif文は、「1文字目がP以外」もしくは「2文字目が5以外」だったら、真になり、printfとexitを実行します。
その結果、2文字が「P5」だった時にかぎり、exitしないという動作になります。

ですから「P2専用」にするなら、ここの「5」を「2」にすればOKです。

余力があるなら、「P2」と「P5」のどちらでも終了しないようにして、
P2のときはデータ読み込みにfscanfを使い、P5の時はfgetc、と使い分けるようなコードにした方がいいでしょう。

この回答への補足

コンパイルに成功し、P2のPGMデータも読み込み、ディザ画像を作ることに成功しました。本当にありがとうございます。

しかし、その画像が真っ黒でした…

どうしてなのでしょうか?

何度も初心者の質問をしてしまい、本当にすいません。

補足日時:2008/10/24 00:18
    • good
    • 0
この回答へのお礼

わかりました。ありがとうございます。

色々と問題があるのでまた質問するかもしれませんが、そのときはよろしくお願いします。

お礼日時:2008/10/24 00:16

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!