Hoşgeldin Misafir

OpenCV ile Kameradan Fareyle İşaretlenen Renkte Cisim Takibi (C++)

SurHan

28 Kas 2017
4,185 Mesaj

Aktiflik

Seviye

Deneyim

TIM / GÖREV:
-Açıklama:--
Bu programda farenin sol tuşuyla <sağ – aşağıya doğru> bir dikdörtgen çiziyoruz.-
Çizdiğimiz dikdörgenin piksellerini bilgisayar 5 er 5 er atlayarak (atlamadan yapınca işlemci zorlanıyor) renk değerlerini tespit ediyor (HSV koduna göre). Daha sonra bu renk değerlerinde bir cisim görünce onun gezdiği yerlere çizgi çiziyor.-

Çizgileri silmek için ise farenin sağ tuşuna basmamız yeterli.-

kamerayla-renk-takibi.png
-



Kod:
#include <iostream>
 
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/core/core.hpp"
 
using namespace std;
using namespace cv;
 
Mat frame; //kamera görüntüsü frame frame buraya okunuyor
Mat cizgiler; //üzerine çizim yapılan gizli siyah resim
Mat geciciDikdortgen;//renk öğretilirken ekrana çizilen geçici dikdörtgen
Mat sonGoruntu; //çizgileri dikdörtgenin ve kameradan alınan görüntünün birleştirilmiş hali
 
Point ilkKoordinat = 0;
Point sonKoordinat = 0;
 
bool cizgiCiz = false;
 
int HMinDeg = 170;
int HMaxDeg = 179;
int SMinDeg = 150;
int SMaxDeg = 255;
int VMinDeg = 60;
int VMaxDeg = 255;
 
int B;
int G;
int R;
 
void dikdortgenCiz(int event, int x, int y, int flags, void *kullanici)
{
	//farenin sağ tuşuna basınca
	if (event == EVENT_RBUTTONUP)
	{
		cizgiler = Mat::zeros(cizgiler.size(), CV_8UC3);
		cizgiCiz = false;
	}
	//farenin sol tuşuna basınca
	if (event == EVENT_LBUTTONDOWN)
	{
		ilkKoordinat.x = x;
		ilkKoordinat.y = y;
	}
 
	//farenin sol tuşana basarak sürükleyince
	if (flags == EVENT_FLAG_LBUTTON && event == EVENT_MOUSEMOVE)
	{
		//burada geçici bir görüntü gösteriliyor
		//gerçek görüntü sol fareyi bırakınca çiziliyor
		sonKoordinat.x = x;
		sonKoordinat.y = y;
		geciciDikdortgen = Mat::zeros(geciciDikdortgen.size(), CV_8UC3); //zeros yani 0(siyah renk demek) lar matrisi olusturuldu
		rectangle(geciciDikdortgen, Point(ilkKoordinat.x, ilkKoordinat.y), Point(sonKoordinat.x, sonKoordinat.y), Scalar(255, 191, 0), 4, 8, 0);
	}
 
	//farenin sol tuşunu bırakınca
	if (event == EVENT_LBUTTONUP)
	{
		cizgiCiz = true;
		try {
			//aynı noktaya tıklayıp bırakınca Dikdörtgen çizmiyor
			if (!(ilkKoordinat.x == sonKoordinat.x && ilkKoordinat.y == sonKoordinat.y))
			{
				//farenin sol tuşunu bırakınca dikdörtgen siliniyor
				geciciDikdortgen = Mat::zeros(geciciDikdortgen.size(), CV_8UC3); //zeros yani 0(siyah renk demek) lar matrisi olusturuldu
 
				Mat HSV;
				cvtColor(frame, HSV, CV_BGR2HSV);
				Vec3b hsv = HSV.at<Vec3b>(y, x);
 
				int i = ilkKoordinat.x;
				int j = ilkKoordinat.y;
 
				HMinDeg = hsv.val[0];
				HMaxDeg = hsv.val[0];
				SMinDeg = hsv.val[1];
				SMaxDeg = hsv.val[1];
				VMinDeg = hsv.val[2];
				VMaxDeg = hsv.val[2];
 
				Vec3b rgb = frame.at<Vec3b>(y, x);
				B = rgb.val[0];
				G = rgb.val[1];
				R = rgb.val[2];
 
				for (i; i < sonKoordinat.x; i += 5)//x ekseninde geziyor
				{
					for (j; j < sonKoordinat.y; j += 5) //y ekseninde geziyor
					{
						hsv = HSV.at<Vec3b>(j, i);
 
						if (hsv.val[0] < HMinDeg) //bu aralıkta daha küçük h varsa onu min yap
							HMinDeg = hsv.val[0];
						if (hsv.val[0] > HMaxDeg) //bu aralıkta daha buyuk h varsa onu max yap
							HMaxDeg = hsv.val[0];
						if (hsv.val[1] < SMinDeg) //bu aralıkta daha küçük S varsa onu min yap
							SMinDeg = hsv.val[1];
						if (hsv.val[1] > SMaxDeg)
							SMaxDeg = hsv.val[1];
						if (hsv.val[2] < VMinDeg)
							VMinDeg = hsv.val[2];
						if (hsv.val[2] > VMaxDeg)
							VMaxDeg = hsv.val[2];
					}
				}
			}
		}
		catch (...)
		{
			system("cls");
			cout << "<-----------------Hata olustu.----------------->" << endl;
			cout << "<----------Pencerenin disina cikildi.---------->" << endl << endl;
		}
	}
}
 
