OpenCV 快速指南



OpenCV - 概述

OpenCV是一個跨平臺庫,我們可以用它來開發即時的計算機視覺應用程式。它主要關注影像處理、影片捕獲和分析,包括人臉檢測和物體檢測等功能。

讓我們從定義“計算機視覺”這個術語開始本章節。

計算機視覺

計算機視覺可以定義為一門學科,它解釋如何根據場景中存在的結構屬性,從其二維影像重建、解釋和理解三維場景。它處理使用計算機軟體和硬體模擬和複製人類視覺。

計算機視覺與以下領域有很大的重疊:

  • 影像處理 - 它專注於影像操作。

  • 模式識別 - 它解釋各種分類模式的技術。

  • 攝影測量學 - 它關注從影像中獲取精確測量。

計算機視覺與影像處理

影像處理處理影像到影像的轉換。影像處理的輸入和輸出都是影像。

計算機視覺是從影像中構建對物理物件的明確、有意義的描述。計算機視覺的輸出是對三維場景中結構的描述或解釋。

計算機視覺的應用

這裡列出了一些計算機視覺大量使用的主要領域。

機器人應用

  • 定位 - 自動確定機器人位置

  • 導航

  • 避障

  • 裝配(銷孔、焊接、噴漆)

  • 操作(例如 PUMA 機器人機械手)

  • 人機互動 (HRI) - 智慧機器人與人互動和服務人

醫學應用

  • 分類和檢測(例如病灶或細胞分類和腫瘤檢測)
  • 二維/三維分割
  • 三維人體器官重建(MRI 或超聲波)
  • 視覺引導機器人手術

工業自動化應用

  • 工業檢測(缺陷檢測)
  • 裝配
  • 條形碼和包裝標籤閱讀
  • 物體分揀
  • 文件理解(例如 OCR)

安全應用

  • 生物識別技術(虹膜、指紋、人臉識別)

  • 監控 - 檢測某些可疑活動或行為

交通應用

  • 自動駕駛車輛
  • 安全,例如駕駛員警覺性監控

OpenCV 庫的功能

使用 OpenCV 庫,您可以:

  • 讀取和寫入影像

  • 捕獲和儲存影片

  • 處理影像(濾波、變換)

  • 執行特徵檢測

  • 檢測影片或影像中特定物件,例如人臉、眼睛、汽車。

  • 分析影片,即估計影片中的運動,減去背景,並跟蹤影片中的物件。

OpenCV 最初是用 C++ 開發的。除此之外,還提供了 Python 和 Java 繫結。OpenCV 執行在各種作業系統上,例如 Windows、Linux、OSx、FreeBSD、Net BSD、Open BSD 等。

本教程使用 Java 繫結解釋 OpenCV 的概念和示例。

OpenCV 庫模組

以下是 OpenCV 庫的主要庫模組。

核心功能

此模組涵蓋用於構建 OpenCV 應用程式的基本資料結構,例如 Scalar、Point、Range 等。除此之外,它還包括用於儲存影像的多維陣列Mat。在 OpenCV 的 Java 庫中,此模組作為名為org.opencv.core的包包含。

影像處理

此模組涵蓋各種影像處理操作,例如影像濾波、幾何影像變換、顏色空間轉換、直方圖等。在 OpenCV 的 Java 庫中,此模組作為名為org.opencv.imgproc的包包含。

影片

此模組涵蓋影片分析概念,例如運動估計、背景減法和物件跟蹤。在 OpenCV 的 Java 庫中,此模組作為名為org.opencv.video的包包含。

影片 I/O

此模組解釋使用 OpenCV 庫進行影片捕獲和影片編解碼。在 OpenCV 的 Java 庫中,此模組作為名為org.opencv.videoio的包包含。

calib3d

此模組包括關於基本多檢視幾何演算法、單目和立體相機標定、物體姿態估計、立體對應和三維重建元素的演算法。在 OpenCV 的 Java 庫中,此模組作為名為org.opencv.calib3d的包包含。

features2d

此模組包括特徵檢測和描述的概念。在 OpenCV 的 Java 庫中,此模組作為名為org.opencv.features2d的包包含。

Objdetect

此模組包括檢測物件和預定義類的例項,例如人臉、眼睛、杯子、人、汽車等。在 OpenCV 的 Java 庫中,此模組作為名為org.opencv.objdetect的包包含。

Highgui

這是一個易於使用的介面,具有簡單的 UI 功能。在 OpenCV 的 Java 庫中,此模組的功能包含在兩個不同的包中,即org.opencv.imgcodecsorg.opencv.videoio

OpenCV 簡史

OpenCV 最初是英特爾的一個研究專案,旨在輔助 CPU 密集型應用。它於 1999 年正式啟動。

  • 2006 年,其第一個主要版本 OpenCV 1.0 釋出。
  • 2009 年 10 月,第二個主要版本 OpenCV 2 釋出。
  • 2012 年 8 月,OpenCV 被非營利組織 OpenCV.org 接管。

OpenCV - 環境配置

在本節中,您將學習如何在您的系統中安裝 OpenCV 並設定其環境。

安裝 OpenCV

首先,您需要將 OpenCV 下載到您的系統。請按照以下步驟操作。

步驟 1 - 點選以下連結開啟OpenCV的主頁:http://opencv.org/ 點選後,您將看到如下所示的主頁。

OpenCV HomePage

步驟 2 - 現在,點選上面截圖中突出顯示的下載連結。點選後,您將被定向到 OpenCV 的下載頁面。

OpenCV Downloads Page

步驟 3 - 點選上面截圖中突出顯示的連結後,將下載一個名為opencv-3.1.0.exe的檔案。解壓此檔案,在您的系統中生成一個名為opencv的資料夾,如下面的截圖所示。

OpenCV Downloaded

步驟 4 - 開啟資料夾OpenCVbuildjava。在這裡,您將找到名為opencv-310.jar的 OpenCV jar 檔案。將此檔案儲存到單獨的資料夾中以便日後使用。

OpenCV Jar File

Eclipse 安裝

下載所需的 JAR 檔案後,您必須將這些 JAR 檔案嵌入到您的 Eclipse 環境中。您可以透過為這些 JAR 檔案設定構建路徑並使用pom.xml來實現。

設定構建路徑

以下是如何在 Eclipse 中設定 OpenCV 的步驟:

步驟 1 - 確保您已經在系統中安裝了 Eclipse。如果沒有,請下載並在您的系統中安裝 Eclipse。

步驟 2 - 開啟 Eclipse,點選檔案,新建,並開啟一個新專案,如下面的截圖所示。

Open Eclipse

步驟 3 - 選擇專案後,您將獲得新建專案嚮導。在此嚮導中,選擇 Java 專案,然後點選下一步按鈕繼續,如下面的截圖所示。

Select Project

步驟 4 - 繼續前進,您將被定向到新建 Java 專案嚮導。建立一個新專案並點選下一步,如下面的截圖所示。

New Java Project wizard

步驟 5 - 建立新專案後,右鍵單擊它。選擇構建路徑並點選配置構建路徑…,如下面的截圖所示。

Select Build Path

步驟 6 - 點選構建路徑選項後,您將被定向到Java 構建路徑向導。點選新增外部 JARs按鈕,如下面的截圖所示。

Click Build Path

步驟 7 - 選擇您儲存檔案opencv-310.jar的路徑。

步驟 8 - 點選上面截圖中的開啟按鈕,這些檔案將新增到您的庫中。

Click Open Button

步驟 9 - 點選確定,您將成功地將所需的 JAR 檔案新增到當前專案中,您可以透過展開“引用庫”來驗證這些已新增的庫。

Click OK

設定原生庫的路徑

除了 JAR 檔案外,您還需要為 OpenCV 的原生庫(DLL 檔案)設定路徑。

DLL 檔案的位置 - 開啟OpenCV的安裝資料夾,然後轉到子資料夾buildjava。在這裡,您將找到包含 OpenCV dll 檔案的兩個資料夾x64(64 位)和x86(32 位)。

DLL Files Location

開啟適合您作業系統的相應資料夾,然後您可以看到dll檔案,如下面的截圖所示。

Open Folder

現在,請按照以下步驟設定此檔案的路徑:

步驟 1 - 再次開啟 JavaBuildPath 視窗。在這裡,您可以看到已新增的 JAR 檔案和JRE 系統庫

JRE System Library

步驟 2 - 展開後,您將獲得系統庫和原生庫位置,如下面的截圖中突出顯示的那樣。

Native Library Location

步驟 3 − 雙擊原生庫位置。在這裡,您可以看到如下所示的原生庫資料夾配置視窗

Double-click on Native library location

在此處,單擊外部資料夾…按鈕,然後選擇系統中dll檔案的位置。

OpenCV - 影像儲存

為了捕獲影像,我們使用相機和掃描器等裝置。這些裝置記錄影像的數值(例如:畫素值)。OpenCV 是一個處理數字影像的庫,因此我們需要儲存這些影像以便進行處理。

OpenCV 庫的Mat類用於儲存影像的值。它表示一個 n 維陣列,用於儲存灰度或彩色影像、體素體積、向量場、點雲、張量、直方圖等影像資料。

此類包含兩個資料部分:頭部指標

  • 頭部 − 包含諸如大小、儲存方法和矩陣地址(大小恆定)等資訊。

  • 指標 − 儲存影像的畫素值(持續變化)。

Mat 類

OpenCV Java 庫在org.opencv.core包中提供具有相同名稱(Mat)的此類。

建構函式

OpenCV Java 庫的 Mat 類具有各種建構函式,可以使用這些建構函式來構造 Mat 物件。

序號 建構函式和描述
1

Mat()

在大多數情況下,這是沒有引數的預設建構函式。我們使用此建構函式來建立一個空矩陣,並將其傳遞給其他 OpenCV 方法。

2

Mat(int rows, int cols, int type)

此建構函式接受三個整型引數,分別表示二維陣列中的行數和列數以及陣列的型別(用於儲存資料)。

3

Mat(int rows, int cols, int type, Scalar s)

除了前一個建構函式的引數外,此建構函式還額外接受 Scalar 類的一個物件作為引數。

4

Mat(Size size, int type)

此建構函式接受兩個引數,一個表示矩陣大小的物件和一個表示用於儲存資料的陣列型別的整數。

5

Mat(Size size, int type, Scalar s)

除了前一個建構函式的引數外,此建構函式還額外接受 Scalar 類的一個物件作為引數。

6

Mat(long addr)

7

Mat(Mat m, Range rowRange)

此建構函式接受另一個矩陣的物件和 Range 類的一個物件,該物件表示要用於建立新矩陣的行範圍。

8

Mat(Mat m, Range rowRange, Range colRange)

除了前一個建構函式的引數外,此建構函式還額外接受 Range 類的一個物件,表示列範圍。

9

Mat(Mat m, Rect roi)

此建構函式接受兩個物件,一個表示另一個矩陣,另一個表示 (Region Of Interest)。

注意

  • 陣列型別。使用 CV_8UC1、…、CV_64FC4 建立 1-4 通道矩陣,或使用 CV_8UC(n)、…、CV_64FC(n) 建立多通道(最多 CV_CN_MAX 通道)矩陣。

  • 矩陣的型別由org.opencv.core包中CvType類的各個欄位表示。

方法和描述

以下是 Mat 類提供的一些方法。

序號 方法和描述
1

Mat col(int x)

此方法接受一個整數引數,表示列的索引,並檢索並返回該列。

2

Mat row(int y)

此方法接受一個整數引數,表示行的索引,並檢索並返回該行。

3

int cols()

此方法返回矩陣中的列數。

4

int rows()

此方法返回矩陣中的行數。

5

Mat setTo(Mat value)

此方法接受Mat型別的物件,並將陣列元素設定為指定的值。

6

Mat setTo(Scalar s)

此方法接受Scalar型別的物件,並將陣列元素設定為指定的值。

建立和顯示矩陣

在本節中,我們將討論我們的第一個 OpenCV 示例。我們將看到如何建立和顯示一個簡單的 OpenCV 矩陣。

以下是使用 OpenCV 建立和顯示矩陣的步驟。

步驟 1:載入 OpenCV 原生庫

使用 OpenCV 庫編寫 Java 程式碼時,第一步需要使用loadLibrary()載入 OpenCV 的原生庫。如下所示載入 OpenCV 原生庫。

//Loading the core library 
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

步驟 2:例項化 Mat 類

使用本章前面提到的任何函式例項化 Mat 類。

//Creating a matrix 
Mat matrix = new Mat(5, 5, CvType.CV_8UC1, new Scalar(0));

步驟 3:使用方法填充矩陣

您可以透過向row()/col()方法傳遞索引值來檢索矩陣的特定行/列。

並且,您可以使用setTo()方法的任何變體為其設定值。

//Retrieving the row with index 0 
Mat row0 = matrix.row(0); 
     
//setting values of all elements in the row with index 0 
row0.setTo(new Scalar(1)); 
     
//Retrieving the row with index 3 
Mat col3 = matrix.col(3);  
     
//setting values of all elements in the row with index 3 
col3.setTo(new Scalar(3));

示例

您可以使用以下程式程式碼使用 OpenCV 庫在 Java 中建立和顯示一個簡單的矩陣。

import org.opencv.core.Core; 
import org.opencv.core.Mat;  
import org.opencv.core.CvType;  
import org.opencv.core.Scalar;   

