opencv 模仿 MFC 小介面(一)
(1) 基本的滑鼠 按鈕操作
轉載學習
https://blog.csdn.net/NCHFGFB/article/details/51516030
https://blog.csdn.net/shyn02588/article/details/44151481
①滑鼠事件
回撥函式
CV_EXPORTS void setMouseCallback(const string& winname, MouseCallback onMouse, void* userdata = 0);
const string& winname,windows視窗名稱,對名為winname的視窗進行滑鼠監控。
MouseCallback onMouse,滑鼠響應處理函式,監聽滑鼠的點選,移動,鬆開,判斷滑鼠的操作型別,並進行響應的函式處理。
void* userdata = 0 滑鼠響應處理函式的ID,與滑鼠相應處理函式相匹配就行,暫時只用到預設為0的情況。
滑鼠響應函式
void on_mouse(int event,int x,int y,int flags,void *ustc)
x,y代表相應位置
滑鼠位於視窗的(x,y)座標位置,視窗左上角預設為原點,向右為x軸,向下為y軸。
event事件:
enum { CV_EVENT_MOUSEMOVE =0, //滑鼠移動 CV_EVENT_LBUTTONDOWN =1, //按下左鍵 CV_EVENT_RBUTTONDOWN =2, //按下右鍵 CV_EVENT_MBUTTONDOWN =3, //按下中鍵 CV_EVENT_LBUTTONUP =4, //放開左鍵 CV_EVENT_RBUTTONUP =5, //放開右鍵 CV_EVENT_MBUTTONUP =6, //放開中鍵 CV_EVENT_LBUTTONDBLCLK =7, //左鍵雙擊 CV_EVENT_RBUTTONDBLCLK =8, //右鍵雙擊 CV_EVENT_MBUTTONDBLCLK =9, //中鍵雙擊 CV_EVENT_MOUSEWHEEL =10, //滾輪滾動 CV_EVENT_MOUSEHWHEEL =11 //橫向滾輪滾動 };
flags,代表滑鼠的拖拽事件
enum
{
CV_EVENT_FLAG_LBUTTON =1, //左鍵拖拽
CV_EVENT_FLAG_RBUTTON =2, //右鍵拖拽
CV_EVENT_FLAG_MBUTTON =4, //中鍵拖拽
CV_EVENT_FLAG_CTRLKEY =8, //按住CTRL拖拽
CV_EVENT_FLAG_SHIFTKEY =16, //按住Shift拖拽
CV_EVENT_FLAG_ALTKEY =32 //按住ALT拖拽
};
例項 簡單畫圖和ROI提取
畫線
#include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <stdio.h> using namespace cv; using namespace std; Mat src(500,500,CV_8UC3,Scalar(255,255,255)); bool down = false; Point prept = Point(0, 0); Point curpt = prept; void on_mouse(int event, int x, int y, int flags, void* ustc) { if (event == CV_EVENT_LBUTTONDOWN) //右鍵按下 { prept = Point(x, y); down = true; } else if (event == CV_EVENT_LBUTTONUP) //右鍵放開 down = false; if (down ==true&&event == CV_EVENT_MOUSEMOVE) //右鍵按下且滑鼠移動 { curpt = cvPoint(x, y); line(src, prept, curpt, Scalar(255, 0, 0), 5); waitKey(5); //可以解決畫圖時卡頓的問題 imshow("src", src); prept = curpt; } else if (event == CV_EVENT_RBUTTONUP) { imwrite("1.jpg",src);//加了用來截圖 } } int main() { cvNamedWindow("src"); cvSetMouseCallback("src", on_mouse, 0); imshow("src", src); cvWaitKey(0); cvDestroyAllWindows(); return 0; }
效果(滑鼠左鍵畫圖,右鍵儲存)
②ROI提取
#include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <stdio.h> using namespace cv; using namespace std; Mat org,dst,img,tmp; void on_mouse(int event,int x,int y,int flags,void *ustc)//event滑鼠事件代號,x,y滑鼠座標,flags拖拽和鍵盤操作的代號 { static Point pre_pt = (-1,-1);//初始座標 static Point cur_pt = (-1,-1);//實時座標 char temp[16]; if (event == CV_EVENT_LBUTTONDOWN)//左鍵按下,讀取初始座標,並在影象上該點處劃圓 { org.copyTo(img);//將原始圖片複製到img中 sprintf(temp,"(%d,%d)",x,y); pre_pt = Point(x,y); putText(img,temp,pre_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255),1,8);//在視窗上顯示座標 circle(img,pre_pt,2,Scalar(255,0,0,0),CV_FILLED,CV_AA,0);//劃圓 imshow("img",img); } else if (event == CV_EVENT_MOUSEMOVE && !(flags & CV_EVENT_FLAG_LBUTTON))//左鍵沒有按下的情況下滑鼠移動的處理函式 { img.copyTo(tmp);//將img複製到臨時影象tmp上,用於顯示實時座標 sprintf(temp,"(%d,%d)",x,y); cur_pt = Point(x,y); putText(tmp,temp,cur_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255));//只是實時顯示滑鼠移動的座標 imshow("img",tmp); } else if (event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON))//左鍵按下時,滑鼠移動,則在影象上劃矩形 { img.copyTo(tmp); sprintf(temp,"(%d,%d)",x,y); cur_pt = Point(x,y); putText(tmp,temp,cur_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255)); rectangle(tmp,pre_pt,cur_pt,Scalar(0,255,0,0),1,8,0);//在臨時影象上實時顯示滑鼠拖動時形成的矩形 imshow("img",tmp); } else if (event == CV_EVENT_LBUTTONUP)//左鍵鬆開,將在影象上劃矩形 { org.copyTo(img); sprintf(temp,"(%d,%d)",x,y); cur_pt = Point(x,y); putText(img,temp,cur_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255)); circle(img,pre_pt,2,Scalar(255,0,0,0),CV_FILLED,CV_AA,0); rectangle(img,pre_pt,cur_pt,Scalar(0,255,0,0),1,8,0);//根據初始點和結束點,將矩形畫到img上 imshow("img",img); img.copyTo(tmp); //擷取矩形包圍的影象,並儲存到dst中 int width = abs(pre_pt.x - cur_pt.x); int height = abs(pre_pt.y - cur_pt.y); if (width == 0 || height == 0) { printf("width == 0 || height == 0"); return; } dst = org(Rect(min(cur_pt.x,pre_pt.x),min(cur_pt.y,pre_pt.y),width,height)); namedWindow("dst"); imshow("dst",dst); waitKey(0); } } void main() { org = imread("1.jpg"); org.copyTo(img); org.copyTo(tmp); namedWindow("img");//定義一個img視窗 setMouseCallback("img",on_mouse,0);//呼叫回撥函式 imshow("img",img); waitKey(); }
(2)按鈕
在影象上顯示文字(draw text)和建立按鈕(draw button)
TrackBar
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <stdio.h>
using namespace cv;
using namespace std;
int contrast,bright;
Mat img,src;
void ContrastAndBright(int,void* )
{
for(int y=0;y<img.rows;y++)
{
cout<<'c'<<endl;
for(int x=0;x<img.cols;x++)
{
for(int c=0;c<3;c++)
{
src.at<Vec3b>(y,x)[c]=saturate_cast<uchar>((contrast*0.01)*(img.at<Vec3b>(y,x)[c])+bright);
}
}
}
imshow("1",src);
}
int main()
{
img=imread("d://zc//tp//lena.jpg");
src=Mat::zeros(img.size(),img.type());
cout<<src.rows<<endl<<endl;
contrast=100;
bright=10;
namedWindow("1",1);
createTrackbar("對比","1",&contrast,200,ContrastAndBright);
createTrackbar("亮度","1",&bright,200,ContrastAndBright);
ContrastAndBright(contrast,0);
ContrastAndBright(bright,0);
while(char(waitKey(1))!='q'){}
return 0;
}
1、drawString()函式封裝了opencv的putText函式和getTextSize函式,使得畫顯示文字更加安全,可靠。
函式介面:
- Rect drawString(Mat img, string text, Point coord, Scalar color, float fontScale = 0.6f, int thickness = 1, int fontFace = FONT_HERSHEY_COMPLEX)
2、text,要顯示的文字資訊
3、coord要顯示文字的座標位置。例如Point(20,20),x,y均為正數,則從偏離左上角高20寬20畫素開始畫文字
Point(20,-10),x為正數,y為負數,則從偏離左20,底10,開始畫文字。對於Point(-20,10),Point(-20,-20)類似。
4、fontScale,字型的縮放大小,當文字資訊過多一行不能顯示,則可以縮小字型
5、thickness,為字型粗細
6、fontFace,字型型別
2、Rect drawButton(Mat img, string text, Point coord, int minWidth = 0)
#include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <stdio.h> using namespace cv; using namespace std; Rect drawString(Mat img, string text, Point coord, Scalar color, float fontScale = 0.6f, int thickness = 1, int fontFace = FONT_HERSHEY_COMPLEX) { //獲取文字大小和基線 int baseline=0; Size textSize = getTextSize(text, fontFace, fontScale, thickness, &baseline); baseline += thickness; // 為左/右或上/下調整校正座標 if (coord.y >= 0) { //影象左上角的文字的左上角的座標,因此按行向下移動 coord.y += textSize.height; } else { //影象左下角的文字的左下角的座標,因此從底部上來 coord.y += img.rows - baseline + 1; } // 如果希望變成右側調整 if (coord.x < 0) { coord.x += img.cols - textSize.width + 1; } // 獲取文字的邊界矩形 Rect boundingRect = Rect(coord.x, coord.y - textSize.height, textSize.width, baseline + textSize.height); // 畫出平滑的文字 putText(img, text, coord, fontFace, fontScale, color, thickness, CV_AA); //讓使用者知道文字的多大,以防他們想安排些事情 return boundingRect; } Rect drawButton(Mat img, string text, Point coord, int minWidth = 0) { int B = 10; Point textCoord = Point(coord.x + B, coord.y + B); // 獲取文字邊界矩形 Rect rcText = drawString(img, text, textCoord, CV_RGB(0,0,0)); // 在文本週圍畫一個填充的矩形 Rect rcButton = Rect(rcText.x - B, rcText.y - B, rcText.width + 2*B, rcText.height + 2*B); // 設定按鈕的最小寬度 if (rcButton.width < minWidth) rcButton.width = minWidth; // 建立一個半透膜的白色矩形 Mat matButton = img(rcButton); matButton += CV_RGB(90, 90, 90); //畫一個非透明的白色邊界 rectangle(img, rcButton, CV_RGB(200,200,200), 1, CV_AA); //使用抗鋸齒,畫一個實際用來顯示的文字 drawString(img, text, textCoord, CV_RGB(10,55,20)); return rcButton; } int main(int argc,char **argv) { Mat img=imread("1.jpg"); const int b=10; string str="123123123"; string b_name1="qqqqqqq"; string b_name2="wwwwwww"; string b_name3="ddddddd"; Rect b_seat1; Rect b_seat2; Rect b_seat3; drawString(img,str,Point(10,-20),Scalar(0,255,0),0.33f,1,3);//在底上20處,右10處,畫文字 b_seat1=drawButton(img,b_name1,Point(b,b),0); b_seat2=drawButton(img,b_name2,Point(b_seat1.x,b_seat1.height+b),b_seat1.width); b_seat3=drawButton(img,b_name3,Point(b_seat2.x,b_seat2.height+b_seat2.y),b_seat1.width); imshow("lena.jpg",img); imwrite("2.jpg",img); waitKey(); }