前边几篇文章基本上介绍了:OpenCV对二维图片的缩放、平移以及旋转操作。和Leap Motion的常见接口函数。今天目的是将所有所学整合在一起,彻底完成与二维图片交互操作。
    本来打算用Leap Motion里边手部向量之类的特征函数来控制图片的旋转,发现一是难度比较大,二是手掌旋转起来特别别扭。因此,仔细考量之后,最终选择了:hand.palmPosition().x来控制图片的左右平移、hand.palmPosition().z来控制图片的上下平移、hand.palmPosition().y来控制图片的旋转、hand.sphereRadius()来控制图片的缩放。这样做的优点在于:代码简洁,原理比较明了,而且手部比较稳定,不会产生在控制图片一个维度时另外几个维度也发生较大摆动。话不多少,直接上代码:
#include <iostream>
#include <cstring>
#include <windows.h> 
#include <stdio.h>  
#include <conio.h> 
#include <opencv2/opencv.hpp> 
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp> 
#include <Leap.h>

using namespace Leap;
using namespace cv;
using namespace std;

bool flags = 1;
float radios, angle = 0;
float position[3] = { 0,0,0 };
Point2f point(0.0, 0.0);

class MouseListener : public Listener {
public:
	virtual void onInit(const Controller&);
	virtual void onConnect(const Controller&);
	virtual void onFrame(const Controller&);
	
	virtual void onDisconnect(const Controller&);
	virtual void onExit(const Controller&);
	/*virtual void onFocusGained(const Controller&);
	virtual void onFocusLost(const Controller&);
	virtual void onDeviceChange(const Controller&);*/
	virtual void onServiceConnect(const Controller&);
	virtual void onServiceDisconnect(const Controller&);
	/*virtual void onServiceChange(const Controller&);
	virtual void onDeviceFailure(const Controller&);
	virtual void onLogMessage(const Controller&, MessageSeverity severity, int64_t timestamp, const char* msg);
	*/
private:
};

class show_picture //定义一个新的用来与图像交互的类
{
public:
	Mat image, image_size_change, image_for_display;//image是原始图片,永远不做更改。image_size_change相当于每一次更改后的图片。image_for_display是用来显示的,相当于包含了image_size_change的画布。
	float mul = 1.0;
	void imshow_FullScreen(Mat img);//在画布上显示图片
	void Translation(int dx, int dy);//图片平移
	void Change_Size(float div);//图片放大缩小
	void Revolve(float degree);
	void Picture_Init();
	void Display(int x, int y, float div, float degree);
	show_picture(int width, int length, int x, int y)
	{
		Screen_Width = width;
		Screen_Length = length;
		point_O.x = x;
		point_O.y = y;
	}
	show_picture()
	{
		Screen_Width = 1080;
		Screen_Length = 1920;
		point_O.x = 0;
		point_O.y = 0;
	}
private:
	Point2f point_O, pointA, pointB;//图片的左上方原点(用来定位图片)
	int Screen_Width, Screen_Length;//画布的长和宽
};

void MouseListener::onInit(const Controller& controller) 
{
	std::cout << "初始化完成" << std::endl;
}

void MouseListener::onConnect(const Controller& controller) 
{

	std::cout << "Connected" << std::endl;
	

	/*controller.enableGesture(Gesture::TYPE_CIRCLE);//解锁手势——画圈
	controller.enableGesture(Gesture::TYPE_KEY_TAP);//解锁手势——点击
	controller.enableGesture(Gesture::TYPE_SWIPE);//解锁手势——挥手
	controller.enableGesture(Gesture::TYPE_SCREEN_TAP);//解锁手势——点击屏幕
	controller.setPolicyFlags(Controller::PolicyFlag::POLICY_BACKGROUND_FRAMES);*///允许程序在后台时依然可以接收到Leap Motion的消息
}

void MouseListener::onDisconnect(const Controller& controller)
{
	std::cout << "Disconnected" << std::endl;
}

void MouseListener::onExit(const Controller& controller)
{
	std::cout << "Exited" << std::endl;
}

void MouseListener::onServiceConnect(const Controller& controller)
{
	std::cout << "ServiceConnected" << std::endl;
}

void MouseListener::onServiceDisconnect(const Controller& controller)
{
	std::cout << "ServiceDisconnected" << std::endl;
}