class DisplayingMatrix { 
   public static void main(String[] args) {     
      //Loading the core library 
      System.loadLibrary(Core.NATIVE_LIBRARY_NAME);     

      //Creating a matrix 
      Mat matrix = new Mat(5, 5, CvType.CV_8UC1, new Scalar(0));  

      //Retrieving the row with index 0 
      Mat row0 = matrix.row(0);

      //setting values of all elements in the row with index 0 
      row0.setTo(new Scalar(1)); 

      //Retrieving the row with index 3 
      Mat col3 = matrix.col(3);  

      //setting values of all elements in the row with index 3 
      col3.setTo(new Scalar(3)); 

      //Printing the matrix 
      System.out.println("OpenCV Mat data:\n" + matrix.dump()); 
   } 
}

執行上述程式後,您將獲得以下輸出 −

OpenCV Mat data: 
[  1,   1,   1,   3,   1; 
   0,   0,   0,   3,   0; 
   0,   0,   0,   3,   0; 
   0,   0,   0,   3,   0; 
   0,   0,   0,   3,   0]

使用 JavaSE API 載入影像

java.awt.image.BufferedImage包的BufferedImage類用於儲存影像,import javax.imageio包的ImageIO類提供讀取和寫入影像的方法。

示例

您可以使用以下程式程式碼使用 JavaSE 庫載入和儲存影像。

import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import javax.imageio.ImageIO;
  
public class LoadingImage_JSE_library {
   public static void main( String[] args ) throws IOException {
      //Input File 
      File input = new File("C:/EXAMPLES/OpenCV/sample.jpg");
          
      //Reading the image 
      BufferedImage image = ImageIO.read(input);
      
      //Saving the image with a different name
      File ouptut = new File("C:/OpenCV/sample.jpg");
      ImageIO.write(image, "jpg", ouptut);
         
      System.out.println("image Saved");
   } 
}

執行上述程式後,您將獲得以下輸出 −

image Saved

如果您開啟指定的路徑,您可以觀察到儲存的影像如下所示 −

Loading Image using JavaSE API

OpenCV - 讀取影像

org.opencv.imgcodecs包的Imgcodecs類提供讀取和寫入影像的方法。使用 OpenCV,您可以讀取影像並將其儲存在矩陣中(如果需要,可以在矩陣上執行轉換)。之後,您可以將處理後的矩陣寫入檔案。

Imgcodecs類的read()方法用於使用 OpenCV 讀取影像。以下是此方法的語法。

imread(filename)

它接受一個引數(filename),一個表示要讀取的檔案路徑的 String 型別變數。

以下是使用 OpenCV 庫在 Java 中讀取影像的步驟。

步驟 1:載入 OpenCV 原生庫

使用load()方法載入 OpenCV 原生庫,如下所示。

//Loading the core library 
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

步驟 2:例項化 Imgcodecs 類

例項化Imgcodecs類。

//Instantiating the Imgcodecs class 
Imgcodecs imageCodecs = new Imgcodecs();

步驟 3:讀取影像

使用imread()方法讀取影像。此方法接受一個表示影像路徑的字串引數,並返回作為Mat物件的讀取影像。

//Reading the Image from the file  
Mat matrix = imageCodecs.imread(Path of the image);

示例

以下程式程式碼顯示瞭如何使用 OpenCV 庫讀取影像

import org.opencv.core.Core; 
import org.opencv.core.Mat;  
import org.opencv.imgcodecs.Imgcodecs;
 
public class ReadingImages {
   public static void main(String args[]) { 
      //Loading the OpenCV core library  
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME ); 
     
      //Instantiating the Imagecodecs class 
      Imgcodecs imageCodecs = new Imgcodecs(); 
     
      //Reading the Image from the file  
      String file ="C:/EXAMPLES/OpenCV/sample.jpg"; 
      Mat matrix = imageCodecs.imread(file); 
     
      System.out.println("Image Loaded");     
   } 
}

執行上述程式後,OpenCV 將載入指定的影像並顯示以下輸出 −

Image Loaded

OpenCV - 寫入影像

Imgcodecs類的write()方法用於使用 OpenCV 寫入影像。要寫入影像,請重複前面示例中的前三個步驟。

要寫入影像,您需要呼叫Imgcodecs類的imwrite()方法。

以下是此方法的語法。

imwrite(filename, mat)

此方法接受以下引數 −

  • filename − 一個表示要儲存檔案路徑的String變數。

  • mat − 一個表示要寫入影像的Mat物件。

示例

以下程式是使用 OpenCV 庫使用 Java 程式寫入影像的示例。

import org.opencv.core.Core; 
import org.opencv.core.Mat; 
import org.opencv.imgcodecs.Imgcodecs;
 
public class WritingImages {  
   public static void main(String args[]) { 
      //Loading the OpenCV core library  
      System.loadLibrary(Core.NATIVE_LIBRARY_NAME); 
      
      //Instantiating the imagecodecs class 
      Imgcodecs imageCodecs = new Imgcodecs(); 

      //Reading the Image from the file and storing it in to a Matrix object 
      String file ="C:/EXAMPLES/OpenCV/sample.jpg";   
      Mat matrix = imageCodecs.imread(file); 

      System.out.println("Image Loaded ..........");
      String file2 = "C:/EXAMPLES/OpenCV/sample_resaved.jpg"; 

      //Writing the image 
      imageCodecs.imwrite(file2, matrix); 
      System.out.println("Image Saved ............"); 
   } 
}

執行上述程式後,您將獲得以下輸出 −

Image Loaded .......... 
Image Saved ...........

如果您開啟指定的路徑,您可以觀察到儲存的影像如下所示 −

Write Image

OpenCV - 圖形使用者介面 (GUI)

在前面的章節中,我們已經討論瞭如何使用 OpenCV Java 庫讀取和儲存影像。除此之外,我們還可以使用 AWT/Swings 和 JavaFX 等 GUI 庫在單獨的視窗中顯示載入的影像。

將 Mat 轉換為 Buffered Image

要讀取影像,我們使用imread()方法。此方法以矩陣的形式返回讀取的影像。但是,要將此影像與 GUI 庫(AWT/Swings 和 JavaFX)一起使用,應將其轉換為java.awt.image.BufferedImage包的BufferedImage類的物件。

以下是將 OpenCV 的Mat物件轉換為BufferedImage物件的步驟。

步驟 1:將 Mat 編碼為 MatOfByte

首先,您需要將矩陣轉換為位元組矩陣。您可以使用Imgcodecs類的imencode()方法來完成此操作。以下是此方法的語法。

imencode(ext, image, matOfByte);

此方法接受以下引數 −

  • Ext − 一個指定影像格式(.jpg、.png 等)的 String 引數。

  • image − 影像的 Mat 物件。

  • matOfByte − MatOfByte 類的一個空物件。

使用此方法編碼影像,如下所示。

//Reading the image 
Mat image = Imgcodecs.imread(file);

//instantiating an empty MatOfByte class 
MatOfByte matOfByte = new MatOfByte();

//Converting the Mat object to MatOfByte 
Imgcodecs.imencode(".jpg", image, matOfByte);

步驟 2:將 MatOfByte 物件轉換為位元組陣列

使用toArray()方法將MatOfByte物件轉換為位元組陣列。

byte[] byteArray = matOfByte.toArray();

步驟 3:準備 InputStream 物件

透過將上一步中建立的位元組陣列傳遞給ByteArrayInputStream類的建構函式來準備 InputStream 物件。

//Preparing the InputStream object 
InputStream in = new ByteArrayInputStream(byteArray);

步驟 4:準備 InputStream 物件

將上一步中建立的 Input Stream 物件傳遞給ImageIO類的read()方法。這將返回一個 BufferedImage 物件。

//Preparing the BufferedImage 
BufferedImage bufImage = ImageIO.read(in);

使用 AWT/Swings 顯示影像

要使用 AWT/Swings 框架顯示影像,首先使用imread()方法讀取影像,並按照上述步驟將其轉換為BufferedImage

然後,例項化JFrame類並將建立的緩衝影像新增到 JFrame 的 ContentPane 中,如下所示 −

//Instantiate JFrame 
JFrame frame = new JFrame();
 
//Set Content to the JFrame 
frame.getContentPane().add(new JLabel(new ImageIcon(bufImage))); 
frame.pack(); 
frame.setVisible(true);

示例

以下程式程式碼顯示瞭如何使用 OpenCV 庫讀取影像並透過 Swing 視窗顯示影像。

import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.imgcodecs.Imgcodecs;

public class DisplayingImagesUsingSwings {
   public static void main(String args[]) throws Exception { 
      //Loading the OpenCV core library  
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME ); 
    
      //Reading the Image from the file and storing it in to a Matrix object 
      String file = "C:/EXAMPLES/OpenCV/sample.jpg"; 
      Mat image = Imgcodecs.imread(file); 
    
      //Encoding the image 
      MatOfByte matOfByte = new MatOfByte();       
      Imgcodecs.imencode(".jpg", image, matOfByte); 

      //Storing the encoded Mat in a byte array 
      byte[] byteArray = matOfByte.toArray(); 

      //Preparing the Buffered Image 
      InputStream in = new ByteArrayInputStream(byteArray); 
      BufferedImage bufImage = ImageIO.read(in); 

      //Instantiate JFrame 
      JFrame frame = new JFrame(); 

      //Set Content to the JFrame 
      frame.getContentPane().add(new JLabel(new ImageIcon(bufImage))); 
      frame.pack(); 
      frame.setVisible(true);
      
      System.out.println("Image Loaded");     
   } 
}

執行上述程式後,您將獲得以下輸出 −

Image Loaded

除此之外,您還可以看到一個顯示載入影像的視窗,如下所示 −

Displaying Image using Swings

使用 JavaFX 顯示影像

要使用 JavaFX 顯示影像,首先使用imread()方法讀取影像,並將其轉換為BufferedImage。然後,將 BufferedImage 轉換為 WritableImage,如下所示。

WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);

將此WritableImage物件傳遞給ImageView類的建構函式。

ImageView imageView = new ImageView(writableImage);

示例

以下程式程式碼顯示瞭如何使用 OpenCV 庫讀取影像並透過 JavaFX 視窗顯示影像。

import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

import javax.imageio.ImageIO;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.imgcodecs.Imgcodecs;

public class DisplayingImagesJavaFX extends Application {
   @Override 
   public void start(Stage stage) throws IOException {   
      WritableImage writableImage = loadImage(); 
  
      //Setting the image view 
      ImageView imageView = new ImageView(writableImage); 
        
      //Setting the position of the image 
      imageView.setX(50); 
      imageView.setY(25); 
        
      //setting the fit height and width of the image view 
      imageView.setFitHeight(400); 
      imageView.setFitWidth(500);
      
      //Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);
      
      //Creating a Group object  
      Group root = new Group(imageView);
      
      //Creating a scene object
      Scene scene = new Scene(root, 600, 400);
      
      //Setting title to the Stage 
      stage.setTitle("Loading an image");
      
      //Adding scene to the stage
      stage.setScene(scene);

      //Displaying the contents of the stage
      stage.show();
   } 
   public WritableImage loadImage() throws IOException {
      //Loading the OpenCV core library  
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
      
      //Reading the Image from the file and storing it in to a Matrix object
      String file ="C:/EXAMPLES/OpenCV/sample.jpg";
      Mat image = Imgcodecs.imread(file);
      
      //Encoding the image
      MatOfByte matOfByte = new MatOfByte();
      Imgcodecs.imencode(".jpg", image, matOfByte);

      //Storing the encoded Mat in a byte array
      byte[] byteArray = matOfByte.toArray();
      
      //Displaying the image
      InputStream in = new ByteArrayInputStream(byteArray); 
      BufferedImage bufImage = ImageIO.read(in);

      System.out.println("Image Loaded");
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
      return writableImage; 
   }
   public static void main(String args[]) {
      launch(args); 
   } 
}

執行上述程式後,您將獲得以下輸出 −

Image Loaded

除此之外,您還可以看到一個顯示載入影像的視窗,如下所示 −

Displaying Image using JavaFX

OpenCV - IMREAD_XXX 引數

OpenCV 支援各種型別的影像,例如彩色、二值、灰度等。使用imread()方法和Imgcodecs類的預定義欄位,您可以將給定影像讀取為另一種型別。

imread() 方法的標誌引數 (IMREAD_XXX)

在前面的章節中,我們看到了Imgcodecs類的imread()方法的語法。它接受一個表示要讀取的影像位置的字串引數。

imread(filename)

imread()方法還有另一種語法。

imread(filename, int flags)

此語法接受兩個引數 −

  • filename − 它接受一個引數(filename),一個表示要讀取的檔案路徑的 String 型別變數。

  • flags − 一個整數值,表示預定義的標誌值。對於每個值,這都會將給定影像讀取為特定型別(灰度顏色等)。

以下是列出Imgproc類中作為此引數值的各個欄位的表格。

序號 欄位和描述
1

IMREAD_COLOR

如果標誌設定為此值,則載入的影像將被轉換為3通道BGR(藍綠紅)彩色影像。

2

IMREAD_GRAYSCALE

如果標誌設定為此值,則載入的影像將被轉換為單通道灰度影像。

3

IMREAD_LOAD_GDAL

如果標誌設定為此值,則可以使用gdal驅動程式載入影像。

4

IMREAD_ANYCOLOR

如果標誌設定為此值,則影像將以任何可能的顏色格式讀取。

5

IMREAD_REDUCED_COLOR_2

IMREAD_REDUCED_COLOR_4

IMREAD_REDUCED_COLOR_8

如果標誌設定為此值,則影像將作為三通道BGR讀取,並且影像大小將根據所使用的欄位減少到原始影像大小的½、¼或⅛。

6

IMREAD_REDUCED_GRAYSCALE_2

IMREAD_REDUCED_GRAYSCALE_4

IMREAD_REDUCED_GRAYSCALE_8

如果標誌設定為此值,則影像將作為單通道灰度影像讀取,並且影像大小將根據所使用的欄位減少到原始影像大小的½、¼或⅛。

