LINUX.ORG.RU
ФорумTalks

Делаем «графический планшет» из веб-камеры и старой мыши

 , ,


3

1

Итак (для нетерпеливых видео результата в самом низу), идея сделать что-то вроде планшета для рисования из веб-камеры и старой мыши родилась (как у всех ненормальных) ночью:


lorimage:320x240
Идея заключалась в том, что бы написать программу (используя opencv как основу), отслеживающую веб-камерой объект опр. цвета, и переводящую его координаты, в координаты курсора мыши. На утро, принялся создавать свое «инновационное» устройство. Раскурочил старую мышь, отпаял правую кнопку:
lorimage:320x240
Припаял кнопку к длинным проводам, и замотал ее на простую шариковую ручку, к концу пришкварил небольшую пластиковую крышку розового цвета, которую собственно и будет отслеживать программа:
lorimage:320x240
Устройство готово, дело оставалось за малым — написать программу:

// wsight
#include "iostream"
#include "time.h"
#include "string"
#include "X.h"
#include "Xlib.h"
#include "Xutil.h"
#include "opencv2/opencv.hpp"

using namespace std;

IplImage* imgTracking;
int lastX = -1;
int lastY = -1;
bool shows = false;

string intToString(int N) {
	ostringstream ss("");
	ss << N;
	return ss.str();
}

string floatToString(float N) {
	ostringstream ss("");
	ss << N;
	return ss.str();
}

IplImage* getThresholdedImage(IplImage* imgHSV) {
	IplImage* imgThresh = cvCreateImage(cvGetSize(imgHSV), IPL_DEPTH_8U, 1);
	cvInRangeS(imgHSV, cvScalar(130, 100, 100), cvScalar(179, 256, 256), imgThresh);
	return imgThresh;
}

void trackObject(IplImage* imgThresh) {
	CvMoments *moments = (CvMoments*) malloc(sizeof(CvMoments));
	cvMoments(imgThresh, moments, 1);
	double moment10 = cvGetSpatialMoment(moments, 1, 0);
	double moment01 = cvGetSpatialMoment(moments, 0, 1);
	double area = cvGetCentralMoment(moments, 0, 0);

	if (area > /*250*/100) {
		int posX = moment10 / area;
		int posY = moment01 / area;
		shows = true;
		lastX = posX;
		lastY = posY;
	}
	else {
		shows = false;
	}
	free(moments);
}

void setCaptureMouse() {
	CvCapture* capture = 0;
	capture = cvCaptureFromCAM(0);
	int w = 320;
	int h = 240;
	cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, w);
	cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, h);
	IplImage* frame = 0;
	frame = cvQueryFrame(capture);
	imgTracking = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);
	cvZero(imgTracking);
	cvNamedWindow("Video");
	cvSetWindowProperty("Video", w, h);
	cvResizeWindow("Video", w, h);
	cvNamedWindow("Ball");
	cvSetWindowProperty("Ball", w, h);
	cvResizeWindow("Ball", w, h);
	cout << "Works capture mouse\n";
	Display *dpy;
					Window root_window;
					dpy = XOpenDisplay(0);
					root_window = XRootWindow(dpy, 0);
					XSelectInput(dpy, root_window, KeyReleaseMask);
	while (true) {
		frame = cvQueryFrame(capture);
		frame = cvCloneImage(frame);
		IplImage* imgHSV = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);
		cvCvtColor(frame, imgHSV, CV_BGR2HSV);
		IplImage* imgThresh = getThresholdedImage(imgHSV);
		cvFlip(imgThresh, imgThresh, 1);
		cvFlip(frame, frame, 1);
		trackObject(imgThresh);
		cvAdd(frame, imgTracking, frame);
		if (shows) {
			cvLine(frame, cv::Point(lastX + 8, lastY),cv::Point(lastX + 20, lastY), cv::Scalar(0, 256, 0), 2,2);
			cvLine(frame, cv::Point(lastX - 8, lastY),cv::Point(lastX - 20, lastY), cv::Scalar(0, 256, 0), 2,2);
			cvLine(frame, cv::Point(lastX, lastY + 8),cv::Point(lastX, lastY + 20), cv::Scalar(0, 256, 0), 2,2);
			cvLine(frame, cv::Point(lastX, lastY - 8),cv::Point(lastX, lastY - 20), cv::Scalar(0, 256, 0), 2,2);

			cvLine(frame, cv::Point(lastX + 20, lastY),cv::Point(lastX + 80, lastY), cv::Scalar(256, 256, 256), 1,1);
			cvLine(frame, cv::Point(lastX - 20, lastY),cv::Point(lastX - 80, lastY), cv::Scalar(256, 256, 256), 1,1);
			cvLine(frame, cv::Point(lastX, lastY + 20),cv::Point(lastX, lastY + 80), cv::Scalar(256, 256, 256), 1,1);
			cvLine(frame, cv::Point(lastX, lastY - 20),cv::Point(lastX, lastY - 80), cv::Scalar(256, 256, 256), 1,1);
			XWarpPointer(dpy, None, root_window, 0, 0, 0, 0, lastX*2.0f, lastY*2.0f);
					XFlush(dpy);
		}
		else {
			cvLine(frame, cv::Point(lastX + 8, lastY),cv::Point(lastX + 20, lastY), cv::Scalar(0, 0, 256), 2,2);
			cvLine(frame, cv::Point(lastX - 8, lastY),cv::Point(lastX - 20, lastY), cv::Scalar(0, 0, 256), 2,2);
			cvLine(frame, cv::Point(lastX, lastY + 8),cv::Point(lastX, lastY + 20), cv::Scalar(0, 0, 256), 2,2);
			cvLine(frame, cv::Point(lastX, lastY - 8),cv::Point(lastX, lastY - 20), cv::Scalar(0, 0, 256), 2,2);

			cvLine(frame, cv::Point(lastX + 20, lastY),cv::Point(lastX + 80, lastY), cv::Scalar(256, 256, 256), 1,1);
			cvLine(frame, cv::Point(lastX - 20, lastY),cv::Point(lastX - 80, lastY), cv::Scalar(256, 256, 256), 1,1);
			cvLine(frame, cv::Point(lastX, lastY + 20),cv::Point(lastX, lastY + 80), cv::Scalar(256, 256, 256), 1,1);
			cvLine(frame, cv::Point(lastX, lastY - 20),cv::Point(lastX, lastY - 80), cv::Scalar(256, 256, 256), 1,1);
		}
		cvShowImage("Video", frame);
		cvShowImage("Ball", imgThresh);
		cvReleaseImage(&imgHSV);
		cvReleaseImage(&imgThresh);
		cvReleaseImage(&frame);
		int c = cvWaitKey(10);
		if ((char) c == 27) break;
	}
	cvDestroyAllWindows();
	cvReleaseImage(&imgTracking);
	cvReleaseCapture(&capture);
}

