質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

フィルタ

フィルタとは、特定の条件に合わせてデータへのアクセスをブロックするプログラムやルーチンを指します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

4085閲覧

C言語でガウシアンフィルタの実装をしたい

Trebey

総合スコア7

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

フィルタ

フィルタとは、特定の条件に合わせてデータへのアクセスをブロックするプログラムやルーチンを指します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2018/10/25 11:50

編集2018/10/25 12:41

前提・実現したいこと

c言語で、(24bit)ビットマップを対象に、3*3のガウシアンフィルタを実装したいと考えています。
OpenCVなどの、画像処理用ライブラリは使わずに実装しようとしています。
画像の処理の流れとしては、
ビットマップ画像をグレースケール化→さらにガウシアンフィルタをかける
というものです。
ただし、端の4辺は、グレースケール化したものをそのまま出力するものとしています。

発生している問題・エラーメッセージ

画像を読み込み、グレースケール化するところまではできている(と思います)。

しかし、ガウシアンフィルタをかけると、「ぼやける(平滑化される)」はずが、
左右に分身するような現象が起きてしまいます(「試したこと」欄に記載)。
コードに間違いがあると思いますので、ご指摘お願いいたします。

該当のソースコード

c言語

1/********************************************** 2gaussian: ビットマップ画像のグレースケール化、ガウシアンフィルタ 3概要:入力画像をグレースケール化し、ガウシアンフィルタを掛ける 4**********************************************/ 5#include <stdio.h> 6#include <math.h> 7#include <stdlib.h> 8#include <string.h> 9 10int main(void){ 11//unsigned char img[512][512][3]; //読み込んだ画素情報を保存する(512*512まで可能) 12unsigned char BitMapFileHeader[14]; //BMPのファイルヘッダーを保存する 13unsigned int biSize; //BMPのサイズを保存する 14int biWidth; //BMPの幅を保存する 15int biHeight; //BMPの高さを保存する 16unsigned char BitMapInfoHeader[28]; //上記3つ以外のBMPの情報ヘッダーを保存する 17int i,j,c; //rgb入力for文用 18 19 20 21char filename[50]; 22printf("please write a Bitmap filename(without [.bmp])\n"); 23scanf("%s",filename); 24 25printf("\n"); 26if(filename==NULL){ 27 printf("please write a Bitmap filename(without [.bmp])\n"); 28 scanf("%s",filename); 29} 30 31 32char toGray[50]; 33char toGaussian[50]; 34strcpy(toGray,filename); 35strcpy(toGaussian,filename); 36FILE *fp; //ファイルポインタ 37fp = fopen(strcat(filename,".bmp"),"rb"); 38 39 40//読み込み 41fread(&BitMapFileHeader,sizeof(char),14,fp); //ファイルヘッダーを読み込む 42fread(&biSize,sizeof(int),1,fp); //情報ヘッダーにあるサイズを読み込む 43fread(&biWidth,sizeof(int),1,fp); //情報ヘッダーにある幅を保存 44fread(&biHeight,sizeof(int),1,fp); //情報ヘッダーにある高さを保存 45fread(&BitMapInfoHeader,sizeof(char),28,fp); //残りの情報ヘッダーを保存 46 47//ビットマップは、横の幅が4の倍数になるまで0を加えるので、横幅を調整 48while(1){ 49 if(biWidth%4 == 0){ 50 break; 51 } 52biWidth ++; 53} 54 55unsigned char img[biWidth][biHeight][3];//画像幅、高さ、rgb分を確保 56unsigned char gray[biWidth][biHeight];//画像幅、高さ、rgb分を確保 57unsigned char gaussian[biWidth][biHeight];//ガウシアンフィルタ処理後の値を格納 58for(i = 0; i < biWidth; i++){ //0から幅まで 59 for(j = 0; j < biHeight; j++){ //0から高さまで 60 for(c = 0; c < 3; c++){ //RGBのそれぞれ 61 fread(&img[i][j][c],sizeof(char),1,fp); //画素の情報を読み込んで保存する 62 63 } 64 } 65} 66 67fclose(fp); //ファイルを閉じる 68 69printf("width: %d\nheight: %d\n",biWidth,biHeight); 70 71//グレースケール書き出し 72char *grayfile = strcat(toGray,"_gray.bmp"); 73fp = fopen(grayfile,"wb"); //パスのファイルへ書き込み 74fwrite(&BitMapFileHeader,sizeof(char),14,fp); //ファイルヘッダーを書き込む 75 76fwrite(&biSize,sizeof(int),1,fp); //情報ヘッダーへファイルサイズを書き込む 77fwrite(&biWidth,sizeof(int),1,fp); //情報ヘッダーへ幅を書き込む 78fwrite(&biHeight,sizeof(int),1,fp); //情報ヘッダーへ高さを書き込む 79fwrite(&BitMapInfoHeader,sizeof(char),28,fp); //残りの情報ヘッダーを書き込む 80 81 82for(i = 0; i < biWidth; i++){ //0から幅まで 83 for(j = 0; j < biHeight; j++){ //0から高さまで 84 //gray = (img[i][j][0] + img[i][j][1] + img[i][j][2]) / 3; 85 gray[i][j] = img[i][j][2] * 0.3 + img[i][j][1] * 0.59 + img[i][j][0] * 0.11;//ビットマップは、BGRの順で記述される 86 87 for(c = 0; c < 3; c++){ 88 fwrite(&gray[i][j],sizeof(char),1,fp); //画素の情報を保存する 89 } 90 } 91} 92 93 94fclose(fp); //ファイルを閉じる 95 96 97//ガウシアンフィルタ書き出し 98 99int side; 100int vertical; 101char *bifile = strcat(toGaussian,"_gaussian.bmp"); 102fp = fopen(bifile,"wb"); //パスのファイルへ書き込み 103fwrite(&BitMapFileHeader,sizeof(char),14,fp); //ファイルヘッダーを書き込む 104 105fwrite(&biSize,sizeof(int),1,fp); //情報ヘッダーへファイルサイズを書き込む 106fwrite(&biWidth,sizeof(int),1,fp); //情報ヘッダーへ幅を書き込む 107fwrite(&biHeight,sizeof(int),1,fp); //情報ヘッダーへ高さを書き込む 108fwrite(&BitMapInfoHeader,sizeof(char),28,fp); //残りの情報ヘッダーを書き込む 109 110 111for(i = 0; i < biWidth; i++){ //0から幅まで 112 for(j = 0; j < biHeight; j++){ //0から高さまで 113 gaussian[i][j] = 0;//初期化 114 } 115} 116 117 118for(i = 0; i < biWidth; i++){ //0から幅まで 119 for(j = 0; j < biHeight; j++){ //0から高さまで 120 //ガウシアンフィルタ 121 122 if( (i>0) && (i<biWidth-1) && (j>0) && (j<biHeight-1) ){ 123 //gaussian[i][j] = gray[i][j]/16*4 + (gray[i-1][j-1]/16)*1 + (gray[i-1][j]/16)*2 + (gray[i-1][j+1]/16)*2 + (gray[i][j-1]/16)*2 + (gray[i][j+1]/16)*2 + (gray[i+1][j-1]/16)*1 + (gray[i+1][j]/16)*2 + (gray[i+1][j+1]/16)*1; 124 125 //周辺のものと加算 126 for(side = i-1; side < i+2; side++){ 127 for(vertical = j-1; vertical < j+2; vertical++){ 128 129 if( (side == i) && (vertical == j) ){ 130 //自分自身を指す場合 131 gaussian[i][j] += (gray[side][vertical] /16) * 4; 132 } 133 else if( ( (side == i) && (vertical != j) ) || ( (side != i) && (vertical == j) ) ){ 134 //上下左右のどれか 135 gaussian[i][j] += (gray[side][vertical] /16) * 2; 136 137 } 138 else if( (side != i) && (vertical != j) ){ 139 //四隅のどれか 140 gaussian[i][j] += (gray[side][vertical] /16) * 1; 141 } 142 } 143 } 144 } 145 else{//端の4辺 146 gaussian[i][j] = gray[i][j]; 147 } 148 149 for(c = 0; c < 3; c++){ //RGBのそれぞれ(順番は、[0]B [1]G [2]R) 150 fwrite(&gaussian[i][j],sizeof(char),1,fp); //画素の情報を保存する 151 } 152 153 } 154} 155 156fclose(fp); //ファイルを閉じる 157 158return 0; 159}

###試したこと
画像(jpeg)を示します。
元画像
イメージ説明
グレースケール化
イメージ説明
ガウシアンフィルタ(左右に分身がでてしまう)
イメージ説明

補足情報

コンパイラ:gcc(win)
エディタ:Visual Studio Code

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんにちは。

ざっと見ただけなので外しているかもしれませんが、通常ビットマップ・ファイルは、横方向に走査されます。
それに対して、縦方向に走査したような処理になっています。縦横サイズが異なる画像ですので、操作方向の相違でズレているのかも知れません。
グレイスケール変換時は、1ピクセルだけで処理が完結するので走査方向の相違の影響は受けない筈です。

投稿2018/10/25 15:02

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

wwbQzhMkhhgEmhU

2018/10/25 15:28

ようはとりあえずループ回数に指定されるheightとwidth入れ替えてみたら?ってことかな(適当)
Trebey

2018/11/01 02:52

読み込みと、フィルタをかけるところの走査方向を横向きに(行ごとに)したところ、それらしくなりました!ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問