検索
最新記事
最新コメント
カテゴリーアーカイブ
タグクラウド
<< 2018年05月 >>
1 2 3 4 5
6 7 8 9 10 11 12
20 21 22 23 24 25 26
27 28 29 30 31
プロフィール
さんの画像

情報系を専攻する学生。 しばらく使わなかったりした知識は忘れていくのでこのブログにまとめてみたり。

広告

posted by fanblog

2017年03月08日

prewittフィルタとsobelフィルタのC言語による実装

そういえば、 C言語で24ビットBMP画像を読み込み加工する で画像のフィルタ処理のことを書くと書いておきながらすっかり忘れていました。プログラムはとっくにできてたのにね。

ちょくちょく読んでくれる人がいるみたいなのでせっかくだからコードを載せておこうかなと。しかし前のブログhtmlもうちょっと勉強しとけよ自分って思うわw。特殊文字が表示されてないw。

prewitt_sobel.png



プログラムの詳細


プログラムの詳細は(といっても読み込みと書き込みの部分だけですが)上のリンクに粗末ながら書いてあります。




プログラムの動作


起動後はパスの入力を求められるので画像のパスを入力してEnter。

これでフィルタ適用後の画像が出力されます。

prewitt_sobel_ex.png

トップの画像は左から
元の画像、prewittフィルタ、sobelフィルタ
実際にこのプログラムで加工した画像です。


コード


共通のコードをまとめた改良版もあったはずなんですがすぐ見つからなかったので諦め。


// 画像のパスを受け取りprewittフィルタとsobelフィルタを適用
// prewitt.bmp,sobel.bmpを出力
// 画像の大きさは600x600まで
// https://fanblogs.jp/iorisprogramming/

#include <stdio.h>
#include <math.h>
#include <string.h>

#define PATH 256 // ファイルパスの最大文字数
#define WIDTH 600 // 画像の最大幅
#define HEIGHT 600 // 画像の最大高さ
#define FileHeaderSize 14 // BMPのファイルヘッダーのサイズ
#define InfoHeaderSize 40 // BMPの情報ヘッダーのサイズ
#define LOW 0 // 256段階最小値
#define HIGH 255 // 256段階最大値

unsigned char BitMapFileHeader [FileHeaderSize]; // BMPのファイルヘッダーを保存する
unsigned int biSize ; // BMPのサイズを保存する
int biWidth ; // BMPの幅を保存する
int biHeight ; // BMPの高さを保存する
// 上記以外のBMPの情報ヘッダーを保存する
unsigned char BitMapInfoHeader [InfoHeaderSize];

// prewittフィルターの関数宣言
void prewitt ( unsigned char img [WIDTH][HEIGHT], unsigned char img_prewitt [WIDTH][HEIGHT]);
// sobelフィルターの関数宣言
void sobel ( unsigned char img [WIDTH][HEIGHT], unsigned char img_sobel [WIDTH][HEIGHT]);
// BMPを読み込む関数宣言
void read_img ( unsigned char path [PATH], unsigned char img [WIDTH][HEIGHT][3]);
// BMPを書き込む関数宣言
void write_img ( unsigned char path [PATH], unsigned char img [WIDTH][HEIGHT][3]);
// BMPをグレースケールに変換する関数宣言
void BMPtoGRAY ( unsigned char img [WIDTH][HEIGHT][3], unsigned char img_gray [WIDTH][HEIGHT]);
// グレースケールを計算する関数宣言
int calcGRAY ( unsigned char R , unsigned char G , unsigned char B );
// グレースケールをBMPに変換する関数宣言
void GRAYtoBMP ( unsigned char img_gray [WIDTH][HEIGHT], unsigned char img [WIDTH][HEIGHT][3]);

int main ( void ){
char path [PATH]; // 画像のパスを保存する
unsigned char img [WIDTH][HEIGHT][3]; // BMP画像を保存する
unsigned char img_gray [WIDTH][HEIGHT]; // グレースケールを保存する
unsigned char img_processed [WIDTH][HEIGHT]; // 加工後の画像を保存する

printf( "input image path>>>" ); // パスを入力
scanf( "%s" ,path); // 入力された値をpathに保存

read_img(path,img); // パスの画像を読み込んでimgに保存
BMPtoGRAY(img,img_gray); // imgのグレースケールをimg_grayに保存

prewitt(img_gray,img_processed); // img_grayにprewittフィルタを適用してimg_processedに保存
GRAYtoBMP(img_processed,img); // img_processedをBMPに変換しimgに保存
write_img( "prewitt.bmp" ,img); // prewittフィルタ適用後の画像を保存

sobel(img_gray,img_processed); // img_grayにsobelフィルタを適用してimg_processedに保存
GRAYtoBMP(img_processed,img); // img_processedをBMPに変換しimgに保存
write_img( "sobel.bmp" ,img); // sobelフィルタ適用後の画像を保存

return 0;
}

