针对前方交会需要选择同名点,对图像进行选点的需求,编写本程序实现对图像进行选点操作。
利用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;
本工程目录下是由一张相机连续移动拍摄的多张图像,如下图所示。因此前后两张可以看做立体像,对图像进行选点操作。读者可以自己选择图像,进行选点操作练习。
程序演示效果效果试下:上图为选点效果,下图对其中的点进行删除。