opencv鼠标响应回调函数setMouseCallback()对显示图像进行操作

针对前方交会需要选择同名点,对图像进行选点的需求,编写本程序实现对图像进行选点操作。

利用OpenCV函数读取显示图像,利用鼠标操作函数进行选点删除功能。本代码仅供参考。

// ForwardIntersection.cpp : 定义控制台应用程序的入口点。
//
/*控制台实现选同名点
显示两张立体像对,利用鼠标左键选择同名点,右键对选错的点进行删除(鼠标要放到被删除点的附近)
Author:dyl  Date: 2018/12/07
*/

#include "stdafx.h"
#include
#include
#include
#include"opencv2/imgproc/imgproc.hpp"//putText和circle函数用到
#include"io.h"

using namespace std;
using namespace cv;

vector pointLeft,pointRight;

void getFiles(std::string path, std::vector&files)
{
	/*****获取路径下的所有文件*****/
	//文件句柄
	long hFile = 0;
	struct _finddata_t fileinfo;
	std::string p;
	if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
	{
		do
		{
			//如果是目录,迭代
			//如果不是,加入列表
			if (fileinfo.attrib&_A_SUBDIR)//如果是文件夹
			{
				if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
				{
					getFiles(p.assign(path).append("\\").append(fileinfo.name), files);
				}
			}
			else
			{
				files.push_back(p.assign(path).append("\\").append(fileinfo.name));
			}
		} while (_findnext(hFile, &fileinfo) == 0);
		_findclose(hFile);
	}
}

void on_mouse1(int event, int x, int y, int flags, void *ustc)//event鼠标事件代号,x,y鼠标坐标,flags拖拽和键盘操作的代号  
{
	cv::Mat& LeftImg = *(cv::Mat*) ustc;
	char temp[16];
	Point pre_pt;
	if (event == CV_EVENT_LBUTTONDOWN)//左键按下,读取初始坐标,并在图像上该点处划圆  
	{
		
		Mat tempLeftImg;
		LeftImg.copyTo(tempLeftImg);
		pre_pt = Point(x, y);
		pointLeft.push_back(pre_pt);
		for (int i = 0; i < pointLeft.size(); i++)
		{
			sprintf(temp, "(%d,%d)", pointLeft[i].x, pointLeft[i].y);
			putText(tempLeftImg, temp, pointLeft[i],FONT_HERSHEY_SIMPLEX, 2, Scalar(0, 0,255, 255), 2, 8);//在窗口上显示坐标  
			circle(tempLeftImg, pointLeft[i], 2, Scalar(255, 0, 0, 0), CV_FILLED, CV_AA, 0);//划圆  

		}
		imshow("left", tempLeftImg);
	}
	else if (event == CV_EVENT_RBUTTONDOWN)
	{
		if (pointLeft.size() == 0)
		{
			cout<<"左图像目前没有点,不必删除,请左键选点"< tempDistance)
				{
					minDistance = tempDistance;
					Index = i;
				}
			}
			pointLeft.erase(pointLeft.begin()+Index);

			Mat tempLeftImg2;
			LeftImg.copyTo(tempLeftImg2);
			for (int i = 0; i < pointLeft.size(); i++)
			{
				sprintf(temp, "(%d,%d)", pointLeft[i].x, pointLeft[i].y);
				putText(tempLeftImg2, temp, pointLeft[i], FONT_HERSHEY_SIMPLEX, 2, Scalar(0, 0, 255, 255), 2, 8);//在窗口上显示坐标  
				circle(tempLeftImg2, pointLeft[i], 2, Scalar(255, 0, 0, 0), CV_FILLED, CV_AA, 0);//划圆  
			}
			imshow("left", tempLeftImg2);
		}
	}
	
	else if (event == CV_EVENT_MOUSEMOVE)
	{
		Mat tempLeftImg;
		LeftImg.copyTo(tempLeftImg);
	
		for (int i = 0; i < pointLeft.size(); i++)
		{
			sprintf(temp, "(%d,%d)", pointLeft[i].x, pointLeft[i].y);
			putText(tempLeftImg, temp, pointLeft[i], FONT_HERSHEY_SIMPLEX, 2, Scalar(0, 0, 255, 255), 2, 8);//在窗口上显示坐标  
			circle(tempLeftImg, pointLeft[i], 2, Scalar(255, 0, 0, 0), CV_FILLED, CV_AA, 0);//划圆  
		}
		pre_pt = Point(x, y);
		sprintf(temp, "(%d,%d)",x, y);
		putText(tempLeftImg, temp, pre_pt, FONT_HERSHEY_SIMPLEX, 2, Scalar(0, 0, 255, 255), 2, 8);//在窗口上显示坐标  
		imshow("left", tempLeftImg);
	}
}