int main (void) {
	setCaptureMouse();
	return 0;
}


В результате получилось довольно забавно:
Видео процесса рисования «инновационным» устройством :D

lorimage:320x240



Последнее исправление: makeB (всего исправлений: 4)

срочно бежать и получать грант

kto_tama ★★★★★
()
#include "iostream"
#include "time.h"
#include "string"
#include "X.h"
#include "Xlib.h"
#include "Xutil.h"
#include "opencv2/opencv.hpp"

в те времена, когда меня учили C++, использовалось два вида инклюдов - в угловых скобках для «системных» инклюдов и в кавычках для заголовочных файлов локального проекта.

кажется что-то пошло не так?

StrongDollar
()

самое забавное, почему даже такой способ лагает намного меньше чем galaxy note?

dimon555 ★★★★★
()
Ответ на: комментарий от StrongDollar

кажется что-то пошло не так?

Не знаю произошло или нет, лично я использую кавычки потому, что со скобками геморроя больше.

makeB
() автор топика
Ответ на: комментарий от CYB3R

Как прикольный проект сойдёт. А для рисования... Купи уже планшет.

так работают коммерческие презентационные доски, стоящие бешеные $$$

только камеры там обычно 2, по углам доски

stevejobs ★★★★☆
()
Ответ на: комментарий от StrongDollar

в те времена, когда меня учили C++, использовалось два вида инклюдов - в угловых скобках для «системных» инклюдов и в кавычках для заголовочных файлов локального проекта.

++

Pinkbyte ★★★★★
()
Ответ на: комментарий от stevejobs

У нас в школе такая была, толку от неё мало. Я бы сделал так: проэктор, вебка и лазерная указка. Недорого и удобно.

CYB3R ★★★★★
()
Ответ на: комментарий от StrongDollar

Hmmm... Я думал, что с тех пор ничего не поменялось.

CYB3R ★★★★★
()
Ответ на: комментарий от theNamelessOne

Использует echo вместо редактора.

CYB3R ★★★★★
()
Ответ на: комментарий от theNamelessOne

ну вдруг он захочет написать свой iostream - с уголками, возможно, придется заголовки переписывать

stevejobs ★★★★☆
()
Ответ на: комментарий от theNamelessOne

Зачем мне конопатится обрамляя каждый инклуд разным способом, в зависимости от того, где он находится, если можно обрамить его кавычками, и в этом случае он по любому найдется независимо от пути? Ради каких-то стандартов? Не, этим пусть педанты занимаются, я безалаберен относительно таких вещей :)

makeB
() автор топика

Добавьте 5 звезд ТСу, таких кадров надо беречь и от ЛОРа не отрывать.

Deleted
()

А ничего, что мышь сама по себе является устройством, отслеживающим своё перемещение в пространстве? И намного точнее всяких OpenCV. Лучше бы запилил рисование пальцем по столу с помощью OpenCV :D

Sadler ★★★
()

Неплохо, но такое уже было сделано и есть готовый код, вроде даже на Python.

Quasar ★★★★★
()
Ответ на: комментарий от StrongDollar

кажется что-то пошло не так?

Ага, в образовании.

Pavval ★★★★★
()

даже клей и пластиковые бутылки не пригодились

reliktt
()

А теперь то же самое пожалуйста в wayland-devel. Сейчас Peter Hutterer как раз занимается графическими планшетами.

AEP ★★★★★
()
Ответ на: комментарий от skiminok1986

Что-то типа того, или гитара в воздухе.

Самое интересное даже не конвертация движения в высоту звука, но и передача данных об атаке.

shimon ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.