針對前方交會需要選擇同名點,對圖像進行選點的需求,編寫本程序實現對圖像進行選點操作。
利用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;
本工程目錄下是由一張相機連續移動拍攝的多張圖像,如下圖所示。因此前後兩張可以看做立體像,對圖像進行選點操作。讀者可以自己選擇圖像,進行選點操作練習。
程序演示效果效果試下:上圖爲選點效果,下圖對其中的點進行刪除。