Qt/Gcc
2012.08.16作成
2-7cimginterfaceクラス
imaginterfaceクラスは、画像処理のメインクラス(画像処理関数を集めている)であるimagefuncクラスと画像データとの受け渡しを行うクラスです。
具体的な機能は、以下の2つです。
(1)画像データの数分だけ、画像処理関数を呼び出す。具体的には、画像のRGBそれぞれに画像処理を実施する場合は、画像処理関数を3回呼び出す。
(2)画像配列の変換を行う。具体的には二次元配列を一次元配列に変換したり、その逆をしたりする。
(2)については、ご存知の方が多いと思いますが、汎用の画像処理関数は、一次元配列で処理するものがあるためです。
一次元配列にするメリットは、ポインタでのアクセスによって高速に処理できることと、画像配列用のバッファをmallocやnewで確保することが簡単だからです。
●cimginterface.h
各画像処理関数のインターフェースとなる関数を定義しています。
#ifndef CIMGINTERFACE_H
#define
CIMGINTERFACE_H
#include"cfftdatacreate2d.h"
#include"cimagefunc.h"
class
Cimginterface
{
public:
Cimginterface();//コンストラクタ
int
fftinterfaceRGB(Cfftdatacreate2d *in_fft2d,Cfftdatacreate2d
*out_fft2d);//fftを実施するためのインターフェース関数。GUIのmainwindowクラスから呼ばれる
int IfftinterfaceRGB(Cfftdatacreate2d *in_fft2d,Cfftdatacreate2d
*out_fft2d);//Ifftを実施するためのインターフェース関数。GUIのmainwindowクラスから呼ばれる
int WinerinterfaceRGB(Cfftdatacreate2d *in_fft2d,Cfftdatacreate2d
*out_fft2d);//winnerフィルタを実施するためのインターフェース関数。
int
laplacianInterfaceRGB(Cfftdatacreate2d *in_fft2d,Cfftdatacreate2d
*out_fft2d);//ラプラシアンを実施するためのインターフェース関数。
private:
int fftprocess(unsigned
char **indata,double **l_inar,double **l_inai,unsigned char**outdata,double
**l_outar,double **l_outai,int lxsize,int lysize,int lfftflag,int
lfilteron);//fftを実施する関数を呼び出すための関数
int
winerprocess(unsigned char **indata,unsigned char **outdata,double
**linar,double **linai,int lxsize,int
lysize);//winnerフィルタを実施する関数を呼び出すための関数
};
#endif // CIMGINTERFACE_H
「fftinterfaceRGB(Cfftdatacreate2d *in_fft2d,Cfftdatacreate2d
*out_fft2d);」は、実画像を入力としてfftしたデータを出力としています。
ここで、Cfftdatacreate2dは、fftまたはifftを実施するために必要なデータを保持するクラスです。
「IfftinterfaceRGB(***)」は、fftしたデータを逆変換して元の画像データに戻します。
「WinerinterfaceRGB(Cfftdatacreate2d
*in_fft2d,Cfftdatacreate2d
*out_fft2d)」は、fftを応用したクラスです。ウィナーフィルタを実施しています。
この関数は、元データは画像データでそれを受け取って、fft->周波数空間でのフィルタリング->逆fftという順番に処理して、out_fft2dにその結果(画像データ)を
保持します。
「laplacianInterfaceRGB(***)」は画像データにデジタル線形フィルタ(微分フィルタ)の一種であるラプラシアンフィルタを実施する関数です。
プライベート宣言として、「fftprocess()」と「winerprocess()」を定義しています。最初の関数はfftと逆fftを実施するときに必要なデータを渡しています。
後者はwinerフィルターを実施するのに必要なデータを渡しています。
詳しくは実装で説明します。
●cimginterface.cpp
はじめに以下のヘッダファイルをインクルードします。これは、二次元fftのクラスと画像処理用の関数群をのクラスです。
#include"CFft_2D.h"
#include"cimagefunc.h"
以下の関数は画像のRGB各データにfftを実施します。
fftと逆fftはここでは、自分で実装していますが、汎用のライブラリがいくつかありますので、それを使った方が処理結果など
より高速で信頼性の高い結果が得られると思います。
この関数は実空間での画像データ(つまり普通の画像データ:RGB各8bit)を渡して、内部で処理をしています。
少し、詳しく解説します。
fftにて空間周波数に変換すると、実数部と虚数部のデータが得られます。これをそれぞれ、ar、aiとしています。
fft後の空間周波数を表現する場合、このarとaiを二乗してルートをとります。つまり、パワーとして表現します。
このデータは、RGBそれぞれに定義されています。したがって、カラー画像の場合、fftを3回実施することになります。
//in_fft2d:画像データここでは、実画像
//out_fft2d:処理後のデータ。このデータにfft処理された空間周波数のデータと空間周波数を画像化したデータが格納されている
//return
1:成功,return -1:失敗
int Cimginterface::fftinterfaceRGB(Cfftdatacreate2d
*in_fft2d,Cfftdatacreate2d *out_fft2d)
{
int xsize,ysize;
const int fftflag=1;//fft
const int filteron=0;//fft
これはなくてもよい。以前のプログラムの流用しているので残っている。
xsize=in_fft2d->hsize;//画像データの水平方向サイズをコピー
ysize=in_fft2d->vsize;//画像データの垂直方向サイズをコピー
//以下はRGBそれぞれに対してfftを実施するため3回呼び出している。
if(fftprocess(in_fft2d->Gdata,in_fft2d->Gar,in_fft2d->Gai,out_fft2d->Gdata,out_fft2d->Gar,out_fft2d->Gai,xsize,ysize,fftflag,filteron)==-1)
{
QMessageBox::warning(0,"fail!!","can't fft data size is'nt
2n");
return -1;
}
if(fftprocess(in_fft2d->Rdata,in_fft2d->Rar,in_fft2d->Rai,out_fft2d->Rdata,out_fft2d->Rar,out_fft2d->Rai,xsize,ysize,fftflag,filteron)==-1)
{
QMessageBox::warning(0,"fail!!","can't fft data size is'nt
2n");
return -1;
}
if(fftprocess(in_fft2d->Bdata,in_fft2d->Bar,in_fft2d->Bai,out_fft2d->Bdata,out_fft2d->Bar,out_fft2d->Bai,xsize,ysize,fftflag,filteron)==-1)
{
QMessageBox::warning(0,"fail!!","can't fft data size is'nt
2n");
return -1;
}
out_fft2d->hsize=xsize;
out_fft2d->vsize=ysize;
//今回のFFTデータはGデータのみなので、Gデータを全部にコピーした
/* for(int
y=0;y<ysize;y++){
for(int
x=0;x<xsize;x++){
out_fft2d->Rdata[x][y]=out_fft2d->Gdata[x][y];
out_fft2d->Bdata[x][y]=out_fft2d->Gdata[x][y];
out_fft2d->Rar[x][y]=out_fft2d->Gar[x][y];
out_fft2d->Rai[x][y]=out_fft2d->Gai[x][y];
out_fft2d->Bar[x][y]=out_fft2d->Gar[x][y];
out_fft2d->Bai[x][y]=out_fft2d->Gai[x][y];
}
}*/
return
1;
}
次に逆fftの関数を示します。
この関数は、fftを実施したデータが存在することが前提で呼び出しています。
in_fft2dのメンバー変数であるarとaiにはfftしたときの実数部と虚数部のデータが格納されています。
このデータを逆fftすることによって、out_fft2dのGdata,Bdata,Rdataに逆変換後の画像データを格納します。
ソースコードをみるとfftinterfaceRGBもIfftinterfaceRGBもほぼ同じで、関数内のfftflag,filteronに与える初期値に
よってどちらの処理をするか決めています。ここは改良の余地があります。
//in_fft2d:ここでは、fft後のar、aiを確保している変数
//out_fft2d:処理後のデータ。このデータにfft処理された空間周波数のデータと空間周波数を画像化したデータが格納されている
//return
1:成功,return -1:失敗
int Cimginterface::IfftinterfaceRGB(Cfftdatacreate2d
*in_fft2d,Cfftdatacreate2d *out_fft2d)
{
int xsize,ysize;
const int fftflag=-1;//ifftするときはこのフラグを-1にする。
const int
filteron=1;//ifftするときはこのフラグを1にする。
xsize=in_fft2d->hsize;
ysize=in_fft2d->vsize;
if(fftprocess(in_fft2d->Gdata,in_fft2d->Gar,in_fft2d->Gai,out_fft2d->Gdata,out_fft2d->Gar,out_fft2d->Gai,xsize,ysize,fftflag,filteron)==-1)
{
QMessageBox::warning(0,"fail!!","can't ifft data size is'nt
2n");
return -1;
}
if(fftprocess(in_fft2d->Rdata,in_fft2d->Rar,in_fft2d->Rai,out_fft2d->Rdata,out_fft2d->Rar,out_fft2d->Rai,xsize,ysize,fftflag,filteron)==-1)
{
QMessageBox::warning(0,"fail!!","can't ifft data size is'nt
2n");
return -1;
}
if(fftprocess(in_fft2d->Bdata,in_fft2d->Bar,in_fft2d->Bai,out_fft2d->Bdata,out_fft2d->Bar,out_fft2d->Bai,xsize,ysize,fftflag,filteron)==-1)
{
QMessageBox::warning(0,"fail!!","can't ifft data size is'nt
2n");
return -1;
}
out_fft2d->hsize=xsize;
out_fft2d->vsize=ysize;
//今回のFFTデータはGデータのみなので、Gデータを全部にコピーした
/* for(int
y=0;y<ysize;y++){
for(int
x=0;x<xsize;x++){
out_fft2d->Rdata[x][y]=out_fft2d->Gdata[x][y];
out_fft2d->Bdata[x][y]=out_fft2d->Gdata[x][y];
out_fft2d->Rar[x][y]=out_fft2d->Gar[x][y];
out_fft2d->Rai[x][y]=out_fft2d->Gai[x][y];
out_fft2d->Bar[x][y]=out_fft2d->Gar[x][y];
out_fft2d->Bai[x][y]=out_fft2d->Gai[x][y];
}
}*/
return
1;
}
この関数は、上記のfftinterfaceRGBとIfftinterfaceRGBから呼び出されています。この関数は、二次元fftを実施する関数にデータを渡すために
データを二次元配列から一次元配列にしています。そして、実際にfft、逆fftを実施する関数を呼び出して渡しています。
なぜ一次元に変換しているかというと、以前に本からコピーして利用していた二次元fftのプログラムが一次元で渡すようにしていたためです。
この関数では、CFft_2Dという二次元fftを実施するクラスを定義してそこから二次元fft関数を呼び出すことによって処理を実施しています。
//以下、fft,逆fftのスイッチ
//lfftflag=1;//fft
//lfilteron=0;//fft
//fftflag=-1;//ifft
//filteron=1;//ifft
//indata:画像データ
//l_inar:fftした時の実数部データ
//l_inai:fftした時の虚数部データ
//out_data:fft後の場合は周波数のパワースペクトル画像データ
//l_outar:fft後の実数部データ
//l_outai:fft後の虚数部データ
//lxsize,lysize:画像あるいは、周波数パワースペクトルの水平、垂直サイズ
int
Cimginterface::fftprocess(unsigned char **indata,double **l_inar,double
**l_inai,unsigned char**outdata,double **l_outar,double **l_outai,int lxsize,int
lysize,int lfftflag,int lfilteron)
{
CFft_2D cfft2d;//二次元fftを実施するための関数をあつめたクラス
int
xsize,ysize,fftflag,filteron;
fftflag=lfftflag;//fft
filteron=lfilteron;//fft
xsize=lxsize;
ysize=lysize;
//一次元データを確保する
unsigned char
*ipimage;
unsigned char *otimage;
ipimage = new unsigned char[xsize*ysize];
otimage = new
unsigned char[xsize*ysize];
double *inar;
double *inai;
inar = new
double[xsize*ysize];
inai = new
double[xsize*ysize];
//二次元配列を一次元配列にコピーする
if(fftflag==1){
for(int
i=0;i<ysize;i++){
for(int
j=0;j<xsize;j++){
ipimage[j+i*xsize]=indata[j][i];
}
}
}else if(fftflag==-1){
for(int
i=0;i<ysize;i++){
for(int
j=0;j<xsize;j++){
inar[j+i*xsize]=l_inar[j][i];
inai[j+i*xsize]=l_inai[j][i];
}
}
}
if(cfft2d.Fft2d_main(ipimage,otimage,xsize,ysize,inar,inai,fftflag,filteron)==-1)//fftあるいは逆fftを実施する
{
delete
inai;
delete
inar;
delete
otimage;
delete
ipimage;
return
-1;
}
//fftあるいは逆fftした結果を二次元配列にコピーする
for(int
y=0;y<ysize;y++){
for(int
x=0;x<xsize;x++){
outdata[x][y]=otimage[x+y*xsize];
l_outar[x][y]=inar[x+y*xsize];
l_outai[x][y]=inai[x+y*xsize];
}
}
delete inai;
delete inar;
delete otimage;
delete
ipimage;
return 1;
}
この関数はウィナーフィルタを実行するための関数です。これもRGBそれぞれに実施するため、3回呼び出す形式にしています。
ウィナーフィルタを簡単に説明すると、周波数空間で失った空間周波数を補正するためのフィルタになります。
データの受け渡し方は、fftinterfaceRGBと同じです。
int Cimginterface::WinerinterfaceRGB(Cfftdatacreate2d
*in_fft2d,Cfftdatacreate2d *out_fft2d)
{
int xsize,ysize;
xsize=in_fft2d->hsize;
ysize=in_fft2d->vsize;
if(winerprocess(in_fft2d->Gdata,out_fft2d->Gdata,out_fft2d->Gar,out_fft2d->Gai,xsize,ysize)==-1)
{
QMessageBox::warning(0,"fail!!","can't fft data size is'nt
2n");
return
-1;
}
if(winerprocess(in_fft2d->Rdata,out_fft2d->Rdata,out_fft2d->Rar,out_fft2d->Rai,xsize,ysize)==-1)
{
QMessageBox::warning(0,"fail!!","can't fft data size is'nt
2n");
return
-1;
}
if(winerprocess(in_fft2d->Bdata,out_fft2d->Bdata,out_fft2d->Bar,out_fft2d->Bai,xsize,ysize)==-1)
{
QMessageBox::warning(0,"fail!!","can't fft data size is'nt
2n");
return
-1;
}
out_fft2d->hsize=xsize;
out_fft2d->vsize=ysize;
//今回のFFTデータはGデータのみなので、Gデータを全部にコピーした
/* for(int
y=0;y<ysize;y++){
for(int
x=0;x<xsize;x++){
out_fft2d->Rdata[x][y]=out_fft2d->Gdata[x][y];
out_fft2d->Bdata[x][y]=out_fft2d->Gdata[x][y];
out_fft2d->Rar[x][y]=out_fft2d->Gar[x][y];
out_fft2d->Rai[x][y]=out_fft2d->Gai[x][y];
out_fft2d->Bar[x][y]=out_fft2d->Gar[x][y];
out_fft2d->Bai[x][y]=out_fft2d->Gai[x][y];
}
}*/
return
1;
}
この関数でウィナーフィルターを実行しています。ウィナーフィルターを実行する順番は、fft(周波数空間に変換)、周波数空間内で逆関数でフィルタリング、逆ftt(実空間画像に戻す)という
順番になっています。この関数もこの順番に必要な関数を内部で呼び出しています。
fft,逆fftを実施するために二次元の配列を一次元配列に変換しています。
int Cimginterface::winerprocess(unsigned char **indata,unsigned
char **outdata,double **linar,double **linai,int lxsize,int
lysize)
{
CFft_2D
cfft2d;//二次元fftを実施するための関数をあつめたクラス
CImagefunc
cimg;//フィルタを実施する関数が定義されているクラス
int
xsize,ysize,fftflag,filteron;
xsize=lxsize;
ysize=lysize;
unsigned char
*ipimage;
unsigned char *otimage;
ipimage = new unsigned char[xsize*ysize];
otimage = new
unsigned char[xsize*ysize];
double *inar;
double *inai;
inar = new
double[xsize*ysize];
inai = new
double[xsize*ysize];
for(int
i=0;i<ysize;i++){
for(int
j=0;j<xsize;j++){
ipimage[j+i*xsize]=indata[j][i];
}
}
//fftを実行して周波数空間に変換する
fftflag=1;//fft
filteron=0;//fft
if(cfft2d.Fft2d_main(ipimage,otimage,xsize,ysize,inar,inai,fftflag,filteron)==-1)
{
delete
inai;
delete
inar;
delete
otimage;
delete
ipimage;
return
-1;
}
//変換した周波数空間内で逆フィルターを実行する。
cimg.winer(inar,inai,ipimage,otimage,xsize,ysize);
//逆フィルタを実行後の周波数空間のデータを逆fftを実施する。
fftflag=-1;//ifft
filteron=1;//fft
if(cfft2d.Fft2d_main(ipimage,otimage,xsize,ysize,inar,inai,fftflag,filteron)==-1)
{
delete
inai;
delete
inar;
delete
otimage;
delete
ipimage;
return -1;
}
//ウィナーフィルタを実施後のデータを画像化する。オリジナル画像であるipimageに対してotimageを加算する。
cimg.wimage(ipimage,otimage,(long)xsize,(long)ysize);
for(int
y=0;y<ysize;y++){
for(int
x=0;x<xsize;x++){
outdata[x][y]=otimage[x+y*xsize];
linar[x][y]=inar[x+y*xsize];
linai[x][y]=inai[x+y*xsize];
}
}
return 1;
}
この関数はラプラシアンフィルタをRGBに実施するための関数である。
内部でラプラシアンフィルタを実施するときの、強度(エッジに対してのアンプ量)、ラプラシアンフィルタのタイプを決めて、
実際のフィルタ処理をする「laplacian関数」を呼び出している。
int Cimginterface::laplacianInterfaceRGB(Cfftdatacreate2d
*in_fft2d,Cfftdatacreate2d *out_fft2d)
{
int xsize,ysize;
double amp;
int type;
amp=5.0;//エッジ強度の設定
type=1;//ラプラシアンフィルタのタイプ設定、0-2の数を設定するとそれぞれフィルタの係数が異なる。
CImagefunc imgfunc;//フィルタを実施する関数が定義されているクラス
xsize=in_fft2d->hsize;
ysize=in_fft2d->vsize;
if(imgfunc.laplacian(in_fft2d->Gdata,out_fft2d->Gdata,amp,type,xsize,ysize)==-1)
{
QMessageBox::warning(0,"fail!!","can't fft data size is'nt
2n");
return
-1;
}
if(imgfunc.laplacian(in_fft2d->Rdata,out_fft2d->Rdata,amp,type,xsize,ysize)==-1)
{
QMessageBox::warning(0,"fail!!","can't fft data size is'nt
2n");
return
-1;
}
if(imgfunc.laplacian(in_fft2d->Bdata,out_fft2d->Bdata,amp,type,xsize,ysize)==-1)
{
QMessageBox::warning(0,"fail!!","can't fft data size is'nt
2n");
return
-1;
}
out_fft2d->hsize=xsize;
out_fft2d->vsize=ysize;
//今回のFFTデータはGデータのみなので、Gデータを全部にコピーした
/* for(int
y=0;y<ysize;y++){
for(int
x=0;x<xsize;x++){
out_fft2d->Rdata[x][y]=out_fft2d->Gdata[x][y];
out_fft2d->Bdata[x][y]=out_fft2d->Gdata[x][y];
out_fft2d->Rar[x][y]=out_fft2d->Gar[x][y];
out_fft2d->Rai[x][y]=out_fft2d->Gai[x][y];
out_fft2d->Bar[x][y]=out_fft2d->Gar[x][y];
out_fft2d->Bai[x][y]=out_fft2d->Gai[x][y];
}
}*/
return
1;
}