Qt/Gcc
2012.08.16作成
2-3mainwindowクラス
mainwindowクラスは、メニューの作成/制御、子ウィンドウの生成を実施しています。
このクラスは、サンプルから機能を抜き取って使える部分だけ使っていますので、私も完全に理解できてない部分もあります。
わかる範囲、自分で作成した部分の説明となります。
このクラスは、メニューからのアクションを受け取って処理し、必要なスロット関数(イベント)を呼び出しています。
このスロット関数として、画像処理を実施するクラスの関数を呼び出して画像処理を実行しています。
mainwindow.h
mainwindow.cpp
・mainwindow.h
サンプルプログラムを利用しているので、サンプルとの差分のみ記載していきます。
private
slotsに記載されているcreateMdiChild()のオリジナル関数に対して、子ウィンドウのサイズを
渡せるように変更します。
private slots:
MdiChild *createMdiChild(int
xsize,int ysize);//追加
同じく、private
slotsに以下の関数を定義します。メニューからこれらの機能を選択すると、
呼び出される関数となります。Visual
C++でのイベント関数です。
void
laplacian();
void fftprg();
void
ifftprg();
void
winerprg();
メニューをセットするため、以下のアクションを追加します。
private:
QAction
*laplaAct;
QAction *fftAct;
QAction
*ifftAct;
QAction *onwiner;
・mainwindow.cpp
このファイルもサンプルファイルとの差分のみ記載します。
はじめに以下のメンバー関数を記載します。
この関数は画像ファイルの読み込みを実施します。ここでは、一度ファイルを読み込んで画像ファイルの縦横サイズを
取得して、このサイズを子ウィンドウを作るためにつかいます。
以下にソースコードを記載します。
以下の3つのインクルードファイルを追加します。
#include "cdatacreate2d.h"
#include
"cfftdatacreate2d.h"
#include
"cimginterface.h"//画像処理用のクラスをまとめている。
void
MainWindow::open()
{
QImage tmpimg;//追加
画像サイズを読み込むためのみ使用します。
QString fileName =
QFileDialog::getOpenFileName(this);
if
(!fileName.isEmpty()) {
QMdiSubWindow *existing =
findMdiChild(fileName);
if
(existing)
{
mdiArea->setActiveSubWindow(existing);
return;
}
//以下追加
if(!tmpimg.load(fileName))//画像サイズの値を取得するために画像ファイルを一度読み込む
{
QMessageBox::warning(0,"No
file",fileName);//ファイルが読み込めなかった場合メッセージを表示する。
return;//読み込めなかった場合はなにもせずに関数から抜け出す。
}
/////////////////////////////////////////////
MdiChild *child =
createMdiChild((int)tmpimg.width(),(int)tmpimg.height());//子ウィンドウを作る。このとき、画像サイズと同じ大きさの子ウィンドウとするために、画像サイズを渡している。
//MdiChild *child = createMdiChild();
これは、サンプルプログラムオリジナル
if
(child->loadFile(fileName))
{//表示や実際の画像処理に使う画像ファイルは、ここで読み込んでいる。
statusBar()->showMessage(tr("File loaded"),
2000);
child->show();//子ウィンドウを表示する
}
else {
child->close();
}
}
}
注:open関数内でtmpimg.load(fileName)としてますが、Ubuntu12.04LTSではjpegファイルを読み込めない環境がある
ようです。私の環境ではlibjpeg62がインストールされていないのが原因でした。
sudo
apt-get install libjpeg62
<---このコマンドでインストールできます。以後は読み込めるようになりました。
以下の関数は実装しますが、今回は動作させません。したがって、サンプルプログラム内の各関数をコメントアウトしています。
void MainWindow::cut()、void MainWindow::copy()、void
MainWindow::paste()
メニューの変更時の設定です。ほぼ、サンプルどおりです。
void
MainWindow::updateMenus()
{
//以下のコードのみ追加
//本当は各メニュー毎にこれと同じコードを記載する必要あり
laplaAct->setVisible(hasMdiChild);//add0512
}
void MainWindow::updateWindowMenu()もサンプルから変更ありません。
MdiChild
*MainWindow::createMdiChild()は、変更がありませんが、次で多重定義しています。
//この関数は、子ウィンドウを作って、作ったポインタを返しています。
MdiChild *MainWindow::createMdiChild(int xsize,int
ysize)
{
MdiChild *child = new
MdiChild(xsize,ysize);
mdiArea->addSubWindow(child);
//以下は使用していない。
connect(child,
SIGNAL(copyAvailable(bool)),
cutAct, SLOT(setEnabled(bool)));
connect(child,
SIGNAL(copyAvailable(bool)),
copyAct, SLOT(setEnabled(bool)));
return
child;
}
//メニューアイテムからのアクションを処理しています。
void
MainWindow::createActions()
{
//以下を追加。簡単な微分フィルタ(Laplacian)、FFT、Winerフィルタを実施しました。
//それぞれ、3行で1セット。アクションアイテムを作って、そのチップスを定義して、アクションとスロットを定義。
laplaAct = new QAction(tr("Laplacian"),this);
laplaAct->setStatusTip(tr("Paste the clipboard's contents into the current
"
"selection"));
connect(laplaAct, SIGNAL(triggered()),
this, SLOT(laplacian()));
fftAct
= new QAction(tr("FFT"),this);
fftAct->setStatusTip(tr("Paste the clipboard's contents into the current
"
"selection"));
connect(fftAct, SIGNAL(triggered()), this,
SLOT(fftprg()));
ifftAct = new QAction(tr("IFFT"),this);
ifftAct->setStatusTip(tr("Paste the clipboard's contents into the current
"
"selection"));
connect(ifftAct, SIGNAL(triggered()), this,
SLOT(ifftprg()));
onwiner = new QAction(tr("winer"),this);
onwiner->setStatusTip(tr("Paste the clipboard's contents into the current
"
"selection"));
connect(onwiner, SIGNAL(triggered()), this,
SLOT(winerprg()));
}
//以下がメニューアイテムの実装です。
void
MainWindow::createMenus()
{
//以下が追加editMenuに画像処理用のメニューを追加しています。
editMenu->addAction(laplaAct);//add0512
editMenu->addAction(fftAct);//add0518
editMenu->addAction(ifftAct);//add0528
editMenu->addAction(onwiner);//add
//
}
以下の関数はサンプルから変更ありません。全部理解してませんが、現時点では動けばいいというつもりです。
void MainWindow::createToolBars(),void
MainWindow::createStatusBar(),void MainWindow::readSettings()
void
MainWindow::writeSettings(),MdiChild *MainWindow::activeMdiChild(),QMdiSubWindow
*MainWindow::findMdiChild(const QString &fileName)
void
MainWindow::switchLayoutDirection(),void MainWindow::setActiveSubWindow(QWidget
*window)
ここから、メニュー(たとえばlaplacian)を選択したときの処理の実装です。
サンプルプログラムに対して追加している部分です。
わかりずらいデータの渡し方をしてます。
考え方は以下のとおりです。
1.前提として、アクティブウィンドウにすでに画像データが読み込まれている。
2.アクティブになっている(画像処理したい画像が表示されているウィンドウをアクティブにする)ウィンドウから
画像データをコピーしてくる。MainWindowは子ウィンドウと画像処理クラスとの間のハブの役割をしている。
具体的には、下記の関数内のindataとoutdataがデータの受け渡しをしている。indataがアクティブな子ウィンドウのデータを格納している。
3.画像処理関数には画像処理前のデータが格納されているindataを渡す。そして、画像処理関数内で処理されたデータを
outdataに格納して返してくる。このoutdataを新たに子ウィンドウをつくってそのウィンドウに表示する。
void
MainWindow::laplacian()
{
Cfftdatacreate2d
*indata;//アクティブな子ウィンドウからデータを受け取る
Cfftdatacreate2d
*outdata;//画像処理したデータが格納されている。この画像処理済みデータを画像処理結果を表示する子ウィンドウに渡す
//子アクティブウィンドウからデータの大きさを読み取って、受け渡し用のデータを作っている
//その後、このdataクラスを使って、読み取ったデータを描画用の新規子ウィンドウに渡している
int
flag;
if(activeMdiChild())//処理対象の子ウィンドウが確認
{
int xsize =
activeMdiChild()->childxsize();//処理ウィンドウのxsizeを取得
int ysize =
activeMdiChild()->childysize();//処理ウィンドウのysizeを取得
indata = new
Cfftdatacreate2d(xsize,ysize);//処理対象データを一時的に格納する配列
outdata = new
Cfftdatacreate2d(xsize,ysize);//処理後のデータを一時的に格納する配列
activeMdiChild()->getchilddata(indata);//アクティブになっているウィンドウからデータをindata配列に読み出す
Cimginterface
cimg;//画像処理用関数にアクセスするためのクラス
flag=cimg.laplacianInterfaceRGB(indata,outdata);//画像処理関数に処理データ(indata)を渡して、処理結果をoutdataに返してくる
if(flag !=
-1)//画像処理が成功した場合の処理
{
MdiChild *child =
createMdiChild(xsize,ysize);//画像処理した結果を表示する子ウィンドウをつくる
child->datainp(outdata);//作った子ウィンドウに処理したデータを渡す
child->show();//作った子ウィンドウを表示する
}
delete indata;//一時処理に使用した配列を破棄する
delete
outdata;//一時処理に使用した配列を破棄する
}
}
以下の関数は2次元FFTを実施する関数です。関数内のデータ受け渡しは、上記のlaplacian関数と同じです。
注意:FFT処理は2のn乗のサイズである必要があります。たとえば、128×128、256×256などです。
void
MainWindow::fftprg()
この関数のデータ受け渡しも上記のlaplacian関数とほぼ同じです。しかし、IFFT(逆フーリエ変換)はFFTしたデータが存在することが
前提である。FFTデータ(周波数空間のデータ)になんらかのフィルタ処理をして、逆変換することでフィルタを実施した画像に戻します。
void
MainWindow::ifftprg()
{
Cfftdatacreate2d
*indata;
Cfftdatacreate2d *outdata;
//ここのアクティブウィンドウは、FFTするデータがある前提。
//子アクティブウィンドウからデータの大きさを読み取って、受け渡し用のデータを作っている。
//その後、このdataクラスを使って、読み取ったデータを描画用の新規子ウィンドウに渡している。
int
flag;
if(activeMdiChild())
{
int fftflag =
activeMdiChild()->flaggetfunc();//アクティブウィンドウにfftしたデータがあるか確認する。flagが1ならばfftデータが存在するウィンドウ
if(fftflag){
Cimginterface
cimg;
int xsize =
activeMdiChild()->fftchildxsize();
int ysize = activeMdiChild()->fftchildysize();
indata =
new
Cfftdatacreate2d(xsize,ysize);
outdata = new
Cfftdatacreate2d(xsize,ysize);
activeMdiChild()->getchilddata(indata);//アクティブな子ウィンドウ(FFTデータがある)から、FFTしたデータを取り出す
flag=cimg.IfftinterfaceRGB(indata,outdata);//indataにFFTのデータoutdataに逆変換した結果を返します。
if(flag !=
-1)
{
MdiChild *child =
createMdiChild(xsize,ysize);
child->datainp(outdata);//逆FFTしたデータを
child->IFft2d_setchild();//ウィンドウタイトルをセットして、画像データのウィンドウであることをセットします。
child->show();
}
else
QMessageBox::warning(0,"fail!!","can't Ifft process");
delete
indata;
delete outdata;
}
else
QMessageBox::warning(0,"fail!!","can't fft data");
}
}
void
MainWindow::winerprg()
{
Cfftdatacreate2d
*indata;
Cfftdatacreate2d *outdata;
//子アクティブウィンドウからデータの大きさを読み取って、受け渡し用のデータを作っている。
//その後、このdataクラスを使って、読み取ったデータを描画用の新規子ウィンドウに渡している。
int
flag;
if(activeMdiChild())
{
int xsize =
activeMdiChild()->childxsize();
int ysize = activeMdiChild()->childysize();
Cimginterface
cimg;
indata = new
Cfftdatacreate2d(xsize,ysize);
outdata = new
Cfftdatacreate2d(xsize,ysize);
//flag=
activeMdiChild()->OnWiner(indata);
activeMdiChild()->getchilddata(indata);
flag=cimg.WinerinterfaceRGB(indata,outdata);
if(flag !=
-1)
{
MdiChild *child =
createMdiChild(xsize,ysize);
child->datainp(outdata);
child->Winer_setchild();//ウィンドウタイトルをセットして、画像データ(winer
filter後)のウィンドウであることをセットします。
child->show();
}else
QMessageBox::warning(0,"fail!!","can't Winner process");
delete
indata;
delete outdata;
}
}