Prewittフィルタとは1次の微分フィルタの1種で画像のエッジ抽出などに使われます.一般的にエッジ部分では色の変化が大きく,他の部分では変化が小さいため, x軸ならx軸方向に並んだRGB情報を微分した値を新たなRGB情報とすることで,結果的にエッジ部分に大きい値が現れ,他の部分は値が小さくなりエッジ部分を抽出することができます.微分というと難しそうですが,デジタル画像においてRGB情報は連続ではなく,離散的になっているために引き算をすればいいだけです.
Prewittフィルタは上の式のようになります.このフィルタを注目しているピクセルを中心に適用してやることで注目しているピクセルの値が得られます.前者の式は横方向の微分で,後者は縦方向の微分を行います.しかし,1方向だけで値を出してしまうともう一方の方向のエッジを抽出できません.そこで,
とすることで両方の変化を反映させることができます.また,片方だけでフィルタをかける場合は得られる値がマイナスの場合も考慮して,絶対値を取る必要があります.
for(i=1; i<img->height-1; i++){ for(j=1; j<img->width-1; j++){ sumrw = sumrh = sumgw = sumgh = sumbw = sumbh = 0; for(k=-1; k<=1; k++){ for(l=-1; l<=1; l++){ sumrw += l * img->data[(i+k)*img->width + j + l].r; sumrh += k * img->data[(i+k)*img->width + j + l].r; sumgw += l * img->data[(i+k)*img->width + j + l].g; sumgh += k * img->data[(i+k)*img->width + j + l].g; sumbw += l * img->data[(i+k)*img->width + j + l].b; sumbh += k * img->data[(i+k)*img->width + j + l].b; } } temp->data[i*temp->width + j].r = sqrt((double)(sumrw*sumrw + sumrh*sumrh)); temp->data[i*temp->width + j].g = sqrt((double)(sumgw*sumgw + sumgh*sumgh)); temp->data[i*temp->width + j].b = sqrt((double)(sumbw*sumbw + sumbh*sumbh)); } }
式がいくつか出てきたわりにはプログラムは今までと大してかわりません.ただ,ルートを取るsqrtの関数はmath.hを使っていますので,Makefileは,
bmp_samp: main.o bitmap.o gcc -o bmp_samp -lm main.o bitmap.o main.o: main.c bitmap.h gcc -c main.c bitmap.o: bitmap.c bitmap.h gcc -c bitmap.c clean: rm bmp_samp *.o rm *~
このように-lmを付ける必要があります.また,カラーのままPrewittフィルタにかけてもいいのですが,グレースケールのほうがきれいに抽出できるので,main.cで先にGrayscaleを使用しています.