ShihTzu
@ShihTzu

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

グレースケールの入力画像の2値画像を大津の二値化で出力したい

解決したいこと

グレースケールの入力画像の2値画像を出力するプログラム(しきい値は大津の二値化で自動的に決定。)を作りたいです。
実行したところ、出力画像が真っ黒になってしまいます。おそらく二値化がうまく動いてないのかなとは思いますが、どう修正していいか全く分かりません。解決方法を教えてください。

発生している問題・エラー

エラーの表示はありませんが、出力画像がおかしいです。入力画像と出力画像を以下に貼り付けます。
スクリーンショット 2022-09-12 20.53.03.png

スクリーンショット 2022-09-12 20.43.41.png

該当するソースコード

/****************
* 判別分析法を用いた二値化 *
*****************/

#include <stdio.h>
#include <stdlib.h>
#include "image.h"

void file_in(char *file_name, unsigned char **input, int size_x, int size_y);
void file_out(char *file_name, unsigned char **output, int size_x, int size_y);
//void Expansion(unsigned char **input, unsigned char **output, int size_f, int size_x, int size_y);
long int hist[256];

void ootu(unsigned char **input, unsigned char **output, int size_x, int size_y){
    double sb2_max = 0;
	int value;
    for(int t_num = 0; t_num < 256; t_num ++){
        double sb2 = 0;
        double w0 = 0, w1 = 0, m0 = 0, m1 = 0;
        int class0 = 0, sum0 = 0, ave0 = 0;
        int class1 = 0, sum1 = 0, ave1 = 0;
		int i,j;
        for(int i = 0; i < 128; i ++){
            for(int j = 0; j < 128; j ++){
                if(input[i][j] < t_num){
                    sum0 = sum0 + input[i][j];
                    class0 ++;
                }else{
                    sum1 = sum1 + input[i][j];
                    class1 ++;
                }
            }
        }
        w0 = class0/(double)16384;
        w1 = class1/(double)16384;
        if(class0 == 0){
            m0 = 0;
        }else{
            m0 = sum0/class0;
        }
        if(class1 == 0){
            m1 = 0;
        }else{
            m1 = sum1/class1;
        }
        sb2 = w0 * w1 * (m0 - m1) * (m0 - m1);
        if(sb2 > sb2_max){
            sb2_max = sb2;
            value = t_num;
        }
    }
	int ix, iy;// ループ用変数
	

		
	  
	        for(iy=0;iy<size_y;iy++){
        	     for(ix=0;ix<size_x;ix++){	
         	        if(input[iy][ix]<= value){
						 output[iy][ix]=0;}
					else {
						output[iy][ix]=255;}
		    		}
      			}
}



int main(int argc, char *argv[])
{
	int		ix, iy;		// ループ用変数
	int		size_x, size_y;	// 入力画像の大きさ
	//int		size_f;		// フィルタの大きさ
	unsigned char	**input;	// 入力画像
	unsigned char	**output;	// 出力画像
	FILE		*fp;		// ファイルポインタ
	FILE		*hoge;		//パイプを開く
	/*************
	* 引数の確認 *
	*************/
	if (argc!=3 && argc!=5) {
		printf("Usage: EXPANSION [in_file] [out_file] {size_x} {size_y}\n");
		exit(1);
	}

	if (argc == 3) {
		//size_f = atoi(argv[3]);
		size_x = SIZE_X;
		size_y = SIZE_Y;
	}

	if (argc == 5) {
		//size_f = atoi(argv[3]);
		size_x = atoi(argv[3]);
		size_y = atoi(argv[4]);
	}

	/*********************
	* 画像格納領域の確保 *
	*********************/
	input = (unsigned char **)malloc(size_y*sizeof(unsigned char *));
	if (input == NULL) {
		printf("MEMORY ERROR!\n");
		exit(1);
	}
	for (iy=0; iy<size_y; iy++) {
		input[iy] = (unsigned char *)malloc(size_x*sizeof(unsigned char));
		if (input[iy] == NULL) {
			printf("MEMORY ERROR!\n");
			exit(1);
		}
	}
	output = (unsigned char **)malloc(size_y*sizeof(unsigned char *));
	if (output == NULL) {
		printf("MEMORY ERROR!\n");
		exit(1);
	}
	for (iy=0; iy<size_y; iy++) {
		output[iy] = (unsigned char *)malloc(size_x*sizeof(unsigned char));
		if (output[iy] == NULL) {
			printf("MEMORY ERROR!\n");
			exit(1);
		}
	}

	/*******************************
	* ファイル入出力・フィルタ処理 *
	*******************************/
	file_in(argv[1], input, size_x, size_y);		// 画像ファイルの読込
	//histogram();				//ヒストグラムを作成
	//ootu(input);
	//binarize();
	file_out(argv[2], output, size_x, size_y);		// 画像ファイルの出力
	
	//return 0;
}