void goruntuAl()
{
	VideoCapture video(0);
	if (!video.isOpened())
	{
		cout << "Webcam Acilamadi";
		system("pause");
	}
 
	int eskiX = -1;
	int eskiY = -1;
 
	video.read(geciciDikdortgen);
	geciciDikdortgen = Mat::zeros(geciciDikdortgen.size(), CV_8UC3);
 
	//zeros yani 0(siyah renk demek) lar matrisi olusturuldu
	//cizgiler bu Mat nesnesi uzerine cizilecek
	cizgiler = Mat::zeros(geciciDikdortgen.size(), CV_8UC3);
 
	while (true)
	{
		bool bSuccess = video.read(frame);
		flip(frame, frame, 1);//frame'in yatayda simetrisi alınıyor
		if (!bSuccess)
		{
			cout << "Yeni Frame Yuklenemedi" << endl;
			system("pause");
			break;
		}
 
		Mat HSVres;
 
		//renk ayirma(yani secme) isleminde BGR formati HSV formatindan daha basarili oldugu icin
		//Webcam'den alinan BGR formatindaki goruntu HSV formatina donusturuldu
		cvtColor(frame, HSVres, COLOR_BGR2HSV);
 
		Mat isres;//işlenen frame
 
				  //araliktaki degerler 1 diger degerlere 0 veriyor
		inRange(HSVres, Scalar(HMinDeg, SMinDeg, VMinDeg), Scalar(HMaxDeg, SMaxDeg, VMaxDeg), isres);
 
		//morfolojik acma yapiliyor
		//frame'deki beyaz gurultuler engelleniyor
		//once asindirma sonra genisletme yapiliyor
		erode(isres, isres, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
		dilate(isres, isres, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
 
		//morfolojik kapanma yapiliyor
		//beyaz olan nesnelerin arasindaki kucuk siyah holler temizleniyor
		//once genisletme sonra asindirma yapiliyor
		dilate(isres, isres, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
		erode(isres, isres, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
 
		//siyah beyaz bir frame'deki beyaz renklerin konumunu bulur
		//bu konumlar konum degiskenine atandi
		Moments konum = moments(isres);
 
		//piksel degerleri 1 olan piksellerin y eksenindeki konumu bulundu
		double yEksen = konum.m01;
		//piksel degerleri 1 olan piksellerin x eksenindeki konumu bulundu
		double xEksen = konum.m10;
		//degeri 1 olan piksellerin alani bulundu
		double alan = konum.m00;
 
		if (alan > 100000)
		{
			int yeniX = xEksen / alan;
			int yeniY = yEksen / alan;
 
			//bu degerler 0 dan buyukse
			if (eskiX >= 0 && eskiY >= 0 && yeniX >= 0 && yeniY >= 0)
			{
				//1. parametredeki konumdan 2. parametredeki konuma
				//3. parametrede belirtilen kirmizi renkte
				//4. parametrede belirtilen kalinlikta yani 2 piksel boyutunda
				//Siyah uzerine cizgi cizer			
				if (cizgiCiz == true) {
					line(cizgiler, Point(yeniX, yeniY), Point(eskiX, eskiY), Scalar(B, G, R), 2);
				}
			}
 
			//son bulunan koordinatlar saklanmak icin degiskenlere ataniyor
			eskiX = yeniX;
			eskiY = yeniY;
		}
 
		//dikdörtgen çizmek için fare hareketleri takip ediliyor
		setMouseCallback("Orjinal", dikdortgenCiz, NULL);
 
		imshow("Siyah Beyaz Resim", isres);
 
		//webcam'deki goruntuye cizgiler eklendi
		//webcam'deki görüntüye geçici diktdörtgen eklendi
		sonGoruntu = frame + cizgiler + geciciDikdortgen;
 
		imshow("Orjinal", sonGoruntu);
 
		if (waitKey(30) == 27)
		{
			cout << "Kullanici esc ile cikti" << endl;
			break;
		}
	}
}
 
int main()
{
	goruntuAl();
	destroyAllWindows();
	system("pause");
	return 0;
}