7

IMREAD_UNCHANGED

如果標誌設定為此值,則載入的影像將原樣返回。

OpenCV - 將影像讀取為灰度

以下程式演示如何將彩色影像讀取為灰度影像,並使用JavaFX視窗顯示它。在這裡,我們透過傳遞標誌IMREAD_GRAYSCALE以及包含彩色影像路徑的字串來讀取影像。

import java.awt.image.BufferedImage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

public class ReadingAsGrayscale extends Application {
   @Override
   public void start(Stage stage) throws Exception {
      WritableImage writableImage = loadAndConvert();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // Setting the position of the image
      imageView.setX(10);
      imageView.setY(10);

      // setting the fit height and width of the image view
      imageView.setFitHeight(400);
      imageView.setFitWidth(600);
      
      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);
      
      // Creating a Group object  
      Group root = new Group(imageView);
      
      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);
      
      // Setting title to the Stage
      stage.setTitle("Reading image as grayscale");
      
      // Adding scene to the stage
      stage.setScene(scene);
      
      // Displaying the contents of the stage
      stage.show();
   } 
   public WritableImage loadAndConvert() throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Instantiating the imagecodecs class
      Imgcodecs imageCodecs = new Imgcodecs();

      String input = "C:/EXAMPLES/OpenCV/sample.jpg";

      // Reading the image
      Mat src = imageCodecs.imread(input, Imgcodecs.IMREAD_GRAYSCALE);
       
      byte[] data1 = new byte[src.rows() * src.cols() * (int)(src.elemSize())];
      src.get(0, 0, data1);
      
      // Creating the buffered image
      BufferedImage bufImage = new BufferedImage(src.cols(),src.rows(), 
         BufferedImage.TYPE_BYTE_GRAY);
      
      // Setting the data elements to the image
      bufImage.getRaster().setDataElements(0, 0, src.cols(), src.rows(), data1);
              
      // Creating a WritableImage
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
      System.out.println("Image Read");
      return writableImage;
   } 
   public static void main(String args[]) throws Exception { 
      launch(args); 
   } 
}

輸入影像

假設以上程式中指定的輸入影像是sample.jpg

Sample Image

輸出影像

執行程式後,您將獲得以下輸出。

GrayScale Output Image

OpenCV - 讀取BGR影像

以下程式演示如何將彩色影像讀取為BGR型別影像,並使用JavaFX視窗顯示它。在這裡,我們透過將標誌IMREAD_COLOR以及包含彩色影像路徑的字串傳遞給方法imread()來讀取影像。

import java.awt.image.BufferedImage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

public class ReadingAsColored extends Application {
   @Override 
   public void start(Stage stage) throws Exception {
      WritableImage writableImage = loadAndConvert();
       
      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // Setting the position of the image
      imageView.setX(10);
      imageView.setY(10);

      // setting the fit height and width of the image view
      imageView.setFitHeight(400);
      imageView.setFitWidth(600);
      
      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);
      
      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);
     
      // Setting title to the Stage
      stage.setTitle("Reading as colored image");

      // Adding scene to the stage
      stage.setScene(scene);
      
      // Displaying the contents of the stage
      stage.show();
   } 
   public WritableImage loadAndConvert() throws Exception {     
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
       
      String input = "C:/EXAMPLES/OpenCV/sample.jpg";
       
      Mat dst = new Mat();

      // Reading the image
      Mat src = Imgcodecs.imread(input, Imgcodecs.IMREAD_COLOR);

      byte[] data1 = new byte[src.rows() * src.cols() * (int)(src.elemSize())]; 
      src.get(0, 0, data1);
      
      // Creating the buffered image
      BufferedImage bufImage = new BufferedImage(src.cols(),src.rows(), 
         BufferedImage.TYPE_3BYTE_BGR);

      // Setting the data elements to the image 
      bufImage.getRaster().setDataElements(0, 0, src.cols(), src.rows(), data1);

      // Creating a WritableImage
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);

      System.out.println("Image read");
      return writableImage;
   } 
   public static void main(String args[]) throws Exception {
      launch(args);
   } 
}

輸入影像

假設以上程式中指定的輸入影像是sample.jpg

Sample Image

輸出影像

執行程式後,您將獲得以下輸出。

BGR Output Image

OpenCV - 彩色影像轉換為灰度

在前面的章節中,我們討論瞭如何將輸入影像讀取為不同的型別(二進位制、灰度、BGR等)。在本節中,我們將學習如何將一種型別的影像轉換為另一種型別。

org.opencv.imgproc中的名為Imgproc的類提供將影像從一種顏色轉換為另一種顏色方法。

將彩色影像轉換為灰度

名為cvtColor()的方法用於將彩色影像轉換為灰度影像。以下是此方法的語法。

cvtColor(Mat src, Mat dst, int code)

此方法接受以下引數 −

  • src − 代表源的矩陣。

  • dst − 代表目標的矩陣。

  • code − 代表轉換型別的整數程式碼,例如,RGB到灰度。

您可以透過將程式碼Imgproc.COLOR_RGB2GRAY以及源矩陣和目標矩陣作為引數傳遞給cvtColor()方法來將彩色影像轉換為灰度影像。

示例

以下程式演示如何將彩色影像讀取為灰度影像,並使用JavaFX視窗顯示它。

import java.awt.image.BufferedImage;
  
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;

import javafx.stage.Stage;

public class ColorToGrayscale extends Application {
   @Override
   public void start(Stage stage) throws Exception {
      WritableImage writableImage = loadAndConvert();
       
      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // Setting the position of the image
      imageView.setX(10);
      imageView.setY(10);

      // setting the fit height and width of the image view
      imageView.setFitHeight(400);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Colored to grayscale image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   } 
   public WritableImage loadAndConvert() throws Exception {
      //Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      String input = "C:/EXAMPLES/OpenCV/sample.jpg";

      //Reading the image
      Mat src = Imgcodecs.imread(input);

      //Creating the empty destination matrix
      Mat dst = new Mat();

      //Converting the image to gray sacle and saving it in the dst matrix
      Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2GRAY);
      
      //Extracting data from the transformed image (dst)
      byte[] data1 = new byte[dst.rows() * dst.cols() * (int)(dst.elemSize())];
      dst.get(0, 0, data1);

      //Creating Buffered image using the data
      BufferedImage bufImage = new BufferedImage(dst.cols(),dst.rows(), 
         BufferedImage.TYPE_BYTE_GRAY);

      //Setting the data elements to the image
      bufImage.getRaster().setDataElements(0, 0, dst.cols(), dst.rows(), data1);

      //Creating a WritableImage
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
      System.out.println("Converted to Grayscale");
      return writableImage;
   }
   public static void main(String args[]) throws Exception {
      launch(args);
   }
}

輸入影像

假設以上程式中指定的輸入影像是sample.jpg

Sample Image

輸出影像

執行程式後,您將獲得以下輸出。

Colored Images to GrayScale Output

OpenCV - 彩色影像轉換為二值影像

名為threshold()的方法用於將灰度影像轉換為二值影像。以下是此方法的語法。

threshold(Mat src, Mat dst, double thresh, double maxval, int type)

此方法接受以下引數 −

  • mat − 代表輸入影像的Mat物件。

  • dst − 代表輸出影像的Mat物件。

  • thresh − 代表閾值的整數。

  • maxval − 代表與THRESH_BINARY和THRESH_BINARY_INV閾值型別一起使用的最大值的整數。

  • type − 代表轉換型別的整數程式碼,例如,RGB到灰度。

您可以透過將程式碼Imgproc.THRESH_BINARY以及值傳遞給其餘引數來將灰度影像轉換為二值影像。

示例

以下程式演示如何將彩色影像讀取為二值影像,並使用JavaFX視窗顯示它。

import java.awt.image.BufferedImage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

public class ColorToBinary extends Application {
   @Override
   public void start(Stage stage) throws Exception {
      WritableImage writableImage = loadAndConvert();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // Setting the position of the image
      imageView.setX(10);
      imageView.setY(10);

      // setting the fit height and width of the image view
      imageView.setFitHeight(400);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);
      
      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);
      
      // Setting title to the Stage
      stage.setTitle("Loading an image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }
   public WritableImage loadAndConvert() throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Instantiating the Imgcodecs class
      Imgcodecs imageCodecs = new Imgcodecs();
        
      // File input = new File("C:/EXAMPLES/OpenCV/sample.jpg");
      String input = "C:/EXAMPLES/OpenCV/sample.jpg";

      // Reading the image
      Mat src = imageCodecs.imread(input);

      // Creating the destination matrix
      Mat dst = new Mat();

      // Converting to binary image...
      Imgproc.threshold(src, dst, 200, 500, Imgproc.THRESH_BINARY);

      // Extracting data from the transformed image (dst)
      byte[] data1 = new byte[dst.rows() * dst.cols() * (int)(dst.elemSize())];
      dst.get(0, 0, data1);

      // Creating Buffered image using the data
      BufferedImage bufImage = new BufferedImage(dst.cols(),dst.rows(), 
         BufferedImage.TYPE_BYTE_GRAY);

      // Setting the data elements to the image
      bufImage.getRaster().setDataElements(0, 0, dst.cols(), dst.rows(), data1);

      // Creating a Writable image
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);

      System.out.println("Converted to binary");
      return writableImage;
   }  
   public static void main(String args[]) throws Exception {
      launch(args);
   }
}

輸入影像

假設以上程式中指定的輸入影像是sample.jpg

Sample Image

輸出影像

執行程式後,您將獲得以下輸出。

Colored Image to Binary Output

OpenCV - 灰度影像轉換為二值影像

您可以使用上一章中提到的相同方法將灰度影像轉換為二值影像。只需將灰度影像的路徑作為輸入傳遞給此程式。

示例

以下程式演示如何將灰度影像讀取為二值影像,並使用JavaFX視窗顯示它。

import java.awt.image.BufferedImage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

public class GrayScaleToBinary extends Application {
   @Override
   public void start(Stage stage) throws Exception {
      WritableImage writableImage = loadAndConvert();
       
      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // Setting the position of the image
      imageView.setX(10);
      imageView.setY(10);
      
      // Setting the fit height and width of the image view
      imageView.setFitHeight(400);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Grayscale to binary image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }
   public WritableImage loadAndConvert() throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Instantiating the imagecodecs class
      Imgcodecs imageCodecs = new Imgcodecs();

      String input = "E:/OpenCV/chap7/grayscale.jpg";

      // Reading the image
      Mat src = imageCodecs.imread(input);

      // Creating the destination matrix
      Mat dst = new Mat();

      // Converting to binary image...
      Imgproc.threshold(src, dst, 200, 500, Imgproc.THRESH_BINARY);

      // Extracting data from the transformed image (dst)
      byte[] data1 = new byte[dst.rows() * dst.cols() * (int)(dst.elemSize())];
      dst.get(0, 0, data1);

      // Creating Buffered image using the data
      BufferedImage bufImage = new BufferedImage(dst.cols(),dst.rows(), 
         BufferedImage.TYPE_BYTE_BINARY);

      // Setting the data elements to the image
      bufImage.getRaster().setDataElements(0, 0, dst.cols(), dst.rows(), data1);

      // Creating a Writable image
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);

      System.out.println("Converted to binary");
      return writableImage;
   }
   public static void main(String args[]) throws Exception {
      launch(args);
   }
}

輸入影像

假設以上程式中指定的輸入影像是sample.jpg

Sample Image

輸出影像

執行程式後,您將獲得以下輸出。

GrayScale to Binary

OpenCV - 繪製圓形

您可以使用org.opencv.imgproc包的相應方法在影像上繪製各種形狀,如圓形、矩形、線條、橢圓、折線、凸多邊形和折線。

您可以使用imgproc類的circle()方法在影像上繪製圓形。以下是此方法的語法:

circle(img, center, radius, color, thickness)

此方法接受以下引數 −

  • mat − 代表要繪製圓形的影像的Mat物件。

  • point − 代表圓心Point物件。

  • radius − 代表圓形的半徑的整數型別變數。

  • scalar − 代表圓形顏色的Scalar物件。(BGR)

  • thickness − 代表圓形粗細的整數;預設情況下,粗細值為1。

示例

以下程式演示如何在影像上繪製圓形並使用JavaFX視窗顯示它。

import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.imageio.ImageIO;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class DrawingCircle extends Application {
   Mat matrix = null;
   
   @Override
   public void start(Stage stage) throws Exception {
      // Capturing the snapshot from the camera
      DrawingCircle obj = new DrawingCircle();
      WritableImage writableImage = obj.LoadImage();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // setting the fit height and width of the image view
      imageView.setFitHeight(600);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Drawing Circle on the image");
      
      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }      
   public WritableImage LoadImage() throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap8/input.jpg";
      Mat matrix = Imgcodecs.imread(file);

      //Drawing a Circle
      Imgproc.circle (
         matrix,                 //Matrix obj of the image
         new Point(230, 160),    //Center of the circle
         100,                    //Radius
         new Scalar(0, 0, 255),  //Scalar object for color
         10                      //Thickness of the circle
      );
      
      // Encoding the image
      MatOfByte matOfByte = new MatOfByte();
      Imgcodecs.imencode(".jpg", matrix, matOfByte);

      // Storing the encoded Mat in a byte array
      byte[] byteArray = matOfByte.toArray();

      // Displaying the image
      InputStream in = new ByteArrayInputStream(byteArray);
      BufferedImage bufImage = ImageIO.read(in);
      this.matrix = matrix;
      
      // Creating the Writable Image
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);

      return writableImage;
   }
   public static void main(String args[]) {
      launch(args);
   }
}