自分で試したこと

しきい値valueの定義文の位置を何回か移動してみて実行を繰り返しましたが、解決しませんでした。

0

2Answer

原因

  • ootu()関数がコメントアウトされて実行されてない
  • 出力画像unsigned char **outputがサイズ確保後,何らいじられていない

など複数の要因が考えられます.これでは確保された領域に保存されていた値がそのまま使われるだけで,入っていた値が全部たまたま0,すなわち全面黒になったものと思われます.

改善案

  • ootu()関数のコメントアウトを外す
  • ootu()関数に出力画像outputをちゃんと渡す

などの改善案が考えられます.

また,ootu()関数では意図していなさそうな整数同士の除算sum0/class0などが存在しており,正確な値が計算できていない可能性もあります.浮動小数点数での演算が必要なら適宜キャストしてください.

他にも,25行目の比較条件input[i][j] < t_numと59行目の比較条件input[iy][ix]<= valueが不一致であることも,適切でないと考えられます.$<$と$\leq$でどちらかに揃える必要があると思われます.

0Like

Comments

  1. @ShihTzu

    Questioner

    コメントありがとうございます。
    修正後実行すると、入力画像が二値画像の場合はうまくいきましたが、グレー値も含むモノクロ画像の場合は、コアダンプになったり、白黒の砂嵐のような画像が、画面の上半分くらいまで出ていて、それより下は真っ白になってしまいました。
    原画像の面影はありません。
    行った修正は以下です。
    ・ootu関数のコメントアウトを外す
    ・main関数内125行目のootu()→ootu(input, output, size_x, size_y)に訂正
  2. ・23,24行目のループ回数がハードコーディングされており,128回で固定となっております.コアダンプの原因になります.画像サイズに依存させるためにsize_x等にするべきだと考えられます.

    ・原画像の面影が無いというよりは,依然として出力画像outputに変更がなく,たまたま入っていた値が出力画像に現れただけだと思います.

    ・動作確認のために,閾値valueの初期値を-1で初期化して実行してみてください.また,ootu関数の最後にvalueを標準出力させた値を教えてください.
  3. @ShihTzu

    Questioner

    valueの標準出力は156と出ました。
    なお、出力結果は変わらず砂嵐です。
  4. であればコードに異常はありません,入力に使った画像のフォーマットがおかしいとか,そういった話になりそうです.
  5. @ShihTzu

    Questioner

    確かに他の数種類の入力画像で試したら二値化されていそうな画像が出ましたので、入力画像に異常があるのかもしれません。ありがとうございます。助かりました。

とりあえずootuを

void ootu(unsigned char **input, unsigned char **output, int size_x, int size_y) {
  int x, y;
  for (y=0; y<size_y; y++) {
    for (x=0; x<size_x; x++) {
      output[y][x] = input[y][x];
    }
  }
}

と「入力バッファの内容を出力バッファにコピーするだけ」にして試してみましょう。

これで正しく出力されればootuの中でおかしくなっている、正しく出力されなければファイル入出力の方がおかしいのでootuの中身をいじっても無駄ということになります。

0Like

Comments

  1. @ShihTzu

    Questioner

    コメントありがとうございます。やはり入力画像に異常があるみたいです。

Your answer might help someone💌