void on_mouse2(int event, int x, int y, int flags, void *ustc)//event鼠标事件代号,x,y鼠标坐标,flags拖拽和键盘操作的代号  
{
	cv::Mat& RightImg = *(cv::Mat*) ustc;
	char temp[16];
	Point pre_pt;
	 if (event == CV_EVENT_LBUTTONDOWN)//右键按下,读取初始坐标,并在图像上该点处划圆  
	{
		Mat tempRightImg;
		RightImg.copyTo(tempRightImg);
		pre_pt = Point(x, y);
		pointRight.push_back(pre_pt);
		for (int i = 0; i < pointRight.size(); i++)
		{
			sprintf(temp, "(%d,%d)", pointRight[i].x, pointRight[i].y);
			putText(tempRightImg, temp, pointRight[i], FONT_HERSHEY_SIMPLEX, 2, Scalar(255, 0, 0, 255), 2, 8);//在窗口上显示坐标  
			circle(tempRightImg, pointRight[i], 2, Scalar(255, 0, 0, 0), CV_FILLED, CV_AA, 0);//划圆  

		}
		imshow("right", tempRightImg);
	}
	else if (event == CV_EVENT_RBUTTONDOWN )//鼠标移动的处理函数  
	{
		if (pointRight.size() == 0)
		{
			cout << "右图像当前没有点,不必删除,请左键选点" << endl;
		}
		else
		{
			int Index=0;
			double minDistance = 10000000;
			double tempDistance;
			for (int i = 0; i < pointRight.size(); i++)
			{
				tempDistance = sqrt(pow(x - pointRight[i].x, 2) + pow(y - pointRight[i].y, 2));
				if (minDistance > tempDistance)
				{
					minDistance = tempDistance;
					Index = i;
				}
			}
			pointRight.erase(pointRight.begin() + Index);

			Mat tempRightImg2;
			RightImg.copyTo(tempRightImg2);
			for (int i = 0; i < pointRight.size(); i++)
			{
				sprintf(temp, "(%d,%d)", pointRight[i].x, pointRight[i].y);
				putText(tempRightImg2, temp, pointRight[i], FONT_HERSHEY_SIMPLEX, 2, Scalar(255, 0, 0, 255), 2, 8);//只是实时显示鼠标移动的坐标  
				circle(tempRightImg2, pointRight[i], 2, Scalar(255, 0, 0, 0), CV_FILLED, CV_AA, 0);//划圆  
			}
			imshow("right", tempRightImg2);
		}
	}	
	else if (event == CV_EVENT_MOUSEMOVE)
	{
		Mat tempRightImg;
		RightImg.copyTo(tempRightImg);
		for (int i = 0; i < pointRight.size(); i++)
		{
			sprintf(temp, "(%d,%d)", pointRight[i].x, pointRight[i].y);
			putText(tempRightImg, temp, pointRight[i], FONT_HERSHEY_SIMPLEX, 2, Scalar(255, 0, 0, 255), 2, 8);//在窗口上显示坐标  
			circle(tempRightImg, pointRight[i], 2, Scalar(255, 0, 0, 0), CV_FILLED, CV_AA, 0);//划圆  
		}
		pre_pt = Point(x, y);
		sprintf(temp, "(%d,%d)", x, y);
		putText(tempRightImg, temp, pre_pt, FONT_HERSHEY_SIMPLEX, 2, Scalar(255, 0, 0, 255), 2, 8);//在窗口上显示坐标  
		imshow("right", tempRightImg);
	}
}

int main()
{
	const char* filePath = "测试数据";
	vectorfiles;
	getFiles(filePath, files);//获取该路径下所有文件
	if (files.size() == 0)
	{
		cout << "NO Find Files!" << endl;
		return EXIT_FAILURE;
	}
	cout << "左键选点,右键删除" << endl;
	Mat LeftImg, RightImg;
	string left, right;
	for (int i = 0; i < files.size(); i=i+2)
	{
		LeftImg = imread(files[i].c_str());
		RightImg = imread(files[i+2].c_str());
	
		namedWindow("left", WINDOW_NORMAL);
		namedWindow("right", WINDOW_NORMAL);

		imshow("left", LeftImg);
		imshow("right", RightImg);

		setMouseCallback("left", on_mouse1, (void*)&LeftImg);//调用回调函数 
		setMouseCallback("right", on_mouse2, (void*)&RightImg);
		waitKey();
	}
	destroyAllWindows();
	return 0;
}

setmOusecallback函数的最后一个参数可以把图像传到on_mouse1()函数中,这样可以避免定义全局变量 。需要在on_mouse1()函数中添加一句代码 cv::Mat& RightImg = *(cv::Mat*) ustc;

本工程目录下是由一张相机连续移动拍摄的多张图像,如下图所示。因此前后两张可以看做立体像,对图像进行选点操作。读者可以自己选择图像,进行选点操作练习。

opencv鼠标响应回调函数setMouseCallback()对显示图像进行操作_第1张图片opencv鼠标响应回调函数setMouseCallback()对显示图像进行操作_第2张图片

程序演示效果效果试下:上图为选点效果,下图对其中的点进行删除。

 

你可能感兴趣的:(opencv)