// 引数としてファイルのパスと画像を保存する配列を受け取る
void read_img ( unsigned char path [PATH], unsigned char img [WIDTH][HEIGHT][3]){
FILE * fp ; // ファイルポインタ
int i , j , RGB ; // for文用、幅、高さ、RGB
fp = fopen(path, "rb" ); // パスのファイルを読み込む
if (fp != NULL ){ // ファイルの読み込みに成功したら
fread(&BitMapFileHeader, sizeof ( char ),FileHeaderSize,fp); // ファイルヘッダーを読み込む

fread(&biSize, sizeof ( int ),1,fp); // 情報ヘッダーにあるサイズを読み込む
fread(&biWidth, sizeof ( int ),1,fp); // 情報ヘッダーにある幅を保存
fread(&biHeight, sizeof ( int ),1,fp); // 情報ヘッダーにある高さを保存
fread(&BitMapInfoHeader, sizeof ( char ),InfoHeaderSize-12,fp); // 残りの情報ヘッダーを保存 12 = int * 3
for (i = 0; i < biWidth; i++){ // 0から幅まで
for (j = 0; j < biHeight; j++){ // 0から高さまで
for (RGB = 0; RGB < 3; RGB++){ // RGBのそれぞれ
fread(&img[i][j][RGB], sizeof ( char ),1,fp); // 画素の情報を読み込んで保存する
}
}
}
fclose(fp); // ファイルを閉じる
} else { // ファイルの読み込みに失敗したら
printf( "File Not Found.\n" ); // メッセージを表示
error(); // 異常終了
}
}

// 引数としてBMPを書き込む先のパスと、書き込むBMPの画素情報が入った配列を受け取る
void write_img ( unsigned char path [PATH], unsigned char img [WIDTH][HEIGHT][3]){
FILE * fp ; // ファイルポインタ
int i , j , RGB ; // for文用、幅、高さ、RGB
fp = fopen(path, "wb" ); // パスのファイルへ書き込み
fwrite(&BitMapFileHeader, sizeof ( char ),FileHeaderSize,fp); // ファイルヘッダーを書き込む

fwrite(&biSize, sizeof ( int ),1,fp); // 情報ヘッダーへファイルサイズを書き込む
fwrite(&biWidth, sizeof ( int ),1,fp); // 情報ヘッダーへ幅を書き込む
fwrite(&biHeight, sizeof ( int ),1,fp); // 情報ヘッダーへ高さを書き込む
fwrite(&BitMapInfoHeader, sizeof ( char ),InfoHeaderSize-12,fp); // 残りの情報ヘッダーを書き込む
for (i = 0; i < biWidth; i++){ // 0から幅まで
for (j = 0; j < biHeight; j++){ // 0から高さまで
for (RGB = 0; RGB < 3; RGB++){ // RGBのそれぞれ
fwrite(&img[i][j][RGB], sizeof ( char ),1,fp); // 画素の情報を保存する
}
}
}
fclose(fp); // ファイルを閉じる
}

// 引数としてグレースケール画像と加工後の画像の保存先を受け取る
void prewitt ( unsigned char img [WIDTH][HEIGHT], unsigned char img_prewitt [WIDTH][HEIGHT]){
char H [9] = {-1, 0, 1, // 水平方向
-1, 0, 1,
-1, 0, 1};
char V [9] = {-1,-1,-1, // 垂直方向
0, 0, 0,
1, 1, 1};
int i , j , k , l ; // for文用
double sum , sumH , sumV ; // 計算後の値、水平方向、垂直方向を一時的に保存する
for (k = 1; k < biWidth - 1; k++){ // 左右の一番端以外の画素すべて
for (l = 1; l < biHeight - 1; l++){ // 上下の一番端の画素以外すべて
sumH = 0; // 値を初期化
sumV = 0; // 値を初期化
for (i = 0; i < 3; i++){
for (j = 0; j < 3; j++){
sumH += H[i*3+j]*img[k-1+i][l-1+j]; // 水平方向
sumV += V[i*3+j]*img[k-1+i][l-1+j]; // 垂直方向
}
}
sum = sqrt(pow(sumH,2)+pow(sumV,2));
if (sum < LOW){ // sumが最低値より小さい時
sum = abs(sum); // sumの絶対値をとる
} else if (sum > HIGH){ // sumが最高値より大きい時
sum = HIGH; // sumは最高値とする
}
img_prewitt[k][l] = sum; // 加工後の画素を保存
}
}
}

