0
点赞
收藏
分享

微信扫一扫

【opencv】示例-create_mask.cpp 通过鼠标交互产生掩膜图像(黑白图像)

1a70fcbed17098ce40ed9081450f484d.png

61a5e30a47ed6ffd3206fefc7949d7a4.png

/*
* 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)与图像编辑中非常有用。

72f1a5dde270fc4cccca22e018c564a1.png

举报

相关推荐

0 条评论