OpenCV Sanal Mouse
Mayıs 14, 2011 Yorum bırakın
Kodlar yeniden duzenlenmiştir…
O kadar openCv dememize karsın hiç proje yapmasak ayıp olurdu heralde.Başlangıc olarak Renk tanımlama yontemiyle Mouse kontrolu programının kodlarını asagıdan bulabilirsiniz….Daha once anlatılan openCv kutphanesi eklemeyi unutmayın…Renk olarak Kırmızı yı sectik…Sizde dilerseniz degiştirebilirsiniz….
Uygulamamız daha öncede bahsedildiği üzere Microsoft Visual Studio 2008 C++ ortamında geliştirilmiştir.Win32 console application olarak yaratılan uygulamaya kullancak olduğumuz kütüphaneleri ekliyoruz.
#include “cv.h”
#include “highgui.h”
Yukarıda anlatılan linker ayarlarını gerçekleştirdikten sonra uygulamamızı yazmaya başlayabiliriz. yapılacak adımlar;
- Kameradan Görüntü alma
- Kırmızı bandın nerede olduğunu tayin etme
- Korser pozisyonunun tayini
- Sol klikler
Kameradan resim alabilmek için openCV kütüphanesinde bulunan fonksiyonları kullanırız.Programı daha rahat yazabilmek için asagıda belirrtigim fonksiyonu kaldırak zorunda kaldım.Bunun amacı saniyede daha fazla frame alabilmekti. IplImage*resmi_ isle(IplImage* img)
{
//resim
}
İlk yapmamız gereken kaera cihazlarını çalıştırmaktır. Eğer cihaz yoksa hata mesajı verilerek programdan cıkıs yapılır.
// Kameranın caliştirilmasi
CvCapture* capture = 0;
capture = cvCaptureFromCAM(0);
// Kamera kontrolu
if(!capture)
{
printf(“Kamera calistirilamiyor!…n“);
return -1;
}
Ekranda görebilmemiz için pencereleri oluşturmamız gerekir.Burada üç tane pencere oluşturdum.Bunlardan biri (ana pencere) normal kameramızı görebilmek için , bir tanesi ise (kirmizi) mouse hareketini gorebilmemiz için , (mavi) sol klikleri görebilmek içindir.Bunun için aşagıdaki komutar kullanıldı.
cvNamedWindow(“anaekran”);
cvNamedWindow(“kirmizi”);
cvNamedWindow(“mavi”);
Üzerine cizim yapabileceğimiz bir adet daha image e ihtiyacımız var.
while(true)
{
// kameradan resimleri tutmak için
IplImage* frame = 0;
frame = cvQueryFrame(capture);
Burada kameradan bir frame alıp frame isimli dosyaya onu saklıyoruz.
Dikkat ettiğiniz üzere cizim isimli bir resim oluşturduk.Bunun için herhangi bir hafıza ayrımı yapmadık , NULL olarak tanımlandı.Frame in ilk frame olup olmadığını kontrol etmek için bir kontrol mekanizması tanımlıyoruz.
// eger ilk frame se resmi oluşturmak için.
if(img_cizim == NULL)
{
img_cizim = cvCreateImage(cvGetSize(frame), 8, 3);
}
IplImage* kirmizi= cvCreateImage(cvGetSize(frame), 8, 1);
IplImage* mavi=cvCreateImage(cvGetSize(frame),8,1);
Mouse kontrolleri için iki farklı image olusturuluyor.
cvInRangeS(frame, cvScalar(0,0,140), cvScalar(40,40,255), kirmizi);//(B,G,R)
Asıl işi yapacak olan komut yukarıdaki cvInRange komutudur.Bu komutta istenilen renk aralıgındaki renkler bulunarak ana frame uzerinde yerleri tyin edilir ve bu renkler binary ye cevrilerek 0 yapılır geri kalan tum renkler 1 yapılır.
Resmin enini ve boyunu almamızın nedeni ilerde kullanılmak uzere degerlerin elde edilmesidir.
int yukseklik=frame->height;
int en=frame->width;
//kırmızı için
CvMoments *hareket = (CvMoments*)malloc(sizeof(CvMoments));//structer
cvMoments(kirmizi, hareket, 1);//(resim,moments, binary 0 -1)
double kirmizimomentx = cvGetSpatialMoment(hareket, 1, 0);
double kirmizimomenty = cvGetSpatialMoment(hareket, 0, 1);
double kirmizi_area = cvGetCentralMoment(hareket, 0, 0);//belirli bir algoritmayla x ve y koordinatlarının bir ortatlaması alnıyor.
int posX = 0;
int posY = 0;
posX = kirmizimomentx/kirmizi_area;
posY = kirmizimomenty/kirmizi_area;
CvMoment komutu binary halindeki resmin içerisindeki 0 ların yerlerini bularak işlem yapaktadır.
Daha önce acıklanan opencv kütüphanesiyle kameradan alınan framelerdeki istenilen renge gore x, y koordinatlarını belirlenmişti.Bu x , y koordinatları kullanılmak üzere bir fonksiyon yazıldı.Fonksiyon asagıda gosterildigi uzere deklere edildi.
void mouseposition(int x,int y)
{
SetCursorPos(x,y);
}
SetCursorPos(x,y) fonksiyonu imlecin hangi koordinatlarda olacağını belirleyip, imleci o kooridnatlarda konumlanasını sağlar.
BOOL SetCursorPos(
int x,
int y
);
Olarak Windows.h kütüphnesinde tanımlanmıştır.
Parameters
x
[in] Specifies the new x-coordinate, in screen coordinates, of the cursor.
y
[in] Specifies the new y-coordinate, in screen coordinates, of the cursor.
Mousun her çözünürlükte doğru olarak hareketinin sağlanması için bir ekran çözünürlüğünü alan fonksiyon yazıldı.
void GetDesktopResolution(int& yatay, int& dikey)
{
RECT desktop;
// Get a handle to the desktop window
const HWND hDesktop = GetDesktopWindow();
// Windowsun genişlik ve en degerlerinin alınabilmesi için
GetWindowRect(hDesktop, &desktop);
// Üst kösenin koordinatları (0,0) olacaktır.
// ve alttaki kosenin koordinatları (yatay,dikey) biçiminde olcaktır.
yatay = desktop.right;
dikey = desktop.bottom;
}
HWND WINAPI GetDesktopWindow(void); fonkisyonu hiç argüman almayarak tanımlanmıştır.(void).
Main fonkisyonumuuzun içinde
int yatay= 0;
int dusey = 0;
GetDesktopResolution(yatay, dusey); Şeklinde fonksiyon cagrılarak işletime alınmıstır.Elde edilen yatay ve dusey degerlerinden daha once elde edilen posX ve posY degerleriyle gerekli işlemler yapıldıktan sonra olusan degerler mouse koordinatları olarak atanmıstır.Opencv den gelen negatif değerler gözardı edilmesi için bir if kosullandırılması kullanılması mouse için gerekli olmayan değerlerin fonkiyona gonderilmesini engellemiş ve daha basarılı sonuc elde edilmiştir.
mouseposx=yatay-posX*(yatay/en);
mouseposy=posY*(dikey/boy);
Daha once geliştirilen algoritmada yatay/en oranları 2 olarak kabul edilmiş ama du anda uzerinde caliısılan bilgisayarda dogu sonuclar elde edilmesine ragmen baska ortamlarda testen gecemememiştir. Cünkü her bilgisayarın kamera cekim genişliği farklı olup ekrn cozununürlukleri de farklıdır.Fakat fotograf en/ekran boy oranı her zaman dogru katsayı verecegi için sorun teskil etmemektedir.
PosX ve posY nin direk mouseposition fonksiyonunumuza gonderilmememesinin sebebi kameradan dolayı ayna etkisinin oluşmasıydı.Yani ekran bize dönuk olduğu için bizim sağ yöne yaptığımız hareketler sol olarak algılanıyordu ve bu başarılı bir sonuç elde etmede problemdi.
Ekrandaki koordinatları görebilmek için OpenCV den elde ettiğimiz PosX ve PosY değerleri ve ayrıca mouseposx ve mouseposy değerleri ekranda görebilmek adına bu değerleri printf yardımyla console ekranında gorebiliyoruz.
Sol klik işlemleri
CvMoment fonkisyonundn gelen degerler renk algılanmadıgı zaman negatif, diger durumlarda pozitiftir.Bu durumu kullanarak bir asagıdaki algoritmayı yazıldı.
if(solklikx>0 && solkliky>0)//eksi degerlerin mouse fonksiyonuna gitmesini engellemek için…
{
printf(“donguye girdi”);
cvCircle(frame, cvPoint(posX, posY),15,cvScalar(255,0,0),15,8,0);//ekranda gorebilemk için…
//cvCircle(frame, cvPoint(solklikx, solkliky),12,cvScalar(0,255,0),8,8,0);//ekranda gorebilemk için…
solklik=1;
}
/* printf(“%d\n”,solklik);*/
if(solklik==0)
{
mousesolklikbirak(mouseposx,mouseposy);
solklik=2;
printf(“sol birakildi\n”);
}
if(solklik==1)
{
mousesolklikbas(mouseposx,mouseposy);
solklik=0;
printf(“sol basildi\n”);
}
Kullanılan resimlerin ve structerların bırakılması noktaında asagıdaki kodlar yazıldı.
cvShowImage(“kirmizi”, kirmizi);
cvShowImage(“anaekran”, frame);
cvShowImage(“mavi”, mavi);
int c = cvWaitKey(10);
cvReleaseImage(&kirmizi);
cvReleaseImage(&mavi);
delete hareket;