執行上述程式後,您將獲得以下輸出 −

Drawing Circle

OpenCV - 繪製直線

您可以使用imgproc類的line()方法在影像上繪製線條。以下是此方法的語法。

line(img, pt1, pt2, color, thickness)

此方法接受以下引數 −

  • mat − 代表要繪製線條的影像的Mat物件。

  • pt1和pt2 − 兩個Point物件,代表要繪製線條的兩個點。

  • scalar − 代表圓形顏色的Scalar物件。(BGR)

  • thickness − 代表線條粗細的整數;預設情況下,粗細值為1。

示例

以下程式演示如何在影像上繪製線條並使用JavaFX視窗顯示它。

import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.imageio.ImageIO;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class DrawingLine extends Application {
   Mat matrix = null;

   @Override
   public void start(Stage stage) throws Exception {
   
      // Capturing the snapshot from the camera
      DrawingLine obj = new DrawingLine();
      WritableImage writableImage = obj.LoadImage();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // setting the fit height and width of the image view
      imageView.setFitHeight(600);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object  
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Drawing a line on the image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }
   public WritableImage LoadImage() throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap8/input.jpg";
      Mat matrix = Imgcodecs.imread(file);

      // Drawing a line
      Imgproc.line (
         matrix,                    //Matrix obj of the image
         new Point(10, 200),        //p1
         new Point(300, 200),       //p2
         new Scalar(0, 0, 255),     //Scalar object for color
         5                          //Thickness of the line
      );
      // Encoding the image
      MatOfByte matOfByte = new MatOfByte();
      Imgcodecs.imencode(".jpg", matrix, matOfByte);

      // Storing the encoded Mat in a byte array
      byte[] byteArray = matOfByte.toArray();

      // Displaying the image
      InputStream in = new ByteArrayInputStream(byteArray);
      BufferedImage bufImage = ImageIO.read(in);

      this.matrix = matrix;

      // Creating the Writable Image
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
      return writableImage;
   }
   public static void main(String args[]) {
      launch(args);
   }
}

執行上述程式後,您將獲得以下輸出 −

Drawing Line

OpenCV - 繪製矩形

您可以使用imgproc類的rectangle()方法在影像上繪製矩形。以下是此方法的語法:

rectangle(img, pt1, pt2, color, thickness)

此方法接受以下引數 −

  • mat − 代表要繪製矩形的影像的Mat物件。

  • pt1和pt2 − 兩個Point物件,代表要繪製矩形的頂點。

  • scalar − 代表矩形顏色的Scalar物件。(BGR)

  • thickness − 代表矩形粗細的整數;預設情況下,粗細值為1。

示例

以下示例演示如何在影像上繪製矩形並使用JavaFX視窗顯示它。

import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.imageio.ImageIO;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class DrawingRectangle extends Application {
   Mat matrix = null;

   @Override
   public void start(Stage stage) throws Exception {
      // Capturing the snapshot from the camera
      DrawingRectangle obj = new DrawingRectangle();
      WritableImage writableImage = obj.LoadImage();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // setting the fit height and width of the image view
      imageView.setFitHeight(600);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Drawing Rectangle on the image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }
   public WritableImage LoadImage() throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap8/input.jpg";
      Mat matrix = Imgcodecs.imread(file);

      // Drawing a Rectangle
      Imgproc.rectangle (
         matrix,                    //Matrix obj of the image
         new Point(130, 50),        //p1
         new Point(300, 280),       //p2
         new Scalar(0, 0, 255),     //Scalar object for color
         5                          //Thickness of the line
      );
      
      // Encoding the image
      MatOfByte matOfByte = new MatOfByte();
      Imgcodecs.imencode(".jpg", matrix, matOfByte);

      // Storing the encoded Mat in a byte array
      byte[] byteArray = matOfByte.toArray();

      // Displaying the image
      InputStream in = new ByteArrayInputStream(byteArray);
      BufferedImage bufImage = ImageIO.read(in);

      this.matrix = matrix;

      // Creating the Writable Image
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
      return writableImage;
   }
   public static void main(String args[]) {
      launch(args);
   }
}

執行上述程式後,您將獲得以下輸出 −

Drawing Rectangle

OpenCV - 繪製橢圓

您可以使用imgproc類的rectangle()方法在影像上繪製橢圓。以下是此方法的語法:

ellipse(img, box, color, thickness)

此方法接受以下引數 −

  • mat − 代表要繪製矩形的影像的Mat物件。

  • box − RotatedRect 物件(橢圓繪製在此矩形內切)

  • scalar − 代表矩形顏色的Scalar物件。(BGR)

  • thickness − 代表矩形粗細的整數;預設情況下,粗細值為1。

RotatedRect類的建構函式接受Point類物件、Size類物件和double型別變數,如下所示。

RotatedRect(Point c, Size s, double a)

示例

以下程式演示如何在影像上繪製橢圓並使用JavaFX視窗顯示它。

import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.imageio.ImageIO;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Point;
import org.opencv.core.RotatedRect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class DrawingEllipse extends Application {
   Mat matrix = null;

   @Override
   public void start(Stage stage) throws Exception {
      // Capturing the snapshot from the camera
      DrawingEllipse obj = new DrawingEllipse();
      WritableImage writableImage = obj.LoadImage();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // setting the fit height and width of the image view
      imageView.setFitHeight(600);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Drawing Ellipse on the image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }
   public WritableImage LoadImage() throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap8/input.jpg";
      Mat matrix = Imgcodecs.imread(file);

      // Drawing an Ellipse
      Imgproc.ellipse (
         matrix,                          //Matrix obj of the image
         new RotatedRect (                // RotatedRect(Point c, Size s, double a)
            new Point(200, 150),
            new Size(260, 180), 180 
         ),
         new Scalar(0, 0, 255),           //Scalar object for color
         10                               //Thickness of the line
      );
      
      // Encoding the image
      MatOfByte matOfByte = new MatOfByte();
      Imgcodecs.imencode(".jpg", matrix, matOfByte);

      // Storing the encoded Mat in a byte array
      byte[] byteArray = matOfByte.toArray();

      // Displaying the image
      InputStream in = new ByteArrayInputStream(byteArray);
      BufferedImage bufImage = ImageIO.read(in);

      this.matrix = matrix;
      
      // Creating the Writable Image
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);

      return writableImage;
   }
   public static void main(String args[]) {
      launch(args);
   }
}

執行上述程式後,您將獲得以下輸出 −

Drawing Ellipse

OpenCV - 繪製折線

您可以使用imgproc類的polylines()方法在影像上繪製折線。以下是此方法的語法。

polylines(img, pts, isClosed, color, thickness)

此方法接受以下引數 −

  • mat − 代表要繪製折線的影像的Mat物件。

  • pts − 包含MatOfPoint型別物件的List物件。

  • isClosed − 指定折線是否閉合的布林型別引數。

  • scalar − 代表折線顏色的Scalar物件。(BGR)

  • thickness − 代表折線粗細的整數;預設情況下,粗細值為1。

MatOfPoint類的建構函式接受Point類物件。

MatOfPoint(Point... a)

示例

以下程式演示如何在影像上繪製折線並使用JavaFX視窗顯示它。

import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class DrawingPolyLines extends Application {
   Mat matrix = null;

   @Override
   public void start(Stage stage) throws Exception {
      // Capturing the snapshot from the camera
      DrawingPolyLines obj = new DrawingPolyLines();
      WritableImage writableImage = obj.LoadImage();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // setting the fit height and width of the image view
      imageView.setFitHeight(600);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Drawing Polylines on the image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }      
   public WritableImage LoadImage() throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap8/input.jpg";
      Mat matrix = Imgcodecs.imread(file);

      List<MatOfPoint> list = new ArrayList();
      list.add(
         new MatOfPoint (
            new Point(75, 100), new Point(350, 100),
            new Point(75, 150), new Point(350, 150),
            new Point(75, 200), new Point(350, 200),
            new Point(75, 250), new Point(350, 250)
         )
      );
      // Drawing polylines
      Imgproc.polylines (
         matrix,                    // Matrix obj of the image
         list,                      // java.util.List<MatOfPoint> pts
         false,                     // isClosed
         new Scalar(0, 0, 255),     // Scalar object for color
         2                          // Thickness of the line
      );
      // Encoding the image
      MatOfByte matOfByte = new MatOfByte();
      Imgcodecs.imencode(".jpg", matrix, matOfByte);

      // Storing the encoded Mat in a byte array
      byte[] byteArray = matOfByte.toArray();

      // Displaying the image
      InputStream in = new ByteArrayInputStream(byteArray);
      BufferedImage bufImage = ImageIO.read(in);

      this.matrix = matrix;

      // Creating the Writable Image
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
      return writableImage;
   }
   public static void main(String args[]) {
      launch(args);
   }
}

執行上述程式後,您將獲得以下輸出 −

Drawing Polylines

OpenCV - 繪製凸多邊形

您可以使用imgproc類的fillconvexPoly()方法在影像上繪製凸多邊形。以下是此方法的語法。

fillConvexPoly(Mat img, MatOfPoint points, Scalar color)

此方法接受以下引數 −

  • mat − 代表要繪製凸多邊形的影像的Mat物件。

  • points − 代表要繪製凸多邊形的點的MatOfPoint物件。

  • scalar − 代表凸多邊形顏色的Scalar物件。(BGR)

MatOfPoint類的建構函式接受Point類物件。

MatOfPoint(Point... a)

示例

以下程式演示如何在影像上繪製凸多邊形並使用JavaFX視窗顯示它。

import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.imageio.ImageIO;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class FillConvexPoly extends Application {
   Mat matrix = null;

   @Override
   public void start(Stage stage) throws Exception {
      // Capturing the snapshot from the camera
      FillConvexPoly obj = new FillConvexPoly();
      WritableImage writableImage = obj.LoadImage();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // setting the fit height and width of the image view
      imageView.setFitHeight(600);
      imageView.setFitWidth(600);

      //Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Drawing convex Polylines (fill) on the image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }
   public WritableImage LoadImage() throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap8/input.jpg";
      Mat matrix = Imgcodecs.imread(file);

      MatOfPoint matOfPoint = new MatOfPoint (
         new Point(75, 100), new Point(350, 100),
         new Point(75, 150), new Point(350, 150),
         new Point(75, 200), new Point(350, 200),
         new Point(75, 250), new Point(350, 250)
      ); 
      // Drawing polylines
      Imgproc.fillConvexPoly (
         matrix,                       // Matrix obj of the image
         matOfPoint,                   // java.util.List<MatOfPoint> pts
         new Scalar(0, 0, 255)         // Scalar object for color
      );
      // Encoding the image
      MatOfByte matOfByte = new MatOfByte();
      Imgcodecs.imencode(".jpg", matrix, matOfByte);

      // Storing the encoded Mat in a byte array
      byte[] byteArray = matOfByte.toArray();

      // Displaying the image
      InputStream in = new ByteArrayInputStream(byteArray);
      BufferedImage bufImage = ImageIO.read(in);
      this.matrix = matrix;
            
      // Creating the Writable Image
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
      return writableImage;
   } 
   public static void main(String args[]) {
      launch(args);
   }
}

執行上述程式後,您將獲得以下輸出 −

Drawing Convex Polylines

OpenCV - 繪製帶箭頭的直線

您可以使用imgproc類的arrowedLine()方法在影像上繪製帶箭頭的線條。以下是此方法的語法:

arrowedLine(Mat img, Point pt1, Point pt2, Scalar color)

此方法接受以下引數 −

  • mat − 代表要繪製帶箭頭線條的影像的Mat物件。

  • pt1和pt2 − 兩個Point物件,代表要繪製帶箭頭線條的兩個點。

  • scalar − 代表帶箭頭線條顏色的Scalar物件。(BGR)

示例

以下程式演示如何在影像上繪製帶箭頭線條並使用JavaFX視窗顯示它。

import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.imageio.ImageIO;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class DrawingArrowedLine extends Application {
   Mat matrix = null;

   @Override
   public void start(Stage stage) throws Exception {
      // Capturing the snapshot from the camera
      DrawingArrowedLine obj = new DrawingArrowedLine();
      WritableImage writableImage = obj.LoadImage();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // setting the fit height and width of the image view
      imageView.setFitHeight(600);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Drawing a line on the image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }
   public WritableImage LoadImage() throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="C:/EXAMPLES/OpenCV/Aish.jpg";
      Mat matrix = Imgcodecs.imread(file);

      //Drawing a line
      Imgproc.arrowedLine(
         matrix,                       // Matrix obj of the image
         new Point(10, 200),           // p1
         new Point(590, 200),          // p2
         new Scalar(0, 100, 255)       // Scalar object for color
      );

      // arrowedLine(Mat img, Point pt1, Point pt2, Scalar color)
      // Encoding the image
      MatOfByte matOfByte = new MatOfByte();
      Imgcodecs.imencode(".jpg", matrix, matOfByte);

      // Storing the encoded Mat in a byte array
      byte[] byteArray = matOfByte.toArray();

      // Displaying the image
      InputStream in = new ByteArrayInputStream(byteArray);
      BufferedImage bufImage = ImageIO.read(in);
      this.matrix = matrix;

      // Creating the Writable Image
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);

      return writableImage;
   }
   public static void main(String args[]) {
      launch(args);
   }
}

執行上述程式後,您將獲得以下輸出 −

Drawing Arrowed Lines

OpenCV - 新增文字

您可以使用imgproc類的arrowedLine()方法向影像新增文字。以下是此方法的語法。

putText(img, text, org, fontFace, fontScale, Scalar color, int thickness)

