基於Opencv的簡單影像處理

PamShao發表於2020-12-30

實驗環境

      本實驗均在膝上型電腦完成,電腦的配置如表1所示:

系統

Windows 10 家庭版

處理器

英特爾 Core i5-6200 @ 2.30GHz 雙核

主機板

巨集碁 Zoro_SL

記憶體

16G(金士頓 DDR3 1600MHz)

主硬碟

西數 WDC WD10JPVX-22JC3T0

顯示卡

NVIDIA GeForce 940M(4G)

顯示器

奇美 CMN15C4(15.5英寸)

表1:電腦配置

       本實驗使用Opencv對影像處理,使用MFC對影像顯示,具體介紹如表2所示:

Visual Studio 2019

MFC

Opencv3.3.0

表2:環境介紹

主要原理

       由於OpenCV常用的介面只是單純的開啟影像視窗,相關介面控制元件和工具較少且不美觀,故使用MFC製作介面,而用OpenCV單純做影像處理。此時便需要在MFC中顯示OpenCV所用的圖片,現有以下三種方法可以實現:參考(連結

(1)、巢狀。直接將OpenCV視窗巢狀到MFC的Pictrue Control控制元件中。此方法既能直接顯示圖片,也可直接使用OpenCV的滑鼠按鍵事件,但對於滑鼠滾輪事件只能使用MFC本地的滾輪函式。
(2)、轉換。將OpenCV讀取或處理的圖片轉換格式,使之成為MFC的Pictrue Control控制元件可顯示的圖片格式。

(3)、儲存。將OpenCV讀取或處理的圖片儲存為本地圖片,然後用MFC讀取圖片的方法讀取並顯示。此方法是笨方法,在特定情況下使用,儲存和讀取圖片比較耗時,但無需轉換格式,同樣只能使用MFC的滑鼠事件。

       本實驗中使用的是“轉換”方式將Opencv處理後的影像顯示到MFC的控制元件上,具體程式碼如下:

//顯示到第一個Pic控制元件

void CMFC_DEMODlg::ShowPic_1(Mat input_1)

{

         Mat imagedst; // Mat是在矩陣中儲存圖片的資料結構

         CRect rect;  //定義矩陣類,記錄一個矩形資訊(四個座標點等)

         /* GetDlgItem(IDC_STATIC):獲取控制元件IDC_STATIC控制程式碼

            GetClientRect(&rect):獲取控制程式碼指向控制元件區域的大小

         */

         GetDlgItem(IDC_STATIC)->GetClientRect(&rect);

         //獲取影像大小(長、寬、高等)

         Rect dst(rect.left, rect.top, rect.right, rect.bottom);

         //調整影像大小,含有格式轉換

         resize(input_1, imagedst, cv::Size(rect.Width(), rect.Height()));

         imshow("view", imagedst);

}

配置MFC

在VS中新增MFC的元件即可,如圖1所示:

圖1:MFC配置

Opencv介紹

人類獲取的所有資訊中,視覺資訊佔絕大多數。在大資料時代,影像、視訊等視覺資訊載體也是最主要的資料來源之一,在鐵路工程、公路、機場、醫學、生物學、軍事等領域有著廣泛的應用。由於計算機視覺涉及多個領域的專業知識,以及視覺任務的多樣性和視覺物件的複雜性,這使得計算機是視覺研究具有一定的困難性。

Opencv是跨平臺、跨語言、開源、支援模組多、功能強大、效能高、穩定的機器學習庫和計算機視覺庫,其全稱為Open Source Computer Vision Library。OpenCV是由Intel公司組織開發的,自1999年問世以來,逐漸成為計算機視覺研究領域人員的標準庫工具。

Opencv中包含了大量的模組,highgui、imgproc和core是最基礎的三個模組,介紹了影像處理基礎方法的原理,也是研究Opencv的開始。Highgui模組包含用於在Opencv中輸入、儲存、輸出影像的UI介面;core模組包含了Opencv一些基本運算函式和最核心的資料結構;imgproc模組包含了Opencv中影像處理的基本方法,包括影像的平滑、對比度增強、形態學處理、閾值分割、邊緣檢測幾何影像的檢測和擬合、傅立葉變換、頻率域濾波等。Opencv中也包含了更高層次層次餓的影像處理方法的相關模組,包括用於機器學習的ml模組,如神經網路、隨機森林、支援向量機等;實現對目標檢測功能的objdetect模組,如基於HOG的汽車、行人的檢測,基於LBP、Haar特徵的人臉等目標的檢測;針對視訊處理的video模組,如執行物體的跟蹤、背景建模、前景檢測等。由此可見,在計算機視覺研究領域的所有方向,Opencv幾乎都可以實現。Opencv提供的標準統一的函式和資料結構的混合能夠更好地檢測、分割是識別出物體的特徵,這些優勢都為影像處理研究奠定了良好的基礎。

Opencv在VS中配置

       首先,先下載Opencv,進行安裝;然後配置電腦系統變數;最後設定專案屬性,主要分為Debug和Release兩種除錯方法,分別設定專案的通用屬性:VC++目錄—包含目錄和庫目錄和連結器:輸入-新增依賴項,具體如圖2、圖3所示:

 

圖2:VC++配置

 

圖3:連結器配置

功能介紹

       效果分為主頁面,即一個視窗,可以顯示影像和處理後的影像,最上面有三個選單裡面有實現主要的功能,具體的如圖4、圖5、圖6、圖7所示:

圖4:主介面

 

圖5:檔案操作

 

圖6:影像處理

 

圖7:實時影像處理

灰度化和二值化

(1)灰度化

影像灰度化核心思想是 R = G = B ,這個值也叫灰度值

主要程式碼如下,執行結果如圖8所示:

//轉換成灰度影像

Mat CMFC_DEMODlg::ImageGray1()

{

         Mat huidu, out2;

         cvtColor(image, huidu, COLOR_BGR2GRAY);

         return huidu;

}

 

圖8:灰度化

(2)二值化

從灰度影像中獲取二進位制影像,濾除大小或太大的畫素值,k為閾值

主要程式碼如下,執行結果如圖9所示:

//二值化函式

void CMFC_DEMODlg::ImageEZH1()

{

         Mat huidu;

         newform2  Dl;

         if (Dl.DoModal() == IDOK) {

                  int k = Dl.canshu;

                  cvtColor(image, huidu, COLOR_BGR2GRAY);

                  threshold(huidu, out, k, 255, CV_THRESH_BINARY);

                  ShowPic_2(out);

         }

}

 

圖9:二值化

灰度變換

灰度變換是影像增強的一種重要手段,用於改善影像顯示效果,屬於空間域處理方法,它可以使影像動態範圍加大,使影像對比度擴充套件,影像更加清晰,特徵更加明顯。灰度變換其實質就是按一定的規則修改影像每一個畫素的灰度,從而改變影像的灰度範圍。常見的灰度變換影像反轉,對數變換和伽馬變換等。其具體分類如下圖10所示:

 

圖10:灰度變換分類

(1)均值濾波

均值濾波是對是對訊號進行區域性平均, 以平均值來代表該畫素點的灰度值

主要程式碼如下:

//均值濾波

void CMFC_DEMODlg::ImageJZ1()

{

         newform6  D;

         if (D.DoModal() == IDOK) {

                  int k = D.n;

                  //Mat junzhi,out2;

                  out.create(image.size(), image.type());

                  blur(image, out, Size(k, k));

                  ShowPic_2(out);

         }

}

(2)高斯濾波

由於高斯函式的傅立葉變換仍是高斯函式, 因此高斯函式能構成一個在頻域具有平滑效能的低通濾波器。可以通過在頻域做乘積來實現高斯濾波

主要程式碼如下:

//高斯濾波

void CMFC_DEMODlg::ImageGS1()

{

         newform6  D;

         if (D.DoModal() == IDOK) {

                  int k = D.n;

                  GaussianBlur(image, out, Size(k,k), 0, 0);

                  ShowPic_2(out);

         }

}

(3)拉普拉斯濾波

由於拉普拉斯是一種微分運算元,它的應用可增強影像中灰度突變的區域,減弱灰度的緩慢變化區域。

主要程式碼如下:

//拉普拉斯

Mat CMFC_DEMODlg::ImageLPLS1()

{

         Mat lpls;

         Mat K = (Mat_<double>(3, 3) << -1, -1, -1, -1, 9, -1, -1, -1, -1);

         filter2D(image, lpls, image.depth(), K);

         return lpls;

}

邊緣檢測

梯度:畫素灰度值變化的速度

canny邊緣檢測:目的是尋找一個最優的邊緣,執行影像如圖11所示:

最優的邊緣定義為:

1.好的檢測--演算法能夠儘可能的標識出影像中的實際邊緣

2.好的定位--標識出的邊緣要與實際影像中的實際邊緣儘可能接近

3.最小響應--影像中的邊緣只能標識一次,並和可能存在存在的影像噪聲不應該標識為邊緣

步驟:

1、高斯濾波:去燥(根據待濾波的畫素點極其鄰域點的灰度值按照高斯公式生成引數規則進行加權平均,這樣可以有效去除理想影像中疊加的高頻噪聲)

2、計算梯度影像與角度影像

slobel運算元:

根據畫素點上下,左右鄰點灰度加權差,再邊緣處達到極值這一現象檢測邊緣,對噪聲具有平滑作用,但是邊緣定位精度不夠高,當對精度要求不是很高時,是一種常用的邊緣檢測演算法

 

圖11:canny邊緣檢測

直方圖

影像的直方圖:指具有某種灰度級的畫素的個數,反應影像中每種灰度出現的頻率

直方圖均衡化:是間接增減對比度的方法之一,主要把給定影像的直方圖分佈改變為“均勻”分佈。原理是:對個數多的灰度級進行展寬,對個數少的灰度級進行縮減,把原始影像的灰度直方圖從比較集中的某灰度區間在全部灰度範圍內的均勻分佈,從而達到清晰影像目的

主要流程如圖12所示,顯示如圖13所示:

 

圖12:直方圖流程圖

 

圖13:直方圖顯示

混沌加密

混沌:混沌是一種複雜的動力學行為,不是簡單的無序,它沒有明顯的週期和對稱,其內部結構豐富是非線性系統的一種新形式。

Li- Yorke定義:

對於閉區間J,R,設連續對映J—J,如果存在不可數集S J,滿足:

1、S不含週期點

2、對任意的兩個點p,q∈S(p≠q)

3、對任意p∈S及週期點q∈J,且p≠q

稱F對映在S上是混沌的

超混沌:一般混沌系統是一種典型的三維現象,其特點是隻有一個正的李雅普諾夫指數,其運動軌跡只在某個方向上產生不穩定性。在自然界中普遍存在高維非線性系統,它們有不止一個正的李雅普諾夫指數,其運動軌跡在兩個以上的方向出現指數型的發散軌跡,這種混沌態被稱為超混沌

超混沌加密:對稱加密,處理速度和金鑰長度無關,執行顯示如圖14所示:

 

圖14:混沌加密

開啟攝像頭

使用OPENCV開啟攝像頭,並顯示到指定控制元件中:

主要程式碼如下,執行結果如圖15所示:

// 實時視訊處理

static void refineSegments(const Mat& img, Mat& mask, Mat& dst);

void CMFC_DEMODlg::VIDEO_deal_fun()

{

         bool update_bg_model = true;

         Mat tmp_frame, bgmask, out_frame, foreground, bw, gray;;

         cap.open(0);

         if (!cap.isOpened())

         {

                  AfxMessageBox("開啟攝像頭失敗!");

                  exit(-1);

         }

         cap >> tmp_frame;

         if (tmp_frame.empty())

         {

                  AfxMessageBox("讀取幀失敗!");

                  exit(-1);

         }

         Ptr<BackgroundSubtractorMOG2> bgsubtractor = createBackgroundSubtractorMOG2();

         bgsubtractor->setVarThreshold(10);

         for (;;)

         {

                  cap >> tmp_frame;

                  if (tmp_frame.empty())

                          break;

                  bgsubtractor->apply(tmp_frame, bgmask, update_bg_model ? -1 : 0);

                  ShowPic_1(tmp_frame);

}

}

 

圖15:開啟攝像頭

視訊灰度化和模糊化和邊緣檢測

(1)灰度化

主要程式碼如下:

//灰度化

cvtColor(tmp_frame, out_frame, CV_BGR2GRAY);

ShowPic_2(out_frame);

(2)模糊化

主要程式碼如下:

//模糊化

blur(tmp_frame, out_frame, Size(7, 7));//模糊化

ShowPic_2(out_frame);

(3)邊緣檢測

主要程式碼如下:

//邊緣檢測

GaussianBlur(tmp_frame, out_frame, cvSize(3,3), 2, 2, BORDER_DEFAULT);//高斯平滑

Canny(tmp_frame, out_frame,20,100,3);

ShowPic_2(out_frame);

清除背景分割

主要程式碼如下,執行結果如圖16所示:

來源:連結

static void refineSegments(const Mat& img, Mat& mask, Mat& dst)

{

         int niters = 3;

         vector<vector<Point> > contours;

         vector<Vec4i> hierarchy;

         Mat temp;

         dilate(mask, temp, Mat(), Point(-1, -1), niters);  // 膨脹:求核區域畫素最大值,可以填補凹洞

         erode(temp, temp, Mat(), Point(-1, -1), niters * 2); // 腐蝕:求核區域最小值,能消除凸起

         dilate(temp, temp, Mat(), Point(-1, -1), niters);  // 膨脹:求核區域畫素最大值,可以填補凹洞

         findContours(temp, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);  // 輪廓提取

         dst = Mat::zeros(img.size(), CV_8UC3);

         if (contours.size() == 0)

                  return;

         int idx = 0, largestComp = 0;

         double maxArea = 0;

         for (; idx >= 0; idx = hierarchy[idx][0])

         {

                  const vector<Point>& c = contours[idx];

                  double area = fabs(contourArea(Mat(c)));  // 求絕對值

                  if (area > maxArea)

                  {

                          maxArea = area;

                          largestComp = idx;

                  }

         }

         Scalar color(0, 0, 255); //將影像設定成單一灰度和顏色

         drawContours(dst, contours, largestComp, color, FILLED, LINE_8, hierarchy); // 輪廓填充

}

 

圖16:清除背景分割

存在的問題

1、主視窗關閉不掉,內部有退出按鈕,但只能強行關閉視窗,需要手動殺死程式

2、對於實時影像處理的功能,只用了簡單地 if-else 進行切換,不存在實用價值,且演示順序只能為:灰度化、模糊化、邊緣檢測、清除背景分割。

3、opencv呼叫攝像頭是存在諸多問題,以及始終實現不了載入視訊,我太菜!

4、程式碼部分借鑑網上,如有問題,請告知

相關文章