opencv鼠標鼠標響應回調函數setMouseCallback()對顯示圖像進行操作

針對前方交會需要選擇同名點,對圖像進行選點的需求,編寫本程序實現對圖像進行選點操作。

利用OpenCV函數讀取顯示圖像,利用鼠標操作函數進行選點刪除功能。本代碼僅供參考。

// ForwardIntersection.cpp : 定義控制檯應用程序的入口點。
//
/*控制檯實現選同名點
顯示兩張立體像對,利用鼠標左鍵選擇同名點,右鍵對選錯的點進行刪除(鼠標要放到被刪除點的附近)
Author:dyl  Date: 2018/12/07
*/

#include "stdafx.h"
#include<iostream>
#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"//putText和circle函數用到
#include"io.h"

using namespace std;
using namespace cv;

vector<Point> pointLeft,pointRight;

void getFiles(std::string path, std::vector<std::string>&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<<"左圖像目前沒有點,不必刪除,請左鍵選點"<<endl;
		}
		else
		{
			int Index;//記錄最臨近點的索引
			double minDistance=10000000;
			double tempDistance;
			for (int i = 0; i < pointLeft.size(); i++)
			{
				tempDistance = sqrt(pow(x - pointLeft[i].x, 2) + pow(y - pointLeft[i].y, 2));
				if (minDistance > 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 = "測試數據";
	vector<string>files;
	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;

本工程目錄下是由一張相機連續移動拍攝的多張圖像,如下圖所示。因此前後兩張可以看做立體像,對圖像進行選點操作。讀者可以自己選擇圖像,進行選點操作練習。

程序演示效果效果試下:上圖爲選點效果,下圖對其中的點進行刪除。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章