此方法接受以下引數 −

  • mat − 代表要新增文字的影像的Mat物件。

  • text − 代表要新增文字的字串變數。

  • org − 代表影像中文字字串左下角的Point物件。

  • fontFace − 代表字型型別的整數型別變數。

  • fontScale − 代表乘以字型特定基準大小的比例因子的double型別變數。

  • scalar − 代表要新增文字顏色的Scalar物件。(BGR)

  • thickness − 代表線條粗細的整數;預設情況下,粗細值為1。

示例

以下程式演示如何向影像新增文字並使用JavaFX視窗顯示它。

import java.awt.image.BufferedImage;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.imageio.ImageIO;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class AddingTextToImage extends Application {
   Mat matrix = null;

   @Override
   public void start(Stage stage) throws Exception {
      // Capturing the snapshot from the camera
      AddingTextToImage obj = new AddingTextToImage();
      WritableImage writableImage = obj.LoadImage();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // setting the fit height and width of the image view
      imageView.setFitHeight(600);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Adding text to an image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }
   public WritableImage LoadImage() throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap8/input.jpg";
      Mat matrix = Imgcodecs.imread(file);

      // Adding Text
      Imgproc.putText (
         matrix,                          // Matrix obj of the image
         "Ravivarma's Painting",          // Text to be added
         new Point(10, 50),               // point
         Core.FONT_HERSHEY_SIMPLEX ,      // front face
         1,                               // front scale
         new Scalar(0, 0, 0),             // Scalar object for color
         4                                // Thickness
      );
      
      // Encoding the image
      MatOfByte matOfByte = new MatOfByte();
      Imgcodecs.imencode(".jpg", matrix, matOfByte);

      // Storing the encoded Mat in a byte array
      byte[] byteArray = matOfByte.toArray();

      // Displaying the image
      InputStream in = new ByteArrayInputStream(byteArray);
      BufferedImage bufImage = ImageIO.read(in);
      this.matrix = matrix;

      //Creating the Writable Image
      WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
      return writableImage;
   }
   public static void main(String args[]) {
      launch(args);
   }
}

執行上述程式後,您將獲得以下輸出 −

Adding Text

OpenCV - 均值模糊

模糊(平滑)是常用的影像處理操作,用於減少影像噪點。此過程會去除影像中的高頻內容(如邊緣),使其平滑。

一般情況下,模糊化是透過卷積(影像的每個元素與其區域性鄰域元素相加,並由卷積核加權)影像透過低通濾波器卷積核來實現的。

模糊(平均)

在此操作過程中,影像與箱式濾波器(歸一化)進行卷積。在這個過程中,影像的中心元素被卷積核區域內所有畫素的平均值所替換。

您可以使用imgproc類的blur()方法對影像執行此操作。以下是此方法的語法:

blur(src, dst, ksize, anchor, borderType)

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • ksize − 一個Size物件,代表卷積核的大小。

  • anchor − 一個整數型別的變數,代表錨點。

  • borderType − 一個整數型別的變數,代表用於輸出的邊界型別。

示例

下面的程式演示瞭如何在影像上執行平均(模糊)操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class BlurTest {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="C:/EXAMPLES/OpenCV/sample.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Creating the Size and Point objects
      Size size = new Size(45, 45);
      Point point = new Point(20, 30);

      // Applying Blur effect on the Image
      Imgproc.blur(src, dst, size, point, Core.BORDER_DEFAULT);

      // blur(Mat src, Mat dst, Size ksize, Point anchor, int borderType)
      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap9/blur.jpg", dst);
      System.out.println("Image processed");
   }
}

假設以上程式中指定的輸入影像是sample.jpg

Sample Image

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Blur (Averaging)

OpenCV - 高斯模糊

在高斯模糊操作中,影像與高斯濾波器而不是箱式濾波器進行卷積。高斯濾波器是一種低通濾波器,它去除高頻分量。

您可以使用imgproc類的GaussianBlur()方法對影像執行此操作。以下是此方法的語法:

GaussianBlur(src, dst, ksize, sigmaX)

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • ksize − 一個Size物件,代表卷積核的大小。

  • sigmaX − 一個雙精度型別的變數,代表 X 方向上的高斯核標準差。

示例

下面的程式演示瞭如何在影像上執行高斯模糊操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class GaussianTest {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="C:/EXAMPLES/OpenCV/sample.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();
    
      // Applying GaussianBlur on the Image
      Imgproc.GaussianBlur(src, dst, new Size(45, 45), 0);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap9/Gaussian.jpg", dst);
      System.out.println("Image Processed");
   }
}

假設以上程式中指定的輸入影像是sample.jpg

Sample Image

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Gaussian Blur

OpenCV - 中值模糊

中值模糊操作類似於其他平均方法。在這裡,影像的中心元素被卷積核區域內所有畫素的中值所替換。此操作在去除噪聲的同時處理邊緣。

您可以使用imgproc類的medianBlur()方法對影像執行此操作。以下是此方法的語法:

medianBlur(src, dst, ksize)

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • ksize − 一個Size物件,代表卷積核的大小。

示例

下面的程式演示瞭如何在影像上執行中值模糊操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class MedianBlurTest {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="C:/EXAMPLES/OpenCV/sample.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Applying MedianBlur on the Image
      Imgproc.medianBlur(src, dst, 15);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap9/median.jpg", dst);

      System.out.println("Image Processed");
   }
}

假設以上程式中指定的輸入影像是sample.jpg

Sample Image

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Median Blur

OpenCV - 雙邊濾波

影像濾波允許您對影像應用各種效果。在本章和接下來的三章中,我們將討論各種濾波操作,例如雙邊濾波器、箱式濾波器、SQR 箱式濾波器和 Filter2D。

雙邊濾波器

雙邊濾波器操作將雙邊影像應用於濾波器。您可以使用imgproc類的medianBlur()方法對影像執行此操作。以下是此方法的語法。

bilateralFilter(src, dst, d, sigmaColor, sigmaSpace, borderType)

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • d − 一個整數型別的變數,代表畫素鄰域的直徑。

  • sigmaColor − 一個整數型別的變數,代表顏色空間中的濾波器 sigma。

  • sigmaSpace − 一個整數型別的變數,代表座標空間中的濾波器 sigma。

  • borderType − 一個整數物件,代表使用的邊界型別。

示例

下面的程式演示瞭如何在影像上執行雙邊濾波器操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class BilateralFilter {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap11/filter_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Applying Bilateral filter on the Image
      Imgproc.bilateralFilter(src, dst, 15, 80, 80, Core.BORDER_DEFAULT);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap11/bilateralfilter.jpg", dst);

      System.out.println("Image Processed");
   }
}

假設上面程式中指定的輸入影像是filter_input.jpg

Filter Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Bilateral Filter Output

OpenCV - 方框濾波

箱式濾波器操作類似於平均模糊操作;它將雙邊影像應用於濾波器。在這裡,您可以選擇是否應該對箱子進行歸一化。

您可以使用imgproc類的boxFilter()方法對影像執行此操作。以下是此方法的語法:

boxFilter(src, dst, ddepth, ksize, anchor, normalize, borderType)

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • ddepth − 一個整數型別的變數,代表輸出影像的深度。

  • ksize − 一個Size物件,代表模糊核的大小。

  • anchor − 一個整數型別的變數,代表錨點。

  • Normalize − 一個布林型別的變數,指定是否應該對核進行歸一化。

  • borderType − 一個整數物件,代表使用的邊界型別。

示例

下面的程式演示瞭如何在影像上執行箱式濾波器操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class BoxFilterTest {
   public static void main( String[] args ) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file = "E:/OpenCV/chap11/filter_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Creating the objects for Size and Point
      Size size = new Size(45, 45);
      Point point = Point(-1, -1);

      // Applying Box Filter effect on the Image
      Imgproc.boxFilter(src, dst, 50, size, point, true, Core.BORDER_DEFAULT);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap11/boxfilterjpg", dst);

      System.out.println("Image Processed");
   }
}

假設上面程式中指定的輸入影像是filter_input.jpg

Filter Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Box Filter

OpenCV - 平方盒濾波

您可以使用imgproc類的boxFilter()方法對影像執行 SQR 箱式濾波器操作。以下是此方法的語法:

sqrBoxFilter(src, dst, ddepth, ksize)

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • ddepth − 一個整數型別的變數,代表輸出影像的深度。

  • ksize − 一個Size物件,代表模糊核的大小。

示例

下面的程式演示瞭如何在給定影像上執行 Sqrbox 濾波器操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class SqrBoxFilterTest {
   public static void main( String[] args ) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap11/filter_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Applying Box Filter effect on the Image
      Imgproc.sqrBoxFilter(src, dst, -1, new Size(1, 1));
     
      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap11/sqrboxfilter.jpg", dst);

      System.out.println("Image Processed");
   } 
}

假設上面程式中指定的輸入影像是filter_input.jpg

Filter Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

SQRBox Filter

OpenCV - Filter2D

Filter2D 操作將影像與核進行卷積。您可以使用imgproc類的Filter2D()方法對影像執行此操作。以下是此方法的語法:

filter2D(src, dst, ddepth, kernel)

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • ddepth − 一個整數型別的變數,代表輸出影像的深度。

  • kernel − 一個Mat物件,代表卷積核。

示例

下面的程式演示瞭如何在影像上執行 Filter2D 操作。

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class Filter2D {
   public static void main( String[] args ) {
      //Loading the OpenCV core library  
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      //Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap11/filter_input.jpg";
      Mat src = Imgcodecs.imread(file);

      //Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Creating kernel matrix
      Mat kernel = Mat.ones(2,2, CvType.CV_32F);
      
      for(int i = 0; i<kernel.rows(); i++) {
         for(int j = 0; j<kernel.cols(); j++) {
            double[] m = kernel.get(i, j);

            for(int k = 1; k<m.length; k++) {
               m[k] = m[k]/(2 * 2);
            }
            kernel.put(i,j, m);
         }
      }
      Imgproc.filter2D(src, dst, -1, kernel);
      Imgcodecs.imwrite("E:/OpenCV/chap11/filter2d.jpg", dst);
      System.out.println("Image Processed");
   }
}

假設上面程式中指定的輸入影像是filter_input.jpg

Filter Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Filter2D

OpenCV - 膨脹

腐蝕和膨脹是兩種形態學操作。顧名思義,形態學操作是一組根據影像形狀處理影像的操作。

基於給定的輸入影像,開發了一個“結構元素”。這可以透過兩種程式中的任何一種來完成。這些旨在去除噪聲並消除缺陷,使影像清晰。

膨脹

此過程遵循與某種特定形狀(例如正方形或圓形)的核進行卷積。此核具有一個錨點,表示其中心。

此核與圖片重疊以計算最大畫素值。計算後,圖片將被中心處的錨點替換。透過此過程,明亮區域的面積會增大,因此影像大小會增大。

例如,白色陰影或明亮陰影中物件的尺寸會增加,而黑色陰影或黑暗陰影中物件的尺寸會減小。

您可以使用imgproc類的dilate()方法對影像執行膨脹操作。以下是此方法的語法。

dilate(src, dst, kernel)

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • kernel − 一個Mat物件,代表卷積核。

示例

您可以使用getStructuringElement()方法準備核矩陣。此方法接受一個代表morph_rect型別的整數和一個Size型別的物件。

Imgproc.getStructuringElement(int shape, Size ksize);

下面的程式演示瞭如何在給定影像上執行膨脹操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class DilateTest {
   public static void main( String[] args ) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="C:/EXAMPLES/OpenCV/sample.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Preparing the kernel matrix object 
      Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, 
         new  Size((2*2) + 1, (2*2)+1));

      // Applying dilate on the Image
      Imgproc.dilate(src, dst, kernel);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap10/Dilation.jpg", dst);

      System.out.println("Image Processed");
   } 
}

輸入

假設以上程式中指定的輸入影像是sample.jpg

Sample Image

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Dilation

OpenCV - 腐蝕

腐蝕與膨脹的過程非常相似。但是這裡計算的畫素值是最小值,而不是膨脹中的最大值。影像在錨點下用該最小畫素值替換。

透過此過程,黑暗區域的面積會增大,而明亮區域會減小。例如,黑暗陰影或黑色陰影中物件的尺寸會增加,而在白色陰影或明亮陰影中則會減小。

示例

您可以使用imgproc類的erode()方法對影像執行此操作。以下是此方法的語法:

erode(src, dst, kernel)

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • kernel − 一個Mat物件,代表卷積核。

您可以使用getStructuringElement()方法準備核矩陣。此方法接受一個代表morph_rect型別的整數和一個Size型別的物件。

Imgproc.getStructuringElement(int shape, Size ksize);

下面的程式演示瞭如何在給定影像上執行腐蝕操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class ErodeTest {
   public static void main( String[] args ) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="C:/EXAMPLES/OpenCV/sample.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Preparing the kernel matrix object
      Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, 
         new  Size((2*2) + 1, (2*2)+1));

      // Applying erode on the Image
      Imgproc.erode(src, dst, kernel);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap10/Erosion.jpg", dst);

      System.out.println("Image processed");
   }
}

假設以上程式中指定的輸入影像是sample.jpg

Sample Image

輸出

執行程式後,您將獲得以下輸出:

Image Loaded

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Erosion

OpenCV - 形態學操作

在前面的章節中,我們討論了腐蝕膨脹的過程。除了這兩個之外,OpenCV 還有更多形態學變換。Imgproc類的morphologyEx()方法用於對給定影像執行這些操作。

以下是此方法的語法:

morphologyEx(src, dst, op, kernel)

此方法接受以下引數 −

  • src − 一個Mat類物件,代表源(輸入)影像。

  • dst − 一個Mat類物件,代表目標(輸出)影像。

  • op − 一個整數,代表形態學操作的型別。

  • kernel − 一個核矩陣。

