/*
* create_mask.cpp
*
* Author:
* Siddharth Kherada <siddharthkherada27[at]gmail[dot]com>
*
* 这个教程演示了如何制作掩膜图像(黑白图像)。
* 该程序将输入图像作为源图像,并输出对应的掩膜图像。
*/
#include "opencv2/imgproc.hpp" // 导入OpenCV图像处理头文件
#include "opencv2/imgcodecs.hpp" // 导入OpenCV图像编码解码头文件
#include "opencv2/highgui.hpp" // 导入OpenCV高层图形用户界面头文件
#include <iostream> // 导入输入输出流头文件
using namespace std; // 使用std命名空间,避免每次都要加std::
using namespace cv; // 使用cv命名空间,避免每次都要加cv::
Mat src, img1, mask, final; // 定义Mat类对象src(源图像),img1(中间图像),mask(掩膜),final(最终结果)
Point point; // 定义一个点变量
vector<Point> pts; // 定义一个点的向量,用于存储多个点
int drag = 0; // 定义一个整型变量drag表示是否在拖动,默认为0(不在拖动)
int var = 0; // 定义一个整型变量var用来计数,初始化为0
int flag = 0; // 定义一个整型变量flag用来标记,初始化为0
void mouseHandler(int, int, int, int, void*); // 声明鼠标响应函数
void mouseHandler(int event, int x, int y, int, void*)
{
// 鼠标响应函数
if (event == EVENT_LBUTTONDOWN && !drag)
{
// 左键按下且不在拖动状态时
if (flag == 0)
{
// 如果flag为0表明还未完成绘制
if (var == 0)
img1 = src.clone(); // 如果是第一个点,
point = Point(x, y); // 将点击的点位置保存到point中
circle(img1, point, 2, Scalar(0, 0, 255), -1, 8, 0); // 在img1上绘制点
pts.push_back(point); // 把点添加到向量pts中
var++; // 计数加1
drag = 1; // 标记为拖动状态
if (var > 1)
line(img1,pts[var-2], point, Scalar(0, 0, 255), 2, 8, 0); // 绘制线段
imshow("Source", img1); // 显示img1
}
}
if (event == EVENT_LBUTTONUP && drag)
{
// 左键释放且正处于拖动状态
imshow("Source", img1); // 显示img1
drag = 0; // 标记为非拖动状态
}
if (event == EVENT_RBUTTONDOWN)
{
// 右键按下
flag = 1; // 设置标记位
img1 = src.clone(); // 重新克隆源图像到img1
if (var != 0)
{
polylines( img1, pts, 1, Scalar(0,0,0), 2, 8, 0); // 绘制多边形轮廓
}
imshow("Source", img1); // 显示img1
}
if (event == EVENT_RBUTTONUP)
{
// 右键释放
flag = var; // 设置flag为var
final = Mat::zeros(src.size(), CV_8UC3); // 创建与src同等大小的Mat对象final,并初始化为0
mask = Mat::zeros(src.size(), CV_8UC1); // 创建与src同等大小的mask,并初始化为0
fillPoly(mask, pts, Scalar(255, 255, 255), 8, 0); // 使用多边形填充掩膜
bitwise_and(src, src, final, mask); // 计算src和mask的按位与,得到结果保存在final中
imshow("Mask", mask); // 显示掩膜mask
imshow("Result", final); // 显示最终结果final
imshow("Source", img1); // 显示img1
}
if (event == EVENT_MBUTTONDOWN)
{
// 中键按下
pts.clear(); // 清除点向量
var = 0; // 将var重置为0
drag = 0; // 将drag重置为0
flag = 0; // 将flag重置为0
imshow("Source", src); // 显示源图src
}
}
int main(int argc, char **argv)
{
// 主函数,程序开始的地方
CommandLineParser parser(argc, argv, "{@input | lena.jpg | input image}"); // 命令行解析器
parser.about("This program demonstrates using mouse events\n"); // 关于程序的说明
parser.printMessage(); // 打印消息
cout << "\n\tleft mouse button - set a point to create mask shape\n"
"\tright mouse button - create mask from points\n"
"\tmiddle mouse button - reset\n"; // 提示用户如何使用鼠标按钮
String input_image = parser.get<String>("@input"); // 从命令行获取输入图像
src = imread(samples::findFile(input_image)); // 读取输入图像
if (src.empty())
{
printf("Error opening image: %s\n", input_image.c_str()); // 如果图像为空,打印错误消息
return 0; // 退出程序
}
namedWindow("Source", WINDOW_AUTOSIZE); // 创建一个名为"Source"的窗口
setMouseCallback("Source", mouseHandler, NULL); // 为"Source"窗口设置鼠标事件回调函数
imshow("Source", src); // 显示源图像
waitKey(0); // 等待用户按键
return 0; // 程序正常退出
}
这段C++代码利用OpenCV库和标准输入输出流,实现了一个通过鼠标交互产生掩膜图像的工具。程序读取源图像文件,用户可以通过鼠标左键点击设置掩膜多边形的顶点,右键完成掩膜的创建,中键重置所有操作。最终,程序会展示原图、掩膜图以及掩膜后的结果图。这种功能在图像处理中,尤其是在对象分割(Object Segmentation)与图像编辑中非常有用。