Photoshop中的套索工具通过鼠标多次点击可以选中一个任意多边形的区域,然后单独对这块区域进行编辑,下面就使用OpenCV实现一个简单的功能,模拟Photoshop中的套索工具。
这里的套索工具通过鼠标左键在图片上多次点击创建任意多个点,右键点击后将这些点连成封闭的多边形,形成一块待编辑的区域,键盘方向键控制该区域的移动,从而将该区域内的图像复制到原图像的其他地方。
首先定义下列全局变量
const char* winName = "TaoSuoTool";//窗口名称
cv::Mat resultImg;//最终在OpenCV窗口上显示的图像
cv::Mat foregroundImg;//编辑前的图像
cv::Mat areaMask;//蒙版,多边形区域实际绘制在该蒙版上
cv::Point maskLocation;//蒙版位置,通过方向键移动后蒙版位置随之变化
std::vector<cv::Point> drawingPoints;//区域完成前正在点击的所有点
std::vector<cv::Point> areaPoints;//区域完成后其多边形顶点
main函数
int main(int argc, char **arv)
{
foregroundImg = cv::imread("test.jpg");
foregroundImg.copyTo(resultImg);
areaMask = cv::Mat::zeros(foregroundImg.size(), CV_8U);
cv::imshow(winName, resultImg);
maskLocation.x = maskLocation.y = 0;
cv::setMouseCallback(winName, OnMouseEvent);
int key = cv::waitKeyEx(0);
while (key != VK_ESCAPE)
{
key = cv::waitKeyEx(0);
}
return 0;
}
在鼠标回调函数OnMouseEvent中处理三个消息:鼠标左键按下,鼠标右键按下和鼠标移动
void OnMouseEvent(int event, int x, int y, int flags, void* userdata)
{
if (event == cv::EVENT_LBUTTONDOWN)
{
OnLeftMouseButtonDown(x,y);
}
else if (event == cv::EVENT_RBUTTONDOWN)
{
OnRightMouseButtonDown(x,y);
}
if (event == cv::EVENT_MOUSEMOVE)
{
OnMouseMove(x,y);
}
}
在编写鼠标事件前先定义一个函数
void OnCompleteArea(bool bDrawOutline);
它表示完成当前区域的编辑,包括右键点击完成封闭多边形、移动区域以及合成最终图片。参数bDrawOutline表示绘制区域多边形的外轮廓,右键点击完成封闭多边形和移动区域过程中都要显示轮廓(bDrawOutline=true),合成最终图片后就不需要显示轮廓了(bDrawOutline=false)。
鼠标左键按下事件:先判断是否有前一个区域存在,存在则先完成前一个区域并且不显示区域轮廓,然后开始绘制新的区域多边形的点,点与点之间用蓝色线连接,点位置处绘制一个4X4的红色矩形。
void OnLeftMouseButtonDown(int x,int y)
{
if (drawingPoints.empty() && areaPoints.size() > 0)
{
OnCompleteArea(false);
}
drawingPoints.push_back(cv::Point(x, y));
cv::rectangle(resultImg, cv::Rect(x - 2, y - 2, 4, 4), CV_RGB(255, 0, 0), -1);
if (drawingPoints.size() >= 2)
{
cv::line(resultImg, drawingPoints[drawingPoints.size() - 2], cv::Point(x, y), CV_RGB(0, 0, 255), 1);
}
cv::imshow(winName, resultImg);
}
鼠标移动事件:判断drawingPoints是否为空,如果已经存在点则绘制线和点,并且还要绘制一根连接到鼠