示例

下面的程式演示瞭如何使用 OpenCV 庫在影像上應用“頂帽”形態學操作。

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class MorphologyExTest {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap12/morph_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Creating kernel matrix
      Mat kernel = Mat.ones(5,5, CvType.CV_32F);

      // Applying Blur effect on the Image 
      Imgproc.morphologyEx(src, dst, Imgproc.MORPH_TOPHAT, kernel);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap12/morph_tophat.jpg", dst);

      System.out.println("Image Processed");
   } 
}

假設上面程式中指定的輸入影像是morph_input.jpg

Morph Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Morph Output

更多操作

除了前面示例中演示的TOPHAT形態學操作之外,OpenCV 還提供各種其他型別的形態學操作。所有這些型別都由Imgproc類的預定義靜態欄位(固定值)表示。

您可以透過將其各自的預定義值傳遞給morphologyEx()方法的op引數來選擇所需的形態學型別。

// Applying Blur effect on the Image
Imgproc.morphologyEx(src, dst, Imgproc.MORPH_TOPHAT, kernel);

以下是代表形態學操作型別及其各自輸出的值。

操作和描述 輸出
MORPH_BLACKHAT MORPH_BLACKHAT
MORPH_CLOSE MORPH_CLOSE
MORPH_CROSS MORPH_CROSS
MORPH_DILATE MORPH_DILATE
MORPH_ELLIPSE MORPH_ELLIPSE
MORPH_ERODE MORPH_ERODE
MORPH_GRADIENT MORPH_GRADIENT
MORPH_OPEN MORPH_OPEN
MORPH_RECT MORPH_RECT
MORPH_TOPHAT MORPH_TOPHAT

OpenCV - 影像金字塔

金字塔是對影像的操作,其中:

  • 輸入影像最初使用特定的平滑濾波器(例如:高斯、拉普拉斯)進行平滑,然後對平滑後的影像進行二次取樣。

  • 此過程重複多次。

在金字塔操作期間,影像的平滑度增加,解析度(大小)減小。

金字塔向上

在金字塔向上操作中,影像最初被上取樣,然後被模糊。您可以使用imgproc類的pyrUP()方法對影像執行金字塔向上操作。以下是此方法的語法:

pyrUp(src, dst, dstsize, borderType)

此方法接受以下引數 −

  • src − 一個Mat類物件,代表源(輸入)影像。

  • mat − 一個Mat類物件,代表目標(輸出)影像。

  • size − 一個Size類物件,代表影像要增大或減小到的尺寸。

  • borderType − 一個整數型別的變數,代表要使用的邊界型別。

示例

下面的程式演示瞭如何在影像上執行金字塔向上操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class PyramidUp {
   public static void main( String[] args ) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap13/pyramid_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Applying pyrUp on the Image
      Imgproc.pyrUp(src, dst, new Size(src.cols()*2,  src.rows()*2), Core.BORDER_DEFAULT);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap13/pyrUp_output.jpg", dst);

      System.out.println("Image Processed");
   }
}

假設上面程式中指定的輸入影像是pyramid_input.jpg

Pyramid Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Pyramid Up Output

金字塔向下

在金字塔向下操作中,影像最初被模糊,然後被下采樣。您可以使用imgproc類的pyrDown()方法對影像執行金字塔向下操作。以下是此方法的語法:

pyrDown(src, dst, dstsize, borderType)

此方法接受以下引數 −

  • src − 一個Mat類物件,代表源(輸入)影像。

  • mat − 一個Mat類物件,代表目標(輸出)影像。

  • size − 一個Size類物件,代表影像要增大或減小到的尺寸。

  • borderType − 一個整數型別的變數,代表要使用的邊界型別。

示例

下面的程式演示瞭如何在影像上執行金字塔向下操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class PyramidDown {
   public static void main( String[] args ) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap13/pyramid_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Applying pyrDown on the Image
      Imgproc.pyrDown(src, dst, new Size(src.cols()/2,  src.rows()/2),
         Core.BORDER_DEFAULT);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap13/pyrDown_output.jpg", dst);

      System.out.println("Image Processed");
   } 
}

假設上面程式中指定的輸入影像是pyramid_input.jpg

Pyramid Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Pyramid Down Output

均值漂移濾波

在均值漂移金字塔操作中,首先對影像進行均值漂移分割。

您可以使用imgproc類的pyrDown()方法對影像執行金字塔均值漂移濾波操作。以下是此方法的語法。

pyrMeanShiftFiltering(src, dst, sp, sr)

此方法接受以下引數 −

  • src − 一個Mat類物件,代表源(輸入)影像。

  • mat − 一個Mat類物件,代表目標(輸出)影像。

  • sp − 一個雙精度型別的變數,代表空間視窗半徑。

  • sr − 一個雙精度型別的變數,代表顏色視窗半徑。

示例

下面的程式演示瞭如何在給定影像上執行均值漂移濾波操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class PyramidMeanShift {
   public static void main( String[] args ) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap13/pyramid_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Applying meanShifting on the Image
      Imgproc.pyrMeanShiftFiltering(src, dst, 200, 300);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap13/meanShift_output.jpg", dst);
      
      System.out.println("Image Processed");
   } 
}

假設上面程式中指定的輸入影像是pyramid_input.jpg

Pyramid Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Mean Shift Filtering Output

OpenCV - 簡單閾值化

閾值化是一種影像分割方法,一般用於建立二值影像。閾值化分為兩種型別,即簡單閾值化和自適應閾值化。

簡單閾值化

在簡單閾值化操作中,畫素值大於指定閾值的值將被賦予一個標準值。

您可以使用Imgproc 類threshold()方法對影像執行簡單的閾值操作,以下是此方法的語法。

threshold(src, dst, thresh, maxval, type)

此方法接受以下引數 −

  • src − 一個Mat類物件,代表源(輸入)影像。

  • dst − 一個Mat類物件,代表目標(輸出)影像。

  • thresh − 一個雙精度型別的變數,代表閾值。

  • maxval − 一個雙精度型別的變數,代表如果畫素值大於閾值則要賦予的值。

  • type − 一個整數型別的變數,代表要使用的閾值型別。

示例

以下程式演示如何在OpenCV中對影像執行簡單的閾值操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class Thresh {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap14/thresh_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();
      Imgproc.threshold(src, dst, 50, 255, Imgproc.THRESH_BINARY);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap14/thresh_trunc.jpg", dst);

      System.out.println("Image Processed");
   }
}

假設以上程式中指定的輸入影像為thresh_input.jpg

Thresh Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Thresh Output

其他型別的簡單閾值化

除了前面示例中演示的THRESH_BINARY操作外,OpenCV還提供各種其他型別的閾值操作。所有這些型別都由Imgproc類的預定義靜態欄位(固定值)表示。

您可以透過將相應的預定義值傳遞給threshold()方法名為type的引數來選擇所需的閾值操作型別。

Imgproc.threshold(src, dst, 50, 255, Imgproc.THRESH_BINARY);

以下是表示各種閾值操作型別及其各自輸出的值。

操作和描述 輸出
THRESH_BINARY THRESH_BINARY
THRESH_BINARY_INV THRESH_BINARY_INV
THRESH_TRUNC THRESH_TRUNC
THRESH_TOZERO THRESH_TOZERO
THRESH_TOZERO_INV THRESH_TOZERO_INV

OpenCV - 自適應閾值化

簡單閾值化中,閾值是全域性的,即對影像中的所有畫素都相同。自適應閾值化是一種為較小區域計算閾值的方法,因此不同區域將具有不同的閾值。

在OpenCV中,您可以使用Imgproc類的adaptiveThreshold()方法對影像執行自適應閾值操作。以下是此方法的語法。

adaptiveThreshold(src, dst, maxValue, adaptiveMethod, thresholdType, blockSize, C)

此方法接受以下引數 −

  • src − 一個Mat類物件,代表源(輸入)影像。

  • dst − 一個Mat類物件,代表目標(輸出)影像。

  • maxValue − 一個雙精度型變數,表示如果畫素值大於閾值則要賦予的值。

  • adaptiveMethod − 一個整型變數,表示要使用的自適應方法。這將是以下兩個值之一:

    • ADAPTIVE_THRESH_MEAN_C − 閾值是鄰域區域的平均值。

    • ADAPTIVE_THRESH_GAUSSIAN_C − 閾值是鄰域值的加權和,權重為高斯視窗。

  • thresholdType − 一個整型變數,表示要使用的閾值型別。

  • blockSize − 一個整型變數,表示用於計算閾值大小的畫素鄰域。

  • C − 一個雙精度型變數,表示兩種方法中使用的常數(從平均值或加權平均值中減去)。

示例

以下程式演示如何在OpenCV中對影像執行自適應閾值操作。這裡我們選擇型別為binary的自適應閾值和ADAPTIVE_THRESH_MEAN_C作為閾值方法。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class AdaptiveThresh {
   public static void main(String args[]) throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap14/thresh_input.jpg";
      
      // Reading the image
      Mat src = Imgcodecs.imread(file,0);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      Imgproc.adaptiveThreshold(src, dst, 125, Imgproc.ADAPTIVE_THRESH_MEAN_C,
         Imgproc.THRESH_BINARY, 11, 12);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap14/Adaptivemean_thresh_binary.jpg", dst);

      System.out.println("Image Processed");
   } 
}

假設以上程式中指定的輸入影像為thresh_input.jpg

Thresh Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Adaptive Threshold Output

其他型別的自適應閾值化

除了前面示例中演示的ADAPTIVE_THRESH_MEAN_C作為自適應方法和THRESH_BINARY作為閾值型別外,我們還可以選擇這兩種值的更多組合。

Imgproc.adaptiveThreshold(src, dst, 125, Imgproc.ADAPTIVE_THRESH_MEAN_C, 
   Imgproc.THRESH_BINARY, 11, 12);

以下是表示引數adaptiveMethodthresholdType的各種組合值及其各自輸出的值。

adaptiveMethod / thresholdType ADAPTIVE_THRESH_MEAN_C ADAPTIVE_THRESH_GAUSSIAN_C
THRESH_BINARY ADAPTIVE_THRESH_BINARY ADAPTIVE_THRESH_GAUSSIAN_BINARY
THRESH_BINARY_INV ADAPTIVE_THRESH_BINARY_INV ADAPTIVE_THRESH_GAUSSIAN_BINARY_INV

OpenCV - 新增邊界

本章將教你如何向影像新增邊界。

copyMakeBorder() 方法

您可以使用名為Core的類的copyMakeBorder()方法向影像新增各種邊界,該類屬於org.opencv.core包。以下是此方法的語法。

copyMakeBorder(src, dst, top, bottom, left, right, borderType)

此方法接受以下引數 −

  • src − 一個Mat類物件,代表源(輸入)影像。

  • dst − 一個Mat類物件,代表目標(輸出)影像。

  • top − 一個整型變數,表示影像頂部邊界的長度。

  • bottom − 一個整型變數,表示影像底部邊界的長度。

  • left − 一個整型變數,表示影像左側邊界的長度。

  • right − 一個整型變數,表示影像右側邊界的長度。

  • borderType − 一個整型變數,表示要使用的邊界型別。

示例

以下程式是一個示例,演示如何向給定影像新增邊界。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;

public class AddingBorder {
   public static void main( String[] args ) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
     
      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap15/input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();
   
      Core.copyMakeBorder(src, dst, 20, 20, 20, 20, Core.BORDER_CONSTANT);
      Imgcodecs.imwrite("E:/OpenCV/chap15/border_constant.jpg", dst);

      System.out.println("Image Processed");
   }
}

假設以上程式中指定的輸入影像為thresh_input.jpg

Thresh Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Adding Borders Output

其他型別的邊界

除了前面示例中演示的邊界型別BORDER_CONSTANT外,OpenCV還提供各種其他型別的邊界。所有這些型別都由Core類的預定義靜態欄位(固定值)表示。

您可以透過將相應的預定義值傳遞給copyMakeBorder()方法名為borderType的引數來選擇所需的邊界型別。

Core.copyMakeBorder(src, dst, 20, 20, 20, 20, Core.BORDER_CONSTANT);

以下是表示各種邊界操作型別及其各自輸出的值。

操作和描述 輸出
BORDER_CONSTANT BORDER_CONSTANT
BORDER_ISOLATED BORDER_ISOLATED
BORDER_DEFAULT BORDER_DEFAULT
BORDER_REFLECT BORDER_REFLECT
BORDER_REFLECT_101 BORDER_REFLECT_101
BORDER_REFLECT101 BORDER_REFLECT101
BORDER_REPLICATE BORDER_REPLICATE
BORDER_WRAP BORDER_WRAP

OpenCV - Sobel 運算元

使用Sobel運算元,您可以檢測影像在水平和垂直方向上的邊緣。您可以使用sobel()方法對影像應用Sobel運算元。以下是此方法的語法:

Sobel(src, dst, ddepth, dx, dy)

此方法接受以下引數 −

  • src − 一個Mat類物件,代表源(輸入)影像。

  • dst − 一個Mat類物件,代表目標(輸出)影像。

  • ddepth − 一個整型變數,表示影像的深度(-1)

  • dx − 一個整型變數,表示x導數。(0或1)

  • dy − 一個整型變數,表示y導數。(0或1)

示例

以下程式演示如何在給定影像上執行Sobel操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;

import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class SobelTest {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap16/sobel_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Applying sobel on the Image
      Imgproc.Sobel(src, dst, -1, 1, 1);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap16/sobel_output.jpg", dst);

      System.out.println("Image processed");
   }
}

假設以上程式中指定的輸入影像為sobel_input.jpg

