1. 程式人生 > >opencv 模仿 MFC 小介面(一)

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函式,使得畫顯示文字更加安全,可靠。

函式介面:

  1. Rect drawString(Mat img, string text, Point coord, Scalar color, float fontScale = 0.6f, int thickness = 1, int fontFace = FONT_HERSHEY_COMPLEX)  
1、img,畫布

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