OpenCV编写截图程序_&&_鼠标事件

环境:OpenCV3.2.0,VS2013,Windows7。
语言:C++
我需要截取样本作机器学习数据的训练,不但要能方便截图,而且截取的图片必须是固定的尺寸,这样的软件不好找,于是我便打算自己编写一个。
效果如下:可以看到,图片中所有的矩形框都是1:1的正方形!也就是说,我的截图程序,能把截图时鼠标拖动的矩形自动变为正方形,而且最重要的是,自动变化的矩形框尺寸不会超出图像尺寸。
这个程序有如下3个难点:鼠标事件的变化; 自动变化的尺寸不超出图像尺寸;需要考虑到鼠标从上往下、从下往上、从左向右、从右向左 等多种拖动方式


图片.png

感悟:
1、程序一定要考虑到图像的尺寸,不能超出图像的尺寸,否则程序就会出错。 尺寸可以把 长(cols)、 宽(rows)分开考虑,这两个值是独立的,如果把他们综合在一起思考容易把自己搞糊涂。

代码如下:

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
#include <ctime>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include <direct.h>  //windows下C++创建文件夹头文件
//#include <stdlib.h> //srand()和rand()函数  
//#include <time.h>

using namespace cv;
using namespace std;


// global variable
static Mat g_img_src;
static Mat g_img_dst;
static Mat g_imgMouseMove;
static Mat g_img_Cut;
static bool g_MouseDown_flag = false;
static Point g_startPoint;
static string g_window_name = "image";

int P = 0; //图像缩放比例


static void onMouse(int event, int x, int y, int, void*)
{
    if (CV_EVENT_LBUTTONDOWN == event){  //按下鼠标事件
        g_MouseDown_flag = true;  //方框标志位置为真
        g_startPoint = Point(x, y);  //记录下方框的起始位置
    }
    else if (CV_EVENT_MOUSEMOVE == event && g_MouseDown_flag){ //拖动鼠标事件

        //  rectangle(Mat& img,   Point pt1,   Point pt2,   const Scalar& color,   int thickness=1,   int lineType=8,   int shift=0)
        //  img 图像;      
        //  pt1 矩形的一个顶点;           
        //  pt2 矩形对角线上的另一个顶点;     
        //  color 线条颜色(RGB) 或亮度(灰度图像 )(grayscale image)。
        //  thickness 组成矩形的线条的粗细程度,取负值时(如 CV_FILLED)函数绘制填充了色彩的矩形。
        //  line_type 线条的类型,见cvLine的描述;              
        //  shift 坐标点的小数点位数。

        x = x <= (g_img_src.cols-1) ? x : (g_img_src.cols-1);
        y = y <= (g_img_src.rows-1) ? y : (g_img_src.rows-1);
        x = x >= 0 ? x : 0;
        y = y >= 0 ? y : 0;

        g_img_dst.copyTo(g_imgMouseMove);

        rectangle(g_imgMouseMove, g_startPoint, Point(x, y), Scalar_<uchar>::all(20), 3, 8); //在g_imgMouseMove上画鼠标拖动时的矩形
        //rectangle(g_img_src, g_startPoint, Point(x, y), Scalar_<uchar>::all(20), 5, 8);

        //  rectangle(g_img_dst, g_startPoint, Point(x, y), Scalar(g_rng.uniform(100, 255), g_rng.uniform(100, 255), g_rng.uniform(100, 255)));
        //  rectangle(g_img_dst, g_startPoint, Point(x, y), Scalar(0, 255, 0));
        imshow(g_window_name, g_imgMouseMove); //把复制的图像显示出来
    }
    else if (CV_EVENT_LBUTTONUP == event /* && g_startPoint != Point(x, y)*/){ //抬起鼠标事件

        x = x <= (g_img_src.cols - 1) ? x : (g_img_src.cols - 1);
        y = y <= (g_img_src.rows - 1) ? y : (g_img_src.rows - 1);
        x = x >= 0 ? x : 0;
        y = y >= 0 ? y : 0;

        Point centerPoint = Point((x + g_startPoint.x) / 2, (y + g_startPoint.y)/2);

        //取边长大值
        int length = abs(x - g_startPoint.x) > abs(y - g_startPoint.y) ? abs(x - g_startPoint.x) : abs(y - g_startPoint.y);

        int length_x = (x - g_startPoint.x) / abs(x - g_startPoint.x) * length; //得到各自边长的正负
        int length_y = (y - g_startPoint.y) / abs(y - g_startPoint.y) * length;

        g_startPoint.x = centerPoint.x - length_x / 2;
        g_startPoint.y = centerPoint.y - length_y / 2;

        if (g_startPoint.x + length_x > g_img_dst.cols){
            g_startPoint.x = g_img_dst.cols - length;// abs(length_x);
        }
        if (g_startPoint.x + length_x < 0){
            g_startPoint.x = length;
        }

        if (g_startPoint.y + length_y > g_img_dst.rows){
            g_startPoint.y = g_img_dst.rows - length;// abs(length_y);
        }
        if (g_startPoint.y + length_y < 0){
            g_startPoint.y = length;
        }

        x = g_startPoint.x + length_x;
        y = g_startPoint.y + length_y;

        cout << length_x << "   " << length_y << endl;
        rectangle(g_img_dst, g_startPoint, Point(x, y), Scalar_<uchar>::all(20), 3, 8); //在img_dst上画矩形框
                        
        Point cutPoint;

        g_img_src(Rect(g_startPoint*P, Point(x*P, y*P))).copyTo(g_img_Cut); //保存矩形框中的图片:把起始点和结束点的坐标赋给感兴趣区域,并把感兴趣区域赋给g_img_Cut
    //  imshow("sub image", g_img_Cut);
        
        srand(time(NULL)); //设置随机数种子
        imwrite("截取后的图片\\"+to_string(rand() % 100) + to_string(rand() % 300) + to_string(rand() % 20) + to_string(rand() % 30) + ".jpg", g_img_Cut);
        //

        g_MouseDown_flag = false; //清零鼠标按下标志
    }
}

int main(int argc, char** argv){

    if (_mkdir("截取后的图片")==0){
        cout << "保存文件夹创建成功" << endl;
    }

    P = 2; //图像尺寸除以4,以减小图片尺寸

    g_img_src = imread("1.jpg"); //读取图片
    if (!g_img_src.data){
        cout << "图片读取失败,请检查图片的名称或路径" << endl;
        return 0;
    }

    g_img_src.copyTo(g_img_dst);

    resize(g_img_dst, g_img_dst, Size(g_img_dst.cols / P, g_img_dst.rows / P));

    if (g_img_src.empty()){
        cerr << "读取文件错误" << endl;
        return EXIT_FAILURE; //C语言中执行失败返回的值
    }

    namedWindow(g_window_name, 0);//设置窗口属性 //CV_WINDOW_NORMAL  //CV_WINDOW_KEEPRATIO

    //                 窗口的名字        鼠标事件发生时的函数指针    默认值为0
    setMouseCallback(g_window_name, onMouse, 0);  //开启鼠标事件

    while (true){
        imshow(g_window_name, g_img_dst);

        int c = waitKey(0);
        if ((c & 255) == 27){ // 按下Esc键
            destroyAllWindows(); //关闭所有窗口
            cout << "一张图片截图完毕" << endl;
            break;
        }
    }


    return EXIT_SUCCESS;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容