Window Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Sobel Output

Sobel 變體

將不同的值傳遞給最後兩個引數(dx 和 dy)(在 0 和 1 之間),您將獲得不同的輸出:

// Applying sobel on the Image
Imgproc.Sobel(src, dst, -1, 1, 1);

下表列出了Sobel()方法的變數dxdy的各種值及其各自的輸出。

X導數 Y導數 輸出
0 1 Sobel 01
1 0 Sobel 10
1 1 Sobel 11

OpenCV - Scharr 運算元

Scharr也用於檢測影像在水平和垂直方向上的二階導數。您可以使用scharr()方法對影像執行Scharr操作。以下是此方法的語法:

Scharr(src, dst, ddepth, dx, dy)

此方法接受以下引數 −

  • src − 一個Mat類物件,代表源(輸入)影像。

  • dst − 一個Mat類物件,代表目標(輸出)影像。

  • ddepth − 一個整型變數,表示影像的深度(-1)

  • dx − 一個整型變數,表示x導數。(0或1)

  • dy − 一個整型變數,表示y導數。(0或1)

示例

以下程式演示如何將Scharr應用於給定影像。

import org.opencv.core.Core;
import org.opencv.core.Mat;

import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class ScharrTest {

   public static void main( String[] args ) {

      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap16/sobel_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Applying Box Filter effect on the Image
      Imgproc.Scharr(src, dst, Imgproc.CV_SCHARR, 0, 1);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap16/scharr_output.jpg", dst);

      System.out.println("Image processed");
   }
}

假設以上程式中指定的輸入影像為scharr_input.jpg

Window Input

輸出

執行後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到輸出影像如下:

Scharr Output

更多 Scharr 導數

將不同的值傳遞給最後兩個引數 (dx 和 dy) (在 0 和 1 之間),您將獲得不同的輸出:

// Applying scharr on the Image
Imgproc.Scharr(src, dst, -1, 1, 1);

下表列出了scharr()方法的變數dxdy的各種值及其各自的輸出。

X導數 Y導數 輸出
0 1 Scharr 01
1 0 Scharr 10

OpenCV - 拉普拉斯變換

拉普拉斯運算元也是一個導數運算元,用於查詢影像中的邊緣。它是一個二階導數掩碼。在這個掩碼中,我們有兩個進一步的分類,一個是正拉普拉斯運算元,另一個是負拉普拉斯運算元。

與其他運算元不同,拉普拉斯運算元不會在任何特定方向上提取邊緣,而是按以下分類提取邊緣。

  • 內邊緣
  • 外邊緣

您可以使用imgproc類的Laplacian()方法對影像執行拉普拉斯變換操作,以下是此方法的語法。

Laplacian(src, dst, ddepth)

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • ddepth − 一個整型變數,表示目標影像的深度。

示例

以下程式演示如何在給定影像上執行拉普拉斯變換操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class LaplacianTest {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

      //Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap18/laplacian_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Applying GaussianBlur on the Image
      Imgproc.Laplacian(src, dst, 10);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap18/laplacian.jpg", dst);

      System.out.println("Image Processed");
   }
}

假設以上程式中指定的輸入影像為laplacian_input.jpg

Laplacian Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Laplacian Output

OpenCV - 距離變換

距離變換運算元通常以二值影像作為輸入。在此操作中,前景區域內點的灰度強度會更改為它們到最近的0值(邊界)的距離。

您可以使用distanceTransform()方法在OpenCV中應用距離變換。以下是此方法的語法。

distanceTransform(src, dst, distanceType, maskSize)

此方法接受以下引數 −

  • src − 一個Mat類物件,代表源(輸入)影像。

  • dst − 一個Mat類物件,代表目標(輸出)影像。

  • distanceType − 一個整型變數,表示要應用的距離變換型別。

  • maskSize − 一個整型變數,表示要使用的掩碼大小。

示例

以下程式演示如何在給定影像上執行距離變換操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class DistanceTransform {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap19/input.jpg";
      Mat src = Imgcodecs.imread(file,0);

      // Creating an empty matrix to store the results
      Mat dst = new Mat();
      Mat binary = new Mat();

      // Converting the grayscale image to binary image
      Imgproc.threshold(src, binary, 100, 255, Imgproc.THRESH_BINARY);

      // Applying distance transform
      Imgproc.distanceTransform(mat, dst, Imgproc.DIST_C, 3);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap19/distnceTransform.jpg", dst);

      System.out.println("Image Processed");
   }
}

假設以上程式中指定的輸入影像為input.jpg

Distance Transformation Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Distance Transformation Output

距離變換操作型別

除了前面示例中演示的距離操作型別DIST_C外,OpenCV還提供各種其他型別的距離變換操作。所有這些型別都由Imgproc類的預定義靜態欄位(固定值)表示。

您可以透過將相應的預定義值傳遞給distanceTransform()方法名為distanceType的引數來選擇所需的距離變換操作型別。

// Applying distance transform 
Imgproc.distanceTransform(mat, dst, Imgproc.DIST_C, 3);

以下是表示各種distanceTransform操作型別及其各自輸出的值。

操作和描述 輸出
DIST_C DIST_C
DIST_L1 DIST_L1
DIST_L2 DIST_L2
DIST_LABEL_PIXEL DIST_LABEL_PIXEL
DIST_MASK_3 DIST_MASK_3

OpenCV - 使用攝像頭

在本章中,我們將學習如何使用OpenCV使用系統攝像頭捕獲幀。org.opencv.videoio包的VideoCapture類包含使用攝像頭捕獲影片的類和方法。讓我們一步一步地學習如何捕獲幀:

步驟 1:載入 OpenCV 原生庫

使用 OpenCV 庫編寫 Java 程式碼時,第一步需要使用loadLibrary()載入 OpenCV 的原生庫。如下所示載入 OpenCV 原生庫。

// Loading the core library 
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

步驟2:例項化影片捕獲類

使用本教程前面提到的任何函式例項化Mat類。

// Instantiating the VideoCapture class (camera:: 0) 
VideoCapture capture = new VideoCapture(0);

步驟3:讀取幀

您可以使用VideoCapture類的read()方法讀取來自攝像頭的幀。此方法接受Mat類的物件來儲存讀取的幀。

// Reading the next video frame from the camera 
Mat matrix = new Mat(); 
capture.read(matrix);

示例

以下程式演示如何使用攝像頭捕獲幀並使用JavaFX視窗顯示它。它還儲存捕獲的幀。

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.WritableRaster;

import java.io.FileNotFoundException;
import java.io.IOException;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.videoio.VideoCapture;

public class CameraSnapshotJavaFX extends Application {
   Mat matrix = null;

   @Override
   public void start(Stage stage) throws FileNotFoundException, IOException {
      // Capturing the snapshot from the camera
      CameraSnapshotJavaFX obj = new CameraSnapshotJavaFX();
      WritableImage writableImage = obj.capureSnapShot();

      // Saving the image
      obj.saveImage();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // setting the fit height and width of the image view
      imageView.setFitHeight(400);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Capturing an image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }
   public WritableImage capureSnapShot() {
      WritableImage WritableImage = null;

      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Instantiating the VideoCapture class (camera:: 0)
      VideoCapture capture = new VideoCapture(0);

      // Reading the next video frame from the camera
      Mat matrix = new Mat();
      capture.read(matrix);

      // If camera is opened
      if( capture.isOpened()) {
         // If there is next video frame
         if (capture.read(matrix)) {
            // Creating BuffredImage from the matrix
            BufferedImage image = new BufferedImage(matrix.width(), 
               matrix.height(), BufferedImage.TYPE_3BYTE_BGR);
            
            WritableRaster raster = image.getRaster();
            DataBufferByte dataBuffer = (DataBufferByte) raster.getDataBuffer();
            byte[] data = dataBuffer.getData();
            matrix.get(0, 0, data);
            this.matrix = matrix;
            
            // Creating the Writable Image
            WritableImage = SwingFXUtils.toFXImage(image, null);
         }
      }
      return WritableImage;
   }
   public void saveImage() {
      // Saving the Image
      String file = "E:/OpenCV/chap22/sanpshot.jpg";

      // Instantiating the imgcodecs class
      Imgcodecs imageCodecs = new Imgcodecs();

      // Saving it again 
      imageCodecs.imwrite(file, matrix);
   }
   public static void main(String args[]) {
      launch(args);
   }
}

輸出

執行程式後,您將獲得以下輸出。

Capture Frame Using Camera

如果您開啟指定的路徑,您可以看到儲存為jpg檔案的相同幀。

OpenCV - 圖片中的人臉檢測

org.opencv.videoio包的VideoCapture類包含使用系統攝像頭捕獲影片的類和方法。讓我們一步一步地學習如何做到這一點。

步驟 1:載入 OpenCV 原生庫

使用 OpenCV 庫編寫 Java 程式碼時,第一步需要使用loadLibrary()載入 OpenCV 的原生庫。如下所示載入 OpenCV 原生庫。

// Loading the core library 
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

步驟2:例項化CascadeClassifier類

org.opencv.objdetect包的CascadeClassifier類用於載入分類器檔案。透過傳遞xml檔案lbpcascade_frontalface.xml來例項化此類,如下所示。

// Instantiating the CascadeClassifier 
String xmlFile = "E:/OpenCV/facedetect/lbpcascade_frontalface.xml"; 
CascadeClassifier classifier = new CascadeClassifier(xmlFile);

步驟3:檢測人臉

您可以使用名為CascadeClassifier類的detectMultiScale()方法檢測影像中的人臉。此方法接受持有輸入影像的Mat類物件和MatOfRect類物件來儲存檢測到的人臉。

// Detecting the face in the snap 
MatOfRect faceDetections = new MatOfRect(); 
classifier.detectMultiScale(src, faceDetections);

示例

以下程式演示如何在影像中檢測人臉。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;

import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
  
public class FaceDetectionImage {
   public static void main (String[] args) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap23/facedetection_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Instantiating the CascadeClassifier
      String xmlFile = "E:/OpenCV/facedetect/lbpcascade_frontalface.xml";
      CascadeClassifier classifier = new CascadeClassifier(xmlFile);

      // Detecting the face in the snap
      MatOfRect faceDetections = new MatOfRect();
      classifier.detectMultiScale(src, faceDetections);
      System.out.println(String.format("Detected %s faces", 
         faceDetections.toArray().length));

      // Drawing boxes
      for (Rect rect : faceDetections.toArray()) {
         Imgproc.rectangle(
            src,                                               // where to draw the box
            new Point(rect.x, rect.y),                            // bottom left
            new Point(rect.x + rect.width, rect.y + rect.height), // top right
            new Scalar(0, 0, 255),
            3                                                     // RGB colour
         );
      }

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap23/facedetect_output1.jpg", src);

      System.out.println("Image Processed");
   }
}

假設以上程式中指定的輸入影像為facedetection_input.jpg

FaceDetection Input

輸出

執行程式後,您將獲得以下輸出:

Detected 3 faces 
Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

FaceDetection Output

OpenCV - 使用攝像頭進行人臉檢測

以下程式演示如何使用系統攝像頭檢測人臉並使用JavaFX視窗顯示它。

示例

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.WritableRaster;

import java.io.FileNotFoundException;
import java.io.IOException;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;

public class faceDetectionJavaFXX extends Application {
   Mat matrix = null;

   @Override
   public void start(Stage stage) throws FileNotFoundException, IOException {
      // Capturing the snapshot from the camera
      faceDetectionJavaFXX obj = new faceDetectionJavaFXX();
      WritableImage writableImage = obj.capureFrame();

      // Saving the image
      obj.saveImage();

      // Setting the image view
      ImageView imageView = new ImageView(writableImage);

      // setting the fit height and width of the image view
      imageView.setFitHeight(400);
      imageView.setFitWidth(600);

      // Setting the preserve ratio of the image view
      imageView.setPreserveRatio(true);

      // Creating a Group object
      Group root = new Group(imageView);

      // Creating a scene object
      Scene scene = new Scene(root, 600, 400);

      // Setting title to the Stage
      stage.setTitle("Capturing an image");

      // Adding scene to the stage
      stage.setScene(scene);

      // Displaying the contents of the stage
      stage.show();
   }
   public WritableImage capureFrame() {
      WritableImage writableImage = null;

      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Instantiating the VideoCapture class (camera:: 0)
      VideoCapture capture = new VideoCapture(0);

      // Reading the next video frame from the camera
      Mat matrix = new Mat();
      capture.read(matrix);

      // If camera is opened
      if(!capture.isOpened()) {
         System.out.println("camera not detected");
      } else
         System.out.println("Camera detected ");
           
      // If there is next video frame
      if (capture.read(matrix)) {
         /////// Detecting the face in the snap /////
         String file = "E:/OpenCV/facedetect/lbpcascade_frontalface.xml";
         CascadeClassifier classifier = new CascadeClassifier(file);

         MatOfRect faceDetections = new MatOfRect();
         classifier.detectMultiScale(matrix, faceDetections);
         System.out.println(String.format("Detected %s faces",
            faceDetections.toArray().length));

         // Drawing boxes
         for (Rect rect : faceDetections.toArray()) {
            Imgproc.rectangle(
               matrix,                                   //where to draw the box
               new Point(rect.x, rect.y),                            //bottom left
               new Point(rect.x + rect.width, rect.y + rect.height), //top right
               new Scalar(0, 0, 255)                                 //RGB colour
            );
         }
         // Creating BuffredImage from the matrix
         BufferedImage image = new BufferedImage(matrix.width(), matrix.height(),
            BufferedImage.TYPE_3BYTE_BGR);
         
         WritableRaster raster = image.getRaster();
         DataBufferByte dataBuffer = (DataBufferByte) raster.getDataBuffer();
         byte[] data = dataBuffer.getData();
         matrix.get(0, 0, data);

         this.matrix = matrix;
           
         // Creating the Writable Image
         writableImage = SwingFXUtils.toFXImage(image, null);
      }
      return writableImage;
   }
   public void saveImage() {
      // Saving the Image
      String file = "E:/OpenCV/chap23/facedetected.jpg";

      // Instantiating the imagecodecs class
      Imgcodecs imageCodecs = new Imgcodecs();

      // Saving it again
      imageCodecs.imwrite(file, matrix);
   }
   public static void main(String args[]) {
      launch(args);
   }
}

