OpenCV編寫截圖程序_&&_鼠標(biāo)事件

環(huán)境:OpenCV3.2.0稽屏,VS2013卵贱,Windows7。
語(yǔ)言:C++
我需要截取樣本作機(jī)器學(xué)習(xí)數(shù)據(jù)的訓(xùn)練懂缕,不但要能方便截圖允跑,而且截取的圖片必須是固定的尺寸,這樣的軟件不好找搪柑,于是我便打算自己編寫一個(gè)聋丝。
效果如下:可以看到,圖片中所有的矩形框都是1:1的正方形工碾!也就是說(shuō)弱睦,我的截圖程序,能把截圖時(shí)鼠標(biāo)拖動(dòng)的矩形自動(dòng)變?yōu)檎叫我形梗易钪匾氖敲颗瘢詣?dòng)變化的矩形框尺寸不會(huì)超出圖像尺寸。
這個(gè)程序有如下3個(gè)難點(diǎn):鼠標(biāo)事件的變化端圈; 自動(dòng)變化的尺寸不超出圖像尺寸焦读;需要考慮到鼠標(biāo)從上往下、從下往上舱权、從左向右矗晃、從右向左 等多種拖動(dòng)方式


圖片.png

感悟:
1、程序一定要考慮到圖像的尺寸宴倍,不能超出圖像的尺寸张症,否則程序就會(huì)出錯(cuò)。 尺寸可以把 長(zhǎng)(cols)鸵贬、 寬(rows)分開(kāi)考慮俗他,這兩個(gè)值是獨(dú)立的,如果把他們綜合在一起思考容易把自己搞糊涂阔逼。

代碼如下:

#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++創(chuàng)建文件夾頭文件
//#include <stdlib.h> //srand()和rand()函數(shù)  
//#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){  //按下鼠標(biāo)事件
        g_MouseDown_flag = true;  //方框標(biāo)志位置為真
        g_startPoint = Point(x, y);  //記錄下方框的起始位置
    }
    else if (CV_EVENT_MOUSEMOVE == event && g_MouseDown_flag){ //拖動(dòng)鼠標(biāo)事件

        //  rectangle(Mat& img,   Point pt1,   Point pt2,   const Scalar& color,   int thickness=1,   int lineType=8,   int shift=0)
        //  img 圖像;      
        //  pt1 矩形的一個(gè)頂點(diǎn);           
        //  pt2 矩形對(duì)角線上的另一個(gè)頂點(diǎn);     
        //  color 線條顏色(RGB) 或亮度(灰度圖像 )(grayscale image)兆衅。
        //  thickness 組成矩形的線條的粗細(xì)程度,取負(fù)值時(shí)(如 CV_FILLED)函數(shù)繪制填充了色彩的矩形嗜浮。
        //  line_type 線條的類型,見(jiàn)cvLine的描述;              
        //  shift 坐標(biāo)點(diǎn)的小數(shù)點(diǎn)位數(shù)羡亩。

        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上畫鼠標(biāo)拖動(dòng)時(shí)的矩形
        //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); //把復(fù)制的圖像顯示出來(lái)
    }
    else if (CV_EVENT_LBUTTONUP == event /* && g_startPoint != Point(x, y)*/){ //抬起鼠標(biāo)事件

        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);

        //取邊長(zhǎng)大值
        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; //得到各自邊長(zhǎng)的正負(fù)
        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); //保存矩形框中的圖片:把起始點(diǎn)和結(jié)束點(diǎn)的坐標(biāo)賦給感興趣區(qū)域,并把感興趣區(qū)域賦給g_img_Cut
    //  imshow("sub image", g_img_Cut);
        
        srand(time(NULL)); //設(shè)置隨機(jī)數(shù)種子
        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; //清零鼠標(biāo)按下標(biāo)志
    }
}

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

    if (_mkdir("截取后的圖片")==0){
        cout << "保存文件夾創(chuàng)建成功" << endl;
    }

    P = 2; //圖像尺寸除以4危融,以減小圖片尺寸

    g_img_src = imread("1.jpg"); //讀取圖片
    if (!g_img_src.data){
        cout << "圖片讀取失敗畏铆,請(qǐng)檢查圖片的名稱或路徑" << 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 << "讀取文件錯(cuò)誤" << endl;
        return EXIT_FAILURE; //C語(yǔ)言中執(zhí)行失敗返回的值
    }

    namedWindow(g_window_name, 0);//設(shè)置窗口屬性 //CV_WINDOW_NORMAL  //CV_WINDOW_KEEPRATIO

    //                 窗口的名字        鼠標(biāo)事件發(fā)生時(shí)的函數(shù)指針    默認(rèn)值為0
    setMouseCallback(g_window_name, onMouse, 0);  //開(kāi)啟鼠標(biāo)事件

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

        int c = waitKey(0);
        if ((c & 255) == 27){ // 按下Esc鍵
            destroyAllWindows(); //關(guān)閉所有窗口
            cout << "一張圖片截圖完畢" << endl;
            break;
        }
    }


    return EXIT_SUCCESS;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市吉殃,隨后出現(xiàn)的幾起案子辞居,更是在濱河造成了極大的恐慌,老刑警劉巖蛋勺,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件速侈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡迫卢,警方通過(guò)查閱死者的電腦和手機(jī)倚搬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)乾蛤,“玉大人每界,你說(shuō)我怎么就攤上這事〖衣簦” “怎么了眨层?”我有些...
    開(kāi)封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)上荡。 經(jīng)常有香客問(wèn)我趴樱,道長(zhǎng)馒闷,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任叁征,我火速辦了婚禮纳账,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捺疼。我一直安慰自己疏虫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布啤呼。 她就那樣靜靜地躺著卧秘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪官扣。 梳的紋絲不亂的頭發(fā)上翅敌,一...
    開(kāi)封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音惕蹄,去河邊找鬼哼御。 笑死,一個(gè)胖子當(dāng)著我的面吹牛焊唬,可吹牛的內(nèi)容都是我干的恋昼。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼赶促,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼液肌!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鸥滨,我...
    開(kāi)封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嗦哆,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后婿滓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體老速,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年凸主,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了橘券。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡卿吐,死狀恐怖旁舰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嗡官,我是刑警寧澤箭窜,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站衍腥,受9級(jí)特大地震影響磺樱,放射性物質(zhì)發(fā)生泄漏纳猫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一竹捉、第九天 我趴在偏房一處隱蔽的房頂上張望芜辕。 院中可真熱鬧,春花似錦活孩、人聲如沸物遇。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至乃沙,卻和暖如春起趾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背警儒。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工训裆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蜀铲。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓边琉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親记劝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子变姨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容