02.57

PERANCANGAN LOGIKA DAN PERANCANGAN INPUT OUTPUT EFEK MOVIE

Pada pemrograman ini dijelaskan mengenai tahapan-tahapan pembuatan program efek movie dengan menggunakan Visual C++. Tahapan tersebut meliputi Perancangan logika dan Perancangan Input output.

1. Perancangan Logika
Dalam perancangan logika yang dilakukan adalah dengan membuat bagan
alur atau flowchart dari program yang akan dibuat.

1.1. Pembahasan efekmorphing:
Efek morphing adalah efek dimana suatu objek diubah perlahan-lahan
menjadi objek lain. Efek morphing memerlukan dua buah gambar. Proses yang
terjadi pada umumnya adalah gabungan antara teknik deformation dan cross
dissolve. Teknik deformation adalah teknik untuk mengubah bentuk suatu objek.
Teknik deformation digunakan dalam efek morphing untuk mengubah
bentuk/mendeformasikan gambar asal dan gambar tujuan. Setelah itu dilakukan
proses cross dissolve yang berfungsi untuk menggabungkan wama antara gambar
asal dan gambar tujuan.
Ada beberapa efek morphing dalam visual C++, akan tetapi yang dipakai
dalam penulisan ini adalah :
1. Efek Cross Dissolve adalah teknik menampilkan kedua gambar (gambar asal
dan gambar tujuan ) dengan mode transparan. Dengan teknik ini akan terlihat
gambar asal perlahan-lahan menghilang sambil gambar tujuan perlahan-lahan
muncul.
Listing program Cross Disolve:
CTAppView: :CTAppView( )
{
// Ciptakan bitmap objek sebesar 400 x 400, 24 bit warna sebagai layar buffer
BitmapBuffer.CreateBitmap(400,400,1,24,NULL) ;
BitmapBuffer.GetObject(sizeof(BITMAP), sbm) ;
// Ciptakan array gambar sebagai tempat penampung gambar untuk layar buffer
bufferData = new unsigned char [biTi.brnHeight*bm.bmWidthBytes] ;
// Isikan dengan warna R=0, G=0, B=0 (hitam)
memset (bufferData, 0, bm.bmHeight*bm.bmWidthBytes) ;
// Isikan bitmap buffer dengan data gambar
BitmapBuffer.SetBitmapBits(bm.bmHeight*bm.bmWidthBytes,bufferData) ;
CTAppView: :~CTAppView( )
BOOL CTAppView :P reCreateWindow(CREATESTRUCT& cs)
return CView::PreCreateWindow (cs) ;
void CTAppView :OnDraw(CDC* pDC)
BOOL CTAppView :OnPreparePrinting(CPrintInfo* pinfo)
// default preparation
return DoPreparePrinting(pinfo);
void CTAppView :OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*plnfo*/)
void CTAppView :OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*plnfo*/)
void CTAppView :SetViewID(int id)
// Set view ID dari class sehingga dalam class ini kita selalu tahu kita sedang
mengakses
// view yang mana (source / target / result )
viewID=id;
// Simpan pointer untuk view sekarang ke dalam tabel sehingga setelah ketiga view?// memanggil fungsi ini, tabel pView akan berisi ketiga pointer yang menunjuk ke
masing
// – masing view.
pView[id]=this;
void CTAppView::UpdateBuffer(SPRITE & image)
int x,y;
for (x=0;x:D ump(dc) ;
}
#endif //_DEBUG
void CControlPanel::OnLoadSource()
1
// Siapkan dialog untuk menentukan file gambar mana yang akan dibaca.
char fileName[10000]=”";
CFileDialog dig(TRUE, “RAF”, fileName,
OFN_FILEMUSTEXIST I OFN_PATHMUSTEXIST,
“Raw Bitmap File (*.RAF)|*.RAF[|");
dlg.m_ofn.lpstrTitle = "Loading RAW image file";
// Aktifkan dialog
if (dIg.DoModal() == IDOK)
strcpy(fileName, dig.GetPathName());SPRITE image;
// Baca file gambar ke dalam variabel image.
LoadRAWFile(Simage,fileName) ;
// Copykan data yang baru dibaca dari file ke layar buffer milik view untuk gambar
asal
// (VIEW_SOURCE)
pView[VIEW_SOURCE] ->UpdateBuffer (image) ;
delete image.data;
void CControlPanel::OnLoadTarget()
// Siapkan dialog untuk menentukan file gambar mana yang akan dibaca.
char fileName[10000]=”";
CFileDialog dig(TRUE, “RAF”, fileName,
OFN_FILEMUSTEXIST I OFN_PATHMUSTEXIST,
“Raw Bitmap File (*.RAF)|*.RAF||”);
dlg.m_ofn.lpstrTitle = “Loading RAW image file”;
// Aktifkan dialog
if (dIg.DoModal() == IDOK)
{
strcpy(fileName, dig.GetPathName());
SPRITE image;
// Baca file gambar ke dalam variabel image.
LoadRAWFile(&image,fileName) ;
// Copykan data yang baru dibaca dari file ke layar buffer milik gambar tujuan
// (VIEW_TARGET)
pView[VIEW_TARGET] ->UpdateBuffer (image) ,-delete image.data;
void CControlPanel::OnRender()
// Set nomor frame ke 0.
frameNo=0;
// Non aktifkan tombol untuk membaca gambar asal, tujuan, juga tombol untuk
// menciptakan movie. Semua tombol ini dinon aktifkan selama proses
// pembuatan movie / rendering berlangsung.
// ((CButton*)GetDlgItem(IDC_LOAD_SOURCE))->EnableWindow(FALSE) ;
// ((CButton*)GetDlgItem(IDC_LOAD_TARGET))->EnableWindow(FALSE) ;
((CButton*)GetDlgItem(IDC_RENDER))->EnableWindow(FALSE) ;
// Buka file movie baru
InitMOV(&movie,OPEN_FOR_WRITTING) ;
// Set jumlah frame = 20 dan ukuran 400 x 400.?16
SetMOVHeader(Smovie,20,400,400) ;
OpenMOVFile(Smovie,”..\\movie\\movie.mov”);
// Render setiap frame setiap 50 milisecond.
SetTimer(1,50,NULL) ;
}
void CControlPanel::OnTimer(UINT nIDEvent)
f
// Simpan alamat gambar asal dan gambar tujuan ke variabel tipe SPRITE.
SPRITE src,tar,result;
src.data=pView[VIEW_SOURCE]->bufferData;
src.dimX-pView[VIEW_SOURCE]->bm.bmWidth;
src.dimY=pView[VIEW_SOURCE]->bm.bmHeight ;
tar.data=pView[VIEW_TARGET]->bufferData;
tar.dimX=pView[VIEW_TARGET] ->bm.bmWidth;
tar.dimY=pView[VIEW_TARGET]->bm.bmHeight;
// Ciptakan sprite sebesar ukuran layar buffer = 400×400 untuk
// hasil dari morphing.
InitSprite(Sresult,pView[VIEW_SOURCE]->bm.bmWidth,pView[VIEW_SOURCE]-
>bm.bmHeight);
// Lakukan cross dissolve morphing antara gambar src ke tar dan simpan hasilnya di
result.
// Parameter frameNo/19 ialah konstanta yang berharga antara 0 hingga 1. Semakin
dekat
// harganya ke 0 semakin besar proporsi gambar src dibandingkan gambar tar dalam
membentuk
// gambar result hasil morphing. Demikian pula sebaliknya.
CrossDissolve(src,tar,result,(((float)frameNo)/19.0f));
}
// Copykan hasilnya ke variabel data dari movie.
memcpy(movie.cur Frame,result.data,400*400*3) ;
// Tukar komponen Red dan Blue karena selama proses di atas, format sprite memiliki
// urutan yang salah yaitu Blue – Green – Red. Sedangkan proses selanjutnya, sprite
result
// akan dikirimkan ke fungsi UpdateBuffer yang mengharapkan SPRITE berurutan Red -
Green
// – Blue.
// Ingat, frame movie tetap dalam format Blue – Green – Red. Kenapa ? Lihat
‘ penjelasan
// di file image.h
RGBToBGRtresult) ;
pView[VIEW_RESULT]->UpdateBuffer(result) ;
// Simpan frame saat ini ke movie file.
WriteMOVFrame(smovie) ;
// Siap menyimpan frame selanjutnya.
frameNo++ ;
// Jika telah sampai frame 20 maka selesai.
if (frameNo>=20)
{
// Matikan timer sehingga fungsi OnTimer ini tidak akan dipanggil lagi oleh Windows
// secara otomatis sampai ditekannya tombol Render Movie lagi.
Kill Timer(1) ;
// Akfcifkan semua tombol.
// ((CButton*)GetDlgItem(IDC_LOAD_SOURCE))->EnableWindow(TRUE) ;
// ((CButton*)GetDlgItem(IDC_LOAD_TARGET))->EnableWindow(TRUE) ;
((CButton*)GetDlgItem(IDC_RENDER))->EnableWindow(TRUE) ;
// Tutup movie file.
CloseMOVFile(&movie);
}
delete result.data;
CFormView::OnTimer(nIDEvent) ;
}
int CrossDissolve(SPRITE & src, SPRITE & tar, SPRITE & res,float t)
if (src.dimX==tar.dimX&&src.dimY==tar.dimY)
{
for (int x=0;x

2. Teknik Feature morphing adalah teknik yang membagi-bagi keseluruhan objek
menjadi beberapa objek yang disebut feature(seperti objek mata,hidung dll). Pada
teknik ini terdapat garis-garis yang membatasi feature, garis ini disebut garis
feature.
Listing program Feature morphing :
if (IDSelectFX == FX FEATURE)
if (operation == OPERATION_CREATE && viewID == VIEW_SOURCE)
t
// Diciptakannya marker baru. Operasi ini hanya dapat dilakukan
// di window asal.
srcMarkerList[numMarkerList][oprState][0]=point.x;
srcMarkerList[numMarkerList][oprStafce][l]=point.y;
tarMarkerList[numMarkerList][oprState][0]=point.x;
tarMarkerList[numMarkerList][oprState][l]=point.y;?if ;oprState==l)
oprState=0;
numMarkerList++;
} else
oprState=l;
}
pView[0]->InvalidateRect(NULL,FALSE);
pView[l]->InvalidateRect(NULL,FALSE);
} else
if (operation — OPERATION_SELECT I I operation == OPERATION_MOVE)
(
if (viewID == VIEW_SOURCE)
{
int mkrNo;
float curDist,minDist=10000.Of;
for (mkrNo=0;mkrNocurDist)
minDist=curDist ;
selectedMarker=mkrNo;
selectedCP=0;
}
curDist = P2P_2D_Distance(srcMarkerList[mkrNo][1],
Vec2D(point-x,point.y));
if (minDist>curDist)
minDist=curDist;
seiectedMarker=mkrNo;
selectedCP=l ;
}
} else
if (viewID =- VIEW_TARGET)
int mkrNo;
float curDist,minDist=10000.Of;
for (mkrNo=0;mkrNocurDist)
(
minDist^curDist;
selectedMarker=mkrNo;
selectedCP=0;
}
curDist =
P2P_2D_Distance(tarMarkerList[mkrNo][1],Vec2D(point.x,point.y)) ;
if (minDist>curDist)
rninDist=curDist;
selectedMarker=mkrNo;
selectedCP=l ;
}
}
}
pView[0]->InvalidateRect(NULL,FALSE) ;
pView[l]->InvalidateRect(NULL,FALSE) ;
}
}
CView::OnLButtonDown(nFiags, point);
}
void CTAppView::OnLButtonUp(UINT nFlags, CPoint point)?19
// TODO: Add your message handler code here and/or call default
LButton=0;
ReleaseCapture() ;
CView:SOnLButtonUp(nFlags, point) ;
}
void CTAppView::OnMouseMove(UINT nFlags, CPoint point)
(
// TODO: Add your message handler code here and/or call default
if (LButton)
if (IDSelectFX == FX_FEATURE)
i f (selectedMarker>=0&&selectedMarkerInvalidateRect(NULL,FALSE) ;
} else
if (viewID ~ VIEW_TARGET)
{
tarMarkerList[selectedMarker][selectedCP][0]=point.x;
tarMarkerList£seiectedMarker][selecfcedCP][l]=poinfc.y;
pView[l]->InvalidateRect(NULL,FALSE) ;
CView::OnMouseMove(nFlags, point);
}
void CTAppView::OnRButtonDown(UINT nFlags, CPoint point)
(
// TODO: Add your message handler code here and/or call default
if (IDSelectFX == FX_FEATURE)
{
Vec2D 11(srcMarkerList[0][0][0],srcMarkerList[0][0][1]) ;
Vec2D 12(srcMarkerList[0][1][0],srcMarkerList[0][1][1]) ;
Vec2D pt(point.x,point.y);
Vec2D uv;
FindUV(ll,12,pt,uv);
H-Vec2D(tarMarkerList[0][0][0],tarMarkerList[0][0][1]) ;
12=Vec2D(tarMarkerList[0][1][0],tarMarkerList[0][1][1] ) ;
FindXY(ll,12,uv,pt) ;
answer = pt;
pView[l]->InvalidateRect(NULL,FALSE) ;
}
CView::OnRButtonDown(nFlags, point) ;
]
void FindUV(Vec2D 11,Vec2D 12,Vec2D pt,Vec2D & uv)
{
Vec2D vl=12-ll;
Vec2D v2=pt-ll;
float vIMag^vl.Length();
// VI XLength ialah panjang garis M.
// -Di mana garis M ialah garis dari
// titik 11 ke titik X.
// —Titik X ialah titik di mana garis P memotong garis 11->12.
// -Garis P ialah garis yang tegak lurus dengan garis 11->12 di mulai
// dari titik pt;
float vl_xLength=vl*v2/vlMag;
// x adalah koordinat dari titik X.?20
Vec2D x=(vl.Normalise())*vl_xLength+ll;
// uv.x adalah posisi dari titik X sepanjang garis M yang dinormalisasikan
// ke skala (11->12) => (0->1)
uv.x=vl_xLength/vlMag;
// uv.y adalah posisi dari titik pt sepanjang garis P yang dinormalisasikan
// dengan jarak 11->12
Vec2D ll_2Line = 12-11;
Vec2D perl_2(-ll_2Line.y,ll_2Line.x) ;
Vec2D p=pt-x;
uv.Y=(p*perl_2)/vIMag;
}
void FindXY(Vec2D 11,Vec2D 12,Vec2D uv,Vec2D & pt)
{
Vec2D ll_2Line = 12-11;
// 11_X adalah koordinat dari titik 11 ke titik X
Vec2D 11_X = ll_2Line*uv.x+ll;
// peril 2 adalah vektor yang tegak lurus terhadap vektor garis 11->12
Vec2D perll_2(-ll_2Line.y,ll_2Line.x) ;
perll_2=perll_2.Normalise() ;
// Hasil akhir ialah koordinat titik X ditambah dengan vektor v
// relati’f terhadap garis 11->12
pt = 11_X + peri1_2*uv.y;
}
void FeatureMorphing(SPRITE & src,SPRITE & tar,Vec2D srcMarkerList[][2],
Vec2D tarMarkerList[][2],Vec2D
medMarkerListt][2],int numMarkerList,
float t,SPRITE & result)
// Interpolasikan garis – garis marker ke waktu t.
int a,b,c;
for (a=0;a12 maka jarak kita hitung dengan menghitung jarak
// titik gambar ke ujung terdekat dari garis 11->12
if (uv.x<0.0f) dist="P2P_2D_Distance(curPt,medMarkerList[c][0])">1.0f)
dist=P2P_2D_Distance(curPt,medMarkerList[c][1] );
// Jika titik X ada di dalam garis 11->12 maka jaraknya sama dengan panjang vector
else
dist=fabs(uv-y);
// Hitung panjang dari garis marker yang akan kita gunakan untuk menghitung bobot /
// weight dari garis marker ini-
medMarkerList[c][0];
Vec2D medl_2 = medMarkerList[c][1]-
length = medl 2.Length();
// Sekarang kita hitung weight / bobot dari garis marker ini. Dengan fungsi ini
maka
// semakin panjang sebuah garis marker, semakin besar bobotnya. Juga semakin
.// dekat titik gambar ke garis marker, semakin besar pula bobotnya.
// Parameter REL menentukan seberapa besar pengaruh panjang garis marker terhadap
// perhitungan weight / bobot.
// Parameter ALPHA menentukan jarak minimum antara titik gambar dengan garis
marker.
// Jika ALPHA = 0 dan jarak antara titik gambar ke garis marker = 0
// (titik gambar berada di garis 11->12 maka bobot yang dihitung akan salah karena
// pembagian dengan (ALPHA+dist) akan mengakibatkan pembagian dengan 0.
// Untuk itu ALPHA harus selalu lebih besar dari 0. Semakin kecil ALPHA, semakin
// besar bobot / weight yang dihasilkan.
// Parameter AMP berguna untuk melipat gandakan bobot / weight. Semakin besar AMP,
// garis marker dengan weight yang besar akan semakin dominan terhadap
// garis marker yang kecil.
weight = powfpow(length,REL)/(ALPHA+dist),AMP);
// Kalikan lokasi dari titik gambar di gambar asal dan tujuan dengan weight.
accSrcPt+=srcPt*weight;
accTarPt+=tarPt*weight;
// Jumlahkan seluruh weight yang kita gunakan. Sehingga setelah loop berakhir,
// kita dapat mengambil rata — rata dari lokasi dari titik gambar relatif
// terhadap garis – garis marker.
totalWeight+^weight;
}
// Rata – ratakan lokasi dari titik gambar di gambar asal dan tujuan.
// Hasil rata – rata ini ialah lokasi titik gambar saat ini di gambar
// asal dan tujuan.
accSrcPt/^totalWeight;
accTarPt/=totalWeight;
// Pindahkan lokasi titik gambar ke array integer.
int intSrcPt[2] ;
int intTarPt[2];?for (c=0;c<2;c++)>=tar.dimX]|
intSrcPt[1]<0||int3rcpt[l]^fcar.dimy)>=tar.dimX||
intTarPt[1]<0||inttarpt[1]>=tar.dimY)
tarColor[0]=O.Of;tarColor[l]=O.Of;tarColor[2]=0.0f;
} else
// Jika titik gambar berada di dalam layar tujuan, kita ambil warna dari titik
// gambar tersebut.
(
tarColor[0]=tar.data[(intTarPt[1]*tar.dimX+intTarPt[0])*3] ;
tarColor[l]=tar.data[(intTarPt[1]*tar.dimX+intTarPt[0])*3+1] ;
tarColor[2]=tar.data[(intTarPt[1]*tar.dimX+intTarPt[0])*3+2];
Gambar 3.3. efek feature morphing?23
3. Efek Mesh morphing adalah teknik yang hamper mirip dengan feature
morphing, hanya bedanya pada teknik mesh morphing, perubahan terjadi hanya
pada segitiga/ruang tertentu yang diinginkan saja, sedangkan pada teknik feature
morphing, jika salah satu mang bembah, maka semua ruang akan bembah. Pada
teknik ini efek deformasi yang dilakukan pada segitiga tertutup yang akan dirubah
saja dan areanya besifat lokal.
Listing program Mesh morphing :
BufferDC.SelectObject(oldBitmap) ;
// Tampilkan Sites map
int no=~l;
int siteNo, trNo;
CBrush normalBrush(RGB(255,0,0)) ;
CBrush selectedBru3h(RGB(255,255,255)) ;
CBrush * usedBrush;
int b;
CPen nonnalPen, selectedPen;
normal Pen.CreatePen(PS_SOLID,1,RGB(200,200,50)) ;
selectedPen.CreatePen(PS_SOLID,1,RGB(255,255,255) );
CPen * oldPen = dc.SelectObject(SnormalPen);
for (trNo = 0; trNo < siteno =" 0;" siteno ="=" usedbrush =" &selectedBrush;" usedbrush =" &normalBrush;">InvalidateRect(NULL,FALSE) ;
pView[VIEW_TARGET]->InvalidateRect(NULL,FALSE) ;
pView[VIEW_RESULT]->InvalidateRect(NULL,FALSE) ;
]
void CTAppView::OnLButtonDown(UINT nFlags, CPoint point)
{?24
// TODO: Add your message handler code here and/or call default
LButton=l;
SetCapture() ;
if (operation == OPERATION_CREATE && viewID ~ VIEW_SOURCE)
if (operation == OPERATION_CREATE)
{
if (viewID =- VIEW_SOURCE)
{
SitesMap[VIEW_SOURCE][totalSites].x = point.x;
SitesMap[VIEW_SOURCE][totalSites].y = point.y;
SitesMap[VIEW_TARGET][totalSites].x = point.x;
SitesMap[VIEW_TARGET][totalSites].y = point.y;
totalSites++;

4. Teknik Deformation adalah teknik untuk mengubah bentuk suatu objek.
Teknik deformation digunakan dalam efek morphing untuk mengubah
bentuk/mendefbrmasikan gambar asal dan gambar tujuan sehingga memiliki
bentuk yang sama.
Listing program Deformation:
void TriangleMorphing(SPRITE & src, SPRITE & tar,SPRITE & res, Vec2D SrcSites[],
Vec2D TarSites[], Vec2D
MidSites[],int triNetwork[][3],
int totalTris, float t)
int a,b,c,d;
for (a = 0; a < b =" 0;" c =" 0;" curpt =" Vec2D((float)b,(float)a);" totalweight =" O.Of;" d ="0;" dist =" P2P_2D_Distance(curPt,MidSites[triNetwork[c][d]]);"> l.Of)
dist = P2P_2D_Distance(curPt,MidSites[triNetwork[c][(d + 1) % 3]]) ;
// Jika titik X ada di dalam garis 11—>12 maka jaraknya sama dengan panjang
vector V
else
dist=fabs(uv.y);
// Hitung panjang dari garis marker yang akan kita gunakan untuk menghitung
bobot /
// weight dari garis marker ini.
Vec2D medl_2 = MidSites [triNetwork [c] [ (d +1) % 3] ] -
MidSites[triNetwork[c][d]] ;
float length = medl_2.Length();
float weight = pow(pow(length,REL) / (O.lf + dist),AMP);
accSrc += srcPt * weight;
accTar +^ tarPt * weight;
totalWeight += weight;
accSrc /= totalWeight;
accTar /= totalWeight;
// Pindahkan lokasi titik gambar ke array integer.
int intSrcPt[2] ;
int intTarPt[2];
float srcColor[3], tarColor[3];
for (d=0;d<2;d++)>=tar.dimX||
intSrcPt[1]<0||intsrcpt[1]>=tar.dimY)
srcColor[0]=0.0f;srcColor[1]=0.0 f;srcColor[2]=0.0 f;
} else

f
srcColor[0]=src.data[(intSrcPt[l]*src.dimX+intSrcPt[0])*3] ;
srcColor[1]=src.data[(intSrcPt[I]*src.dimX+intSrcPt[0])*3+1] ;
srcColor[2]=src.data[(intSrcPt[1]*src.dimX+intSrcPt[0])*3+2] ;
// Jika titik gambar berada di luar layar tujuan, kita anggap titik
tersebut
// berwarna hitam.?if (intTarPt[0]<0||inttarpt[0]>=tar.dimX|| intTarPt[1]<0||inttarpt[1]>-tar.dimY)

2. Perancangan input output

Pada perancangan input output yang paling pertama dilakukan adalah
mengambil/meload gambar. Gambar yang dapat digunakan dalam program ini
adalah gambar dalam ukuran/skala kecil, misalnya dengan format JPG yang harus
di-convert menjadi format RAF. Setelah file gambar didapatkan, lalu di-save
dalam folder tertentu, misalnya image, kemudian buat folder movie yang kosong,
yang nantinya jika program dijalankan folder tersebut akan sendirinya terisi
dengan nama movie.mov kemudian jalankan program, maka akan muncul
tampilan program yang belum terdapat gambamya, setelah itu lakukan open
source untuk gambar asal dan open destination untuk gambar tujuan. Setelah
mendapatkan gambar yang diinginkan, klik effect untuk memilih efek yang
diinginkan. Maka jika tombol Render diklik , akan muncul perubahan gambar
sesuai efek yang dipilih.

0 komentar:

Posting Komentar