// 引数としてグレースケール画像と加工後の画像の保存先を受け取る
void sobel ( unsigned char img [WIDTH][HEIGHT], unsigned char img_sobel [WIDTH][HEIGHT]){
char H [9] = {-1, 0, 1, // 水平方向
-2, 0, 2,
-1, 0, 1};
char V [9] = {-1,-2,-1, // 垂直方向
0, 0, 0,
1, 2, 1};
int i , j , k , l ; // for文用
double sum , sumH , sumV ; // 計算後の値、水平方向、垂直方向を一時的に保存する
for (k = 1; k < biWidth - 1; k++){ // 左右の一番端以外の画素すべて
for (l = 1; l < biHeight - 1; l++){ // 上下の一番端の画素以外すべて
sumH = 0; // 値を初期化
sumV = 0; // 値を初期化
for (i = 0; i < 3; i++){
for (j = 0; j < 3; j++){
sumH += H[i*3+j]*img[k-1+i][l-1+j]; // 水平方向
sumV += V[i*3+j]*img[k-1+i][l-1+j]; // 垂直方向
}
}
sum = sqrt(pow(sumH,2)+pow(sumV,2));
if (sum < LOW){ // sumが最低値より小さい時
sum = abs(sum); // sumの絶対値をとる
} else if (sum > HIGH){ // sumが最高値より大きい時
sum = HIGH; // sumは最高値とする
}
img_sobel[k][l] = sum; // 加工後の画素を保存
}
}
}

// 引数としてBMPと加工後の画像の保存先を受け取る
void BMPtoGRAY ( unsigned char img [WIDTH][HEIGHT][3], unsigned char img_gray [WIDTH][HEIGHT]){
int i , j ; // for文用
int GRAY ; // 計算後のグレースケール値を保存する
for (i = 0; i < biWidth; i++){ // 0から幅まで
for (j = 0; j < biHeight; j++){ // 0から高さまで
GRAY = calcGRAY(img[i][j][0], img[i][j][1], img[i][j][0]); // グレースケール値を計算
img_gray[i][j] = GRAY; // 計算したグレースケール値を保存
}
}
}

// 引数としてRGBを受け取る
int calcGRAY ( unsigned char R , unsigned char G , unsigned char B ){
int GRAY ; // グレースケール値を保存
GRAY = ( int )(0.299*R+0.587*G+0.114*B); // グレースケール補正
if (GRAY < LOW){ // グレースケール値が最低値より小さい時
GRAY = LOW; // グレースケール値は最低値とする
} else if (GRAY > HIGH){ // グレースケール値が最高値より大きい時
GRAY = HIGH; // グレースケール値は最高値とする
}
return GRAY; // グレースケール値を返す
}

// 引数としてグレースケールと加工後の画像の保存先を受け取る
void GRAYtoBMP ( unsigned char img_gray [WIDTH][HEIGHT], unsigned char img [WIDTH][HEIGHT][3]){
int i , j , RGB ; // for文用
for (i = 0; i < biWidth; i++){ // 0から幅まで
for (j = 0; j < biHeight; j++){ // 0から高さまで
for (RGB = 0; RGB < 3; RGB++){ // RGBすべて
img[i][j][RGB] = img_gray[i][j]; // グレースケール値をRGBに入れる
}
}
}
}



苦しんで覚えるC言語

新品価格
¥2,376 から
(2017/3/8 00:45時点)




タグ: prewitt sobel
【このカテゴリーの最新記事】
posted by iorisprogramming at 00:18 | Comment(0) | TrackBack(0) | C
この記事へのコメント
コメントを書く

お名前:

メールアドレス:


ホームページアドレス:

コメント:

※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバックURL
https://fanblogs.jp/tb/6025846
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック
Build a Mobile Site
スマートフォン版を閲覧 | PC版を閲覧
Share by: