環(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)方式
感悟:
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;
}