void MouseListener::onFrame(const Controller& controller)
{
	const Frame frame = controller.frame();//定义一个帧
	ImageList images = frame.images();//定义一个帧的采集到的图像
	HandList hands = frame.hands();
	const Hand hand = *hands.begin();
	position[0] = hand.palmPosition().x;//-140~140
	position[1] = hand.palmPosition().y;
	position[2] = hand.palmPosition().z-10;
	flags=0;
	radios = hand.sphereRadius();
	waitKey(10);
}

void show_picture::Translation(int dx, int dy)
{
	point_O.x += dx;
	point_O.y += dy;
}

/****************显示带有画布的图片*****************/
void show_picture::imshow_FullScreen(Mat img)
{
	copyMakeBorder(img, image_for_display, point_O.y, Screen_Width - point_O.y - img.rows, point_O.x, Screen_Length - point_O.x - img.cols, BORDER_CONSTANT, Scalar(0, 0, 0));//OpenCV自带的扩充图片的函数
	namedWindow("Canvases", WINDOW_AUTOSIZE);
	circle(image_for_display, point_O, 3, Scalar(0, 0, 255));//标注原点位置方便调试
	imshow("Canvases", image_for_display);//最终显示的是扩充后的图片

}

/****************带有缩放操作的图片显示函数,自定义画布*****************/
void show_picture::Change_Size(float div)
{
	point_O.x += (image_size_change.cols - image_size_change.cols*div) / 2;//计算缩放后的新的坐标
	point_O.y += (image_size_change.rows - image_size_change.rows*div) / 2;
	mul *= div;//采用对每一次的缩放因子累计相乘的方式来消除因为缩放引起的模糊问题
	resize(image_size_change, image_size_change, Size(), div, div);//这里使用的是image原始图片,因此不会越来越模糊

}

void show_picture::Picture_Init()
{
	point_O.x = 500;
	point_O.y = 400;
	resize(image, image_size_change, Size(), 0.2, 0.2);

}
void show_picture::Revolve(float degree)
{
	float radians = degree * CV_PI / 180;

	int uniSize = (int)(max(image_size_change.cols, image_size_change.rows)* 1.414);
	int dx = (int)(uniSize - image_size_change.cols) / 2;
	int dy = (int)(uniSize - image_size_change.rows) / 2;

	copyMakeBorder(image_size_change, image_size_change, dy, dy, dx, dx, BORDER_CONSTANT, Scalar(0, 0, 0));


	Point2f center((float)(image_size_change.cols / 2), (float)(image_size_change.rows / 2));
	Mat affine_matrix = getRotationMatrix2D(center, degree, 1.0);

	//旋轉
	warpAffine(image_size_change, image_size_change, affine_matrix, image_size_change.size());

	point_O.x -= dx;
	point_O.y -= dy;

	imshow_FullScreen(image_size_change);

}

void show_picture::Display(int x, int y, float div, float degree)
{
	Picture_Init();
	Translation(x, y);
	Change_Size(div);
	Revolve(degree);
}

int main(int argc, char**argv)
{
	MouseListener listener;//定义一个监听类变量
	Controller controller;//定义一个控制类变量
	controller.addListener(listener);//将监听类变量加入控制之中
	controller.setPolicy(Leap::Controller::POLICY_BACKGROUND_FRAMES);//打开frame功能
	controller.setPolicy(Leap::Controller::POLICY_IMAGES);//打开images功能

	show_picture picture(1080, 1920, 600, 400);//定义一个1080*1920大小的画布,初始原点在(600,400)的位置
	picture.image = imread("C:\\Users\\MacheNike\\Desktop\\123.jpg");//读入原始图片
	float i = 0,div;

	while (1)
	{
		if ((flags == 0)&&(radios!=0))//采集到一帧图像时进入此程序
		{
			flags = 1;
			div = 1 + (radios-35)  / 20;
			angle = (150 - position[1])*2.5;
			point.x += position[0];
			point.y += position[2];
			picture.Display(point.x/20,point.y/20,div,angle);
			waitKey(1);
		}
	}
	controller.removeListener(listener);//移除监听类
}

至此,一个粗略的Leap Motion与二维图像交互的实验已经完成了,接下来进入与三维图像交互(VTK)!