輸出

執行程式後,您將獲得以下輸出。

Face Detection using Camera

如果您開啟指定的路徑,您可以看到儲存為jpg影像的相同快照。

OpenCV - 仿射變換(平移)

您可以使用imgproc類的warpAffine()方法對影像執行仿射變換。以下是此方法的語法:

Imgproc.warpAffine(src, dst, tranformMatrix, size);

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • tranformMatrix − 一個Mat物件,表示變換矩陣。

  • size − 一個整型變數,表示輸出影像的大小。

示例

以下程式演示如何在給定影像上應用仿射操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class AffineTranslation {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap24/transform_input.jpg";
      Mat src = Imgcodecs.imread(file);

      //Creating an empty matrix to store the result
      Mat dst = new Mat();

      Point p1 = new Point( 0,0 );
      Point p2 = new Point( src.cols() - 1, 0 );
      Point p3 = new Point( 0, src.rows() - 1 );
      Point p4 = new Point( src.cols()*0.0, src.rows()*0.33 );
      Point p5 = new Point( src.cols()*0.85, src.rows()*0.25 );
      Point p6 = new Point( src.cols()*0.15, src.rows()*0.7 );
      
      MatOfPoint2f ma1 = new MatOfPoint2f(p1,p2,p3);
      MatOfPoint2f ma2 = new MatOfPoint2f(p4,p5,p6);

      // Creating the transformation matrix
      Mat tranformMatrix = Imgproc.getAffineTransform(ma1,ma2);

      // Creating object of the class Size
      Size size = new Size(src.cols(), src.cols());

      // Applying Wrap Affine
      Imgproc.warpAffine(src, dst, tranformMatrix, size);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap24/Affinetranslate.jpg", dst);

      System.out.println("Image Processed");
   }
}

假設以上程式中指定的輸入影像為transform_input.jpg

Transform Input

輸出

執行後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Affine Translation

OpenCV - 旋轉

可以使用imgproc類的warpAffine()方法對影像進行旋轉操作。以下是此方法的語法:

Imgproc.warpAffine(src, dst, rotationMatrix, size);

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • rotationMatrix − 表示旋轉矩陣的Mat物件。

  • size − 一個整型變數,表示輸出影像的大小。

示例

下面的程式演示瞭如何旋轉影像。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Size;

import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class Rotation {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap24/transform_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Creating a Point object
      Point point = new Point(300, 200)

      // Creating the transformation matrix M
      Mat rotationMatrix = Imgproc.getRotationMatrix2D(point, 30, 1);

      // Creating the object of the class Size
      Size size = new Size(src.cols(), src.cols());

      // Rotating the given image
      Imgproc.warpAffine(src, dst, rotationMatrix, size);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap24/rotate_output.jpg", dst);

      System.out.println("Image Processed");
   }
}

假設以上程式中指定的輸入影像為transform_input.jpg

Transform Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Rotate Output

OpenCV - 縮放

可以使用imgproc類的resize()方法對影像進行縮放。以下是此方法的語法。

resize(Mat src, Mat dst, Size dsize, double fx, double fy, int interpolation)

此方法接受以下引數 −

  • src − 一個Mat物件,代表此操作的源(輸入影像)。

  • dst − 一個Mat物件,代表此操作的目標(輸出影像)。

  • dsize − 表示輸出影像大小的Size物件。

  • fx − 一個double型別的變數,表示水平方向的縮放因子。

  • fy − 一個double型別的變數,表示垂直方向的縮放因子。

  • Interpolation − 一個整型變數,表示插值方法。

示例

下面的程式演示瞭如何將縮放變換應用於影像。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;

import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class Scaling {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap24/transform_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Creating the Size object
      Size size = new Size(src.rows()*2, src.rows()*2);

      // Scaling the Image
      Imgproc.resize(src, dst, size, 0, 0, Imgproc.INTER_AREA);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap24/scale_output.jpg", dst);

      System.out.println("Image Processed");
   }
}

假設上面程式中指定的輸入影像為transform_input.jpg(大小:寬度300畫素,高度300畫素)。

Transform Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果開啟指定的路徑,您可以看到輸出影像如下所示(大小:寬度600畫素,高度600畫素):

Scale Output

OpenCV - 顏色對映

在OpenCV中,您可以使用Imgproc類的applyColorMap()方法將不同的顏色對映應用於影像。以下是此方法的語法:

applyColorMap(Mat src, Mat dst, int colormap)

它接受三個引數:

  • src − 一個Mat類物件,代表源(輸入)影像。

  • dst − 一個Mat類物件,代表目標(輸出)影像。

  • colormap − 一個整型變數,表示要應用的顏色對映型別。

示例

下面的程式演示瞭如何將顏色對映應用於影像。

import org.opencv.core.Core;
import org.opencv.core.Mat;

import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class ColorMapTest {
   public static void main(String args[]) {
      // Loading the OpenCV core library
      System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap25/color_input.jpg";
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat dst = new Mat();

      // Applying color map to an image
      Imgproc.applyColorMap(src, dst, Imgproc.COLORMAP_HOT);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap25/colormap_hot.jpg", dst);
      System.out.println("Image processed");
   }
}

假設上面程式中指定的輸入影像為color_input.jpg

Color Input

輸出

執行上述程式後,您將獲得以下輸出 −

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Color Output

更多操作

除了前面示例中演示的COLORMAP_HOT之外,OpenCV還提供了各種其他型別的顏色對映。所有這些型別都由Imgproc類的預定義靜態欄位(固定值)表示。

您可以透過將相應的預定義值傳遞給applyColorMap()方法的colormap引數來選擇所需的顏色對映型別。

Imgproc.applyColorMap(src, dst, Imgproc.COLORMAP_HOT);

以下是表示各種顏色對映型別及其相應輸出的值。

操作和描述 輸出
COLORMAP_AUTUMN COLORMAP_AUTUMN
COLORMAP_BONE COLORMAP_BONE
COLORMAP_COOL COLORMAP_COOL
COLORMAP_HOT COLORMAP_HOT
COLORMAP_HSV COLORMAP_HSV
COLORMAP_JET COLORMAP_JET
COLORMAP_OCEAN COLORMAP_OCEAN
COLORMAP_PARULA COLORMAP_PARULA
COLORMAP_PINK COLORMAP_PINK
COLORMAP_RAINBOW COLORMAP_RAINBOW
COLORMAP_SPRING COLORMAP_SPRING
COLORMAP_SUMMER COLORMAP_SUMMER
COLORMAP_WINTER COLORMAP_WINTER

OpenCV - Canny 邊緣檢測

Canny邊緣檢測用於檢測影像中的邊緣。它接受灰度影像作為輸入,並使用多階段演算法。

您可以使用imgproc類的Canny()方法對影像執行此操作,以下是此方法的語法。

Canny(image, edges, threshold1, threshold2)

此方法接受以下引數 −

  • image − 表示此操作的源(輸入影像)的Mat物件。

  • edges − 表示此操作的目標(邊緣)的Mat物件。

  • threshold1 − 一個double型別的變數,表示滯後過程的第一個閾值。

  • threshold2 − 一個double型別的變數,表示滯後過程的第二個閾值。

示例

下面的程式是一個示例,演示瞭如何在給定影像上執行Canny邊緣檢測操作。

import org.opencv.core.Core;
import org.opencv.core.Mat;

import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class CannyEdgeDetection {
   public static void main(String args[]) throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

      // Reading the Image from the file and storing it in to a Matrix object
      String file = "E:/OpenCV/chap17/canny_input.jpg";

      // Reading the image
      Mat src = Imgcodecs.imread(file);

      // Creating an empty matrix to store the result
      Mat gray = new Mat();

      // Converting the image from color to Gray
      Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);
      Mat edges = new Mat();

      // Detecting the edges
      Imgproc.Canny(gray, edges, 60, 60*3);

      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap17/canny_output.jpg", edges);
      System.out.println("Image Loaded");
   } 
}

假設上面程式中指定的輸入影像為canny_input.jpg

Canny Input

輸出

執行上述程式後,您將獲得以下輸出 −

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Canny Output

OpenCV - Hough 線變換

您可以透過使用Imgproc類的HoughLines()方法應用霍夫變換技術來檢測給定影像的形狀。以下是此方法的語法。

HoughLines(image, lines, rho, theta, threshold)

此方法接受以下引數 −

  • image − 表示源(輸入)影像的Mat類物件。

  • lines − 一個儲存儲存線的引數 (r, Φ) 的向量的Mat類物件。

  • rho − 一個double型別的變數,表示引數r的解析度(以畫素為單位)。

  • theta − 一個double型別的變數,表示引數Φ的解析度(以弧度為單位)。

  • threshold − 一個整型變數,表示檢測一條線的最小交叉點數量。

示例

下面的程式演示瞭如何在給定影像中檢測霍夫線。

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;

import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class HoughlinesTest {
   public static void main(String args[]) throws Exception {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file = "E:/OpenCV/chap21/hough_input.jpg";

      // Reading the image
      Mat src = Imgcodecs.imread(file,0);

      // Detecting edges of it
      Mat canny = new Mat();
      Imgproc.Canny(src, canny, 50, 200, 3, false);

      // Changing the color of the canny
      Mat cannyColor = new Mat();
      Imgproc.cvtColor(canny, cannyColor, Imgproc.COLOR_GRAY2BGR);

      // Detecting the hough lines from (canny)
      Mat lines = new Mat();
      Imgproc.HoughLines(canny, lines, 1, Math.PI/180, 100);

      System.out.println(lines.rows());
      System.out.println(lines.cols());

      // Drawing lines on the image
      double[] data;
      double rho, theta;
      Point pt1 = new Point();
      Point pt2 = new Point();
      double a, b;
      double x0, y0;
      
      for (int i = 0; i < lines.cols(); i++) {
         data = lines.get(0, i);
         rho = data[0];
         theta = data[1];
         
         a = Math.cos(theta);
         b = Math.sin(theta);
         x0 = a*rho;
         y0 = b*rho;
         
         pt1.x = Math.round(x0 + 1000*(-b));
         pt1.y = Math.round(y0 + 1000*(a));
         pt2.x = Math.round(x0 - 1000*(-b));
         pt2.y = Math.round(y0 - 1000 *(a));
         Imgproc.line(cannyColor, pt1, pt2, new Scalar(0, 0, 255), 6);
      }
      // Writing the image
      Imgcodecs.imwrite("E:/OpenCV/chap21/hough_output.jpg", cannyColor);
          
      System.out.println("Image Processed");
   }
}

假設上面程式中指定的輸入影像為hough_input.jpg

Hough Input

輸出

執行程式後,您將獲得以下輸出:

143 
1 
Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Hough Output

OpenCV - 直方圖均衡化

影像的直方圖顯示了畫素強度值的頻率。在影像直方圖中,X軸顯示灰度強度,Y軸顯示這些強度的頻率。

直方圖均衡化提高了影像的對比度,以擴充套件強度範圍。您可以使用Imgproc類的equalizeHist()方法均衡給定影像的直方圖。以下是此方法的語法。

equalizeHist(src, dst)

此方法接受以下引數 −

  • src − 一個Mat類物件,代表源(輸入)影像。

  • dst − 表示輸出的Mat類物件。(均衡直方圖後獲得的影像)

示例

下面的程式演示瞭如何均衡給定影像的直方圖。

import java.util.ArrayList;
import java.util.List;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class HistoTest {
   public static void main (String[] args) {
      // Loading the OpenCV core library
      System.loadLibrary( Core.NATIVE_LIBRARY_NAME );

      // Reading the Image from the file and storing it in to a Matrix object
      String file ="E:/OpenCV/chap20/histo_input.jpg";

      // Load the image
      Mat img = Imgcodecs.imread(file);

      // Creating an empty matrix
      Mat equ = new Mat();
      img.copyTo(equ);

      // Applying blur
      Imgproc.blur(equ, equ, new Size(3, 3));

      // Applying color
      Imgproc.cvtColor(equ, equ, Imgproc.COLOR_BGR2YCrCb);
      List<Mat> channels = new ArrayList<Mat>();

      // Splitting the channels
      Core.split(equ, channels);

      // Equalizing the histogram of the image
      Imgproc.equalizeHist(channels.get(0), channels.get(0));
      Core.merge(channels, equ);
      Imgproc.cvtColor(equ, equ, Imgproc.COLOR_YCrCb2BGR);

      Mat gray = new Mat();
      Imgproc.cvtColor(equ, gray, Imgproc.COLOR_BGR2GRAY);
      Mat grayOrig = new Mat();
      Imgproc.cvtColor(img, grayOrig, Imgproc.COLOR_BGR2GRAY);

      Imgcodecs.imwrite("E:/OpenCV/chap20/histo_output.jpg", equ);
      System.out.println("Image Processed");
   }
}

假設上面程式中指定的輸入影像為histo_input.jpg

Histo Input

輸出

執行程式後,您將獲得以下輸出:

Image Processed

如果您開啟指定的路徑,您可以觀察到如下所示的輸出影像:

Histo Output
廣告