日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務,提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

OpenCV-Python/ target=_blank class=infotextkey>Python系列教程介紹| 一

前言

OpenCV是計算機視覺中經(jīng)典的專用庫,其支持多語言、跨平臺,功能強大。OpenCV-Python為OpenCV提供了Python接口,使得使用者在Python中能夠調(diào)用C/C++,在保證易讀性和運行效率的前提下,實現(xiàn)所需的功能。OpenCV-Python Tutorials是官方提供的文檔,其內(nèi)容全面、簡單易懂,使得初學者能夠快速上手使用。

2014年段力輝在當時已翻譯過OpenCV3.0,但時隔五年,如今的OpenCV4.1中許多函數(shù)和內(nèi)容已經(jīng)有所更新,因此有必要對該官方文檔再進行一次翻譯。

翻譯過程中難免有所疏漏,如發(fā)現(xiàn)錯誤,希望大家指出,謝謝支持。

OpenCV-Python Tutorials官方文檔:

https://docs.opencv.org/3.4/d6/d00/tutorialpyroot.html

目錄

  • OpenCV簡介:

了解如何在計算機上安裝OpenCV-Python

  • OpenCV中的GUI特性

在這里,您將學習如何顯示和保存圖像和視頻,控制鼠標事件以及創(chuàng)建軌跡欄。

  • 核心操作

在本節(jié)中,您將學習圖像的基本操作、例如像素編輯、幾何變換,代碼優(yōu)化、一些數(shù)學工具等。

  • OpenCV中的圖像處理

在本節(jié)中,您將學習OpenCV內(nèi)部的不同圖像處理函數(shù)。

  • 特征檢測與描述

在本節(jié)中,您將學習有關(guān)特征檢測和描述符的信息

  • 視頻分析

在本部分中,您將學習與對象跟蹤等視頻配合使用的不同技術(shù)。

  • 相機校準和3D重建

在本節(jié)中,我們將學習有關(guān)相機校準,立體成像等的信息。

  • 機器學習

在本節(jié)中,您將學習OpenCV內(nèi)部的不同圖像處理函數(shù)。

  • 計算攝影學

在本節(jié)中,您將學習不同的計算攝影技術(shù)如圖像去噪等。

  • 目標檢測(objdetect模塊)

在本節(jié)中,您將學習目標檢測技術(shù),例如人臉檢測等。

  • OpenCV-Python Binding

在本節(jié)中,我們將了解如何生成OpenCV-Python Binding

OpenCV-Python教程簡介 | 二

OpenCV

OpenCV由Gary Bradsky于1999年在英特爾創(chuàng)立,第一版于2000年問世。Vadim Pisarevsky加入Gary Bradsky,一起管理英特爾的俄羅斯軟件OpenCV團隊。2005年,OpenCV用于Stanley,該車贏得了2005年DARPA挑戰(zhàn)賽的冠軍。后來,在Willow Garage的支持下,它的積極發(fā)展得以繼續(xù),由Gary Bradsky和Vadim Pisarevsky領(lǐng)導了該項目。OpenCV現(xiàn)在支持與計算機視覺和機器學習有關(guān)的多種算法,并且正在日益擴展。

OpenCV支持多種編程語言,例如C++、Python、JAVA等,并且可在windows、linux、OS X、Android和IOS等不同平臺上使用。基于CUDA和OpenCL的高速GPU操作的接口也正在積極開發(fā)中。

OpenCV-Python是用于OpenCV的Python API,結(jié)合了OpenCV C++ API和Python語言的最佳特性。

OpenCV-Python

OpenCV-Python是旨在解決計算機視覺問題的Python專用庫。

Python是由Guido van Rossum發(fā)起的通用編程語言,很快就非常流行,主要是因為它的簡單性和代碼可讀性。它使程序員可以用較少的代碼行表達想法,而不會降低可讀性。

與C/C++之類的語言相比,Python速度較慢。也就是說,可以使用C/C++輕松擴展Python,這使我們能夠用C/C++編寫計算密集型代碼并創(chuàng)建可用作Python模塊的Python包裝器。這給我們帶來了兩個好處:首先,代碼與原始C/C++代碼一樣快(因為它是在后臺運行的實際C++代碼),其次,在Python中比C/C++編寫代碼更容易。OpenCV-Python是原始OpenCV C++實現(xiàn)的Python包裝器。

OpenCV-Python利用了Numpy,這是一個高度優(yōu)化的庫,用于使用MATLAB樣式的語法進行數(shù)值運算。所有OpenCV數(shù)組結(jié)構(gòu)都與Numpy數(shù)組相互轉(zhuǎn)換。這也使與使用Numpy的其他庫(例如SciPy和Matplotlib)的集成變得更加容易。

OpenCV-Python教程

OpenCV引入了一組新的教程,它們將指導您完成OpenCV-Python中可用的各種功能。本指南主要針對OpenCV 3.x版本(盡管大多數(shù)教程也適用于OpenCV 2.x)。

建議先了解Python和Numpy,因為本指南將不介紹它們。要使用OpenCV-Python編寫優(yōu)化的代碼,必須先明白Numpy。

本教程最初由Abid Rahman K.在Alexander Mordvintsev的指導下作為google Summer of Code 2013計劃的一部分啟動。

OpenCV需要您!

由于OpenCV是開放源代碼計劃,因此歡迎所有人為這個庫,文檔和教程做出貢獻。如果您在本教程中發(fā)現(xiàn)任何錯誤(從小的拼寫錯誤到代碼或概念中的嚴重錯誤),請隨時通過在GitHub中

:https://github.com/opencv/opencv 克隆OpenCV 并提交請求請求來更正它。OpenCV開發(fā)人員將檢查您的請求請求,給您重要的反饋,并且(一旦通過審閱者的批準)它將被合并到OpenCV中。然后,您將成為開源貢獻者:-)

隨著新模塊添加到OpenCV-Python中,本教程將不得不進行擴展。如果您熟悉特定的算法,并且可以編寫一個包括算法基本理論和顯示示例用法的代碼的教程,歡迎你這樣做。

記住,我們可以共同使這個項目取得巨大成功!

貢獻者

以下是向OpenCV-Python提交了教程的貢獻者列表。

  1. Alexander Mordvintsev(GSoC-2013 導師)
  2. Abid Rahman K.(GSoC-2013 實習生)

其他資源

  1. Python快速指南- [一小部分Python]:http://swaroopch.com/notes/python/
  2. 基本的Numpy教程:http://wiki.scipy.org/TentativeNumPyTutorial
  3. numpy示例列表:http://wiki.scipy.org/NumpyExampleList
  4. OpenCV文檔:http://docs.opencv.org/
  5. OpenCV論壇:http://answers.opencv.org/questions/

在Fedora中安裝OpenCV-Python | 三

目標

在本教程中我們將學習在你的Fedora系統(tǒng)中設(shè)置OpenCV-Python。針對Fedora 18(64位)和Fedora 19(32位)進行以下步驟。

介紹

可以通過兩種方式在Fedora中安裝OpenCV-Python:1)從fedora存儲庫中可用的預構(gòu)建二進制文件安裝,2)從源代碼進行編譯。在本節(jié)中,我們將同時看到這兩種方法。

另一個重要的事情是所需的其他庫。OpenCV-Python僅需要Numpy(除了其他依賴關(guān)系,我們將在后面看到)。但是在本教程中,我們還使用Matplotlib進行一些簡單而又漂亮的作圖(與OpenCV相比,感覺好多了)。Matplotlib是可選的,但強烈建議安裝。同樣,我們還將看到IPython,這是一個強烈推薦的交互式Python終端。

從預構(gòu)建的二進制文件安裝OpenCV-Python

以root用戶身份在終端中使用以下命令安裝所有軟件包。

$ yum install numpy opencv *

打開Python IDLE(或IPython),然后在Python終端中鍵入以下代碼。

>>> import cv2 as cv
>>> print( cv.__version__ )

如果打印出來的結(jié)果沒有任何錯誤,那就恭喜!你已經(jīng)成功安裝了OpenCV-Python。

這很簡單。但是這里有一個問題。Yum倉庫可能不總是包含最新版本的 OpenCV。例如,在撰寫本教程時,yum 庫包含2.4.5,而最新的 OpenCV 版本是2.4.6。對于 Python API,最新版本總是包含更好的支持。另外,取決于所使用的驅(qū)動程序、ffmpeg、gstreamer軟件包等,相機支持,視頻播放等可能會出現(xiàn)問題。

所以我個人的偏好是下一種方法,即從源代碼編譯。在某個時候,如果你想為OpenCV 做貢獻,你也需要這個。

從源代碼安裝OpenCV

從源代碼編譯起初可能看起來有點復雜,但是一旦你成功了,就沒有什么復雜的了。

首先,我們將安裝一些依賴項。有些是強制性的,有些是可選的。可選的依賴項,如果不需要,可以跳過。

強制依賴

我們需要CMake來配置安裝,GCC進行編譯,Python-develNumpy來創(chuàng)建Python擴展等。

yum install cmake
yum install python-devel numpy
yum install gcc gcc-c++

接下來,我們需要GTK對GUI功能的支持,相機支持(libdc1394,v4l),媒體支持(ffmpeg,gstreamer)等。

yum install gtk2-devel
yum install libdc1394-devel
yum install ffmpeg-devel
yum install gstreamer-plugins-base-devel

可選依賴項

以上依賴關(guān)系足以在你的fedora計算機中安裝OpenCV。但是根據(jù)你的要求,你可能需要一些額外的依賴項。此類可選依賴項的列表如下。你可以跳過或安裝它,取決于你:)

OpenCV附帶了用于圖像格式(例如PNG,JPEG,JPEG2000,TIFF,WebP等)的支持文件。但是它可能有些舊。如果要獲取最新的庫,可以安裝這些格式的開發(fā)文件。

yum install libpng-devel
yum install libjpeg-turbo-devel
yum install jasper-devel
yum install openexr-devel
yum install libtiff-devel
yum install libwebp-devel

幾個OpenCV功能與英特爾的線程構(gòu)建模塊(TBB)并行。但是,如果要啟用它,則需要先安裝TBB。(同樣在使用CMake配置安裝時,請不要忘記設(shè)置-D WITH_TBB = ON。下面更多詳細信息。)

yum install tbb-devel

OpenCV使用另一個Eigen庫來優(yōu)化數(shù)學運算。因此,如果你的系統(tǒng)中裝有Eigen,則可以利用它。(同樣在使用CMake配置安裝時,請不要忘記設(shè)置WITH_EIGEN = ON。下面更多詳細信息。)

yum install eigen3-devel

如果你要構(gòu)建文檔(是的,你可以使用完整的搜索功能以HTML格式在系統(tǒng)中創(chuàng)建OpenCV完整官方文檔的脫機版本,這樣,如果有任何問題,你就不必總是訪問Inte.NET,而且非常快捷!!!),你需要安裝Doxygen(文檔生成工具)。

yum install doxygen

下載OpenCV

接下來,我們必須下載OpenCV。你可以從sourceforge網(wǎng)站:

http://sourceforge.net/projects/opencvlibrary/ 下載最新版本的OpenCV 。然后解壓縮文件夾。

或者,你可以從OpenCV的github存儲庫下載最新的源代碼。(如果你想為OpenCV做出貢獻,請選擇此項。它始終使你的OpenCV保持最新狀態(tài))。為此,你需要先安裝Git

yum install git
git clone https://github.com/opencv/opencv.git

它將在主目錄(或你指定的目錄)中創(chuàng)建一個文件夾OpenCV。克隆可能需要一些時間,具體取決于你的Internet網(wǎng)絡。

現(xiàn)在打開一個終端窗口,然后導航到下載的OpenCV文件夾。創(chuàng)建一個新的構(gòu)建文件夾并導航到它。

mkdir build
cd build

配置和安裝

現(xiàn)在,我們已經(jīng)安裝了所有必需的依賴項,讓我們安裝OpenCV。必須使用CMake配置安裝。它指定要安裝的模塊,安裝路徑,要使用的其他庫,是否要編譯的文檔和示例等。下面的命令通常用于配置(從build文件夾執(zhí)行)。

cmake -D CMAKE_BUILD_TYPE = RELEASE -D CMAKE_INSTALL_PREFIX = / usr / local ..

它指定構(gòu)建類型為“發(fā)布模式”,安裝路徑為/usr/local。在每個選項之前標志-D,在最后觀察標志..。簡而言之,這是一種格式:

cmake [-D <flag>] [-D <flag>] ..

你可以指定任意數(shù)量的標志,但是每個標志前面應帶有-D。

因此,在本教程中,我們將安裝具有TBB和Eigen支持的OpenCV。我們還構(gòu)建了文檔,但是不包括性能測試和構(gòu)建示例。我們還會禁用與GPU相關(guān)的模塊(因為我們使用的是OpenCV-Python,因此我們不需要與GPU相關(guān)的模塊。這為我們節(jié)省了一些時間)。

(以下所有命令都可以在單個cmake語句中完成,但為了便于理解,此處將其拆分。)

  • 啟用TBB和Eigen支持:cmake -D WITH_TBB=ON -D WITH_EIGEN=ON ..
  • 啟用文檔并禁用測試和示例cmake -D BUILD_DOCS=ON -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF -D BUILD_EXAMPLES=OFF ..
  • 禁用所有與GPU相關(guān)的模塊。cmake -D WITH_OPENCL=OFF -D BUILD_opencv_gpu=OFF -D BUILD_opencv_gpuarithm=OFF -D BUILD_opencv_gpubgsegm=OFF -D BUILD_opencv_gpucodec=OFF -D BUILD_opencv_gpufeatures2d=OFF -D BUILD_opencv_gpufilters=OFF -D BUILD_opencv_gpuimgproc=OFF -D BUILD_opencv_gpulegacy=OFF -D BUILD_opencv_gpuoptflow=OFF -D BUILD_opencv_gpustereo=OFF -D BUILD_opencv_gpuwarping=OFF ..
  • 設(shè)置安裝路徑和構(gòu)建類型cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local ..每次輸入cmake語句時,它都會打印出結(jié)果配置設(shè)置。在完成的最終設(shè)置中,請確保填寫以下字段(以下是我獲得的一些重要配置)。這些字段也應在你的系統(tǒng)中適當填寫。否則將會發(fā)生一些問題。因此,請檢查你是否正確執(zhí)行了上述步驟。
...
-- GUI:
-- GTK+ 2.x: YES (ver 2.24.19)
-- GThread : YES (ver 2.36.3)
-- Video I/O:
-- DC1394 2.x: YES (ver 2.2.0)
-- FFMPEG: YES
-- codec: YES (ver 54.92.100)
-- format: YES (ver 54.63.104)
-- util: YES (ver 52.18.100)
-- swscale: YES (ver 2.2.100)
-- gentoo-style: YES
-- GStreamer:
-- base: YES (ver 0.10.36)
-- video: YES (ver 0.10.36)
-- App: YES (ver 0.10.36)
-- riff: YES (ver 0.10.36)
-- pbutils: YES (ver 0.10.36)
-- V4L/V4L2: Using libv4l (ver 1.0.0)
-- Other third-party libraries:
-- Use Eigen: YES (ver 3.1.4)
-- Use TBB: YES (ver 4.0 interface 6004)
-- Python:
-- Interpreter: /usr/bin/python2 (ver 2.7.5)
-- Libraries: /lib/libpython2.7.so (ver 2.7.5)
-- numpy: /usr/lib/python2.7/site-packages/numpy/core/include (ver 1.7.1)
-- packages path: lib/python2.7/site-packages
...

還有許多其他標志和設(shè)置。它留給你以作進一步的探索。

現(xiàn)在,你可以使用make命令構(gòu)建文件,并使用make install命令進行安裝。make install應該以root身份執(zhí)行。

make
su
make install

安裝結(jié)束。所有文件都安裝在/usr/local/文件夾中。但是要使用它,你的Python應該能夠找到OpenCV模塊。你有兩個選擇。

  1. 將模塊移動到Python路徑中的任何文件夾:可以通過在Python終端中輸入import sys; print(sys.path)來找到Python路徑。它將打印出許多位置。將/usr/local/lib/python2.7/site-packages/cv2.so移至該文件夾中的任何一個。例如, su mv /usr/local/lib/python2.7/site-packages/cv2.so /usr/lib/python2.7/site-packages 但是,每次安裝OpenCV時都必須這樣做。
  2. 將/usr/local/lib/python2.7/site-packages添加到PYTHON_PATH:只需執(zhí)行一次。只需打開/.bashrc并向其添加以下行,然后注銷并返回即可。 export PYTHONPATH=$PYTHONPATH:/usr/local/lib/python2.7/site-packages 至此,OpenCV安裝完成。打開終端,然后嘗試import cv2 as cv。

要構(gòu)建文檔,只需輸入以下命令:

make doxygen

然后打開

opencv/build/doc/doxygen/html/index.html并將其添加到瀏覽器中。

在Ubuntu中安裝OpenCV-Python | 四

在本教程中,我們將學習在Ubuntu System中設(shè)置OpenCV-Python。以下步驟針對Ubuntu 16.04和18.04(均為64位)進行了測試。

可以通過兩種方式在Ubuntu中安裝OpenCV-Python:

  • 從Ubuntu存儲庫中可用的預構(gòu)建二進制文件安裝
  • 從源代碼編譯。在本節(jié)中,我們將同時看到兩者。

另一個重要的事情是所需的其他庫。OpenCV-Python僅需要Numpy(除了其他依賴關(guān)系,我們將在后面看到)。但是在本教程中,我們還使用Matplotlib進行一些簡單而又漂亮的繪圖目的(與OpenCV相比,我感覺好多了)。Matplotlib是可選的,但強烈建議使用。同樣,我們還將看到IPython,這是一個強烈推薦的交互式Python終端。

從預構(gòu)建的二進制文件安裝OpenCV-Python

僅用于編程和開發(fā)OpenCV應用程序時,此方法最有效。

在終端(以root用戶身份)中使用以下命令安裝

python-opencv:https://packages.ubuntu.com/trusty/python-opencv軟件包。

$ sudo apt-get install python-opencv

打開Python IDLE(或IPython),然后在Python終端中鍵入以下代碼。

import cv2 as cv
print(cv.__version__)

如果打印出來的結(jié)果沒有任何錯誤,那就恭喜!你已經(jīng)成功安裝了OpenCV-Python。

這看起很容易,但也可能出現(xiàn)問題。Apt存儲庫不一定總是包含最新版本的OpenCV。例如,在編寫本教程時,apt存儲庫包含2.4.8,而最新的OpenCV版本是3.x。關(guān)于Python API,最新版本將始終包含更好的支持和最新的錯誤修復。

因此,要獲取最新的源代碼,首選方法是從源代碼進行編譯。同樣在某個時間點,如果你想為OpenCV做出貢獻,則將通過這種方式。

從源代碼構(gòu)建OpenCV

首先,從源代碼進行編譯似乎有些復雜,但是一旦成功完成,就沒有什么復雜的了。

首先,我們將安裝一些依賴項。有些是必需的,有些是可選的。如果不想,可以跳過可選的依賴項。

所需的構(gòu)建依賴項

我們需要CMake來配置安裝,需要GCC進行編譯,需要Python-develNumpy來構(gòu)建Python依賴項等。

sudo apt-get install cmake
sudo apt-get install gcc g++

支持python2:sudo apt-get install python-dev python-numpy

支持python3:sudo apt-get install python3-dev python3-numpy

接下來,我們需要GUI功能的GTK支持,相機支持(v4l),媒體支持(ffmpeg,gstreamer)等。

sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev

支持gtk2:sudo apt-get install libgtk2.0-dev

支持gtk3:sudo apt-get install libgtk-3-dev

可選依賴項

以上依賴關(guān)系足以在你的Ubuntu計算機中安裝OpenCV。但是根據(jù)你的需求,你可能需要一些額外的依賴項。此類可選依賴項的列表如下。你可以跳過或安裝它,取決于你:)

OpenCV附帶了用于圖像格式(例如PNG,JPEG,JPEG2000,TIFF,WebP等)的支持文件。但是它可能有些舊。如果要獲取最新的庫,可以為這些格式的系統(tǒng)庫安裝開發(fā)文件。

sudo apt-get install libpng-dev
sudo apt-get install libjpeg-dev
sudo apt-get install libopenexr-dev
sudo apt-get install libtiff-dev
sudo apt-get install libwebp-dev

注意
如果你使用的是Ubuntu 16.04,則還可以安裝libjasper-dev以添加對JPEG2000格式的系統(tǒng)級別支持。

下載OpenCV

要從OpenCV的GitHub

Repository:https://github.com/opencv/opencv下載最新的源代碼。 (如果你想為OpenCV做出貢獻,請選擇此項。為此,你需要先安裝Git

$ sudo apt-get install git
$ git clone https://github.com/opencv/opencv.git

它將在當前目錄中創(chuàng)建一個文件夾"opencv"。下載可能需要一些時間,具體取決于你的Internet網(wǎng)絡。

現(xiàn)在打開一個終端窗口,并導航到下載的"opencv"文件夾。創(chuàng)建一個新的"build"文件夾并導航到它。

$ mkdir build
$ cd build

配置和安裝

現(xiàn)在我們有了所有必需的依賴項,讓我們安裝OpenCV。必須使用CMake配置安裝。它指定要安裝的模塊,安裝路徑,要使用的其他庫,是否要編譯的文檔和示例等。大多數(shù)工作都是使用配置良好的默認參數(shù)自動完成的。

以下命令通常用于配置OpenCV庫構(gòu)建(從構(gòu)建文件夾執(zhí)行):$ cmake ../

OpenCV的默認默認設(shè)置為"Release"構(gòu)建類型,安裝路徑為/usr/local。有關(guān)CMake選項的更多信息,請參考OpenCV C++編譯指南

:https://docs.opencv.org/4.1.2/d7/d9f/tutoriallinuxinstall.html

你應該在CMake輸出中看到以下幾行(它們意味著正確找到了Python):

-- Python 2:
-- Interpreter: /usr/bin/python2.7 (ver 2.7.6)
-- Libraries: /usr/lib/x86_64-linux-gnu/libpython2.7.so (ver 2.7.6)
-- numpy: /usr/lib/python2.7/dist-packages/numpy/core/include (ver 1.8.2)
-- packages path: lib/python2.7/dist-packages
--
-- Python 3:
-- Interpreter: /usr/bin/python3.4 (ver 3.4.3)
-- Libraries: /usr/lib/x86_64-linux-gnu/libpython3.4m.so (ver 3.4.3)
-- numpy: /usr/lib/python3/dist-packages/numpy/core/include (ver 1.8.2)
-- packages path: lib/python3.4/dist-packages

現(xiàn)在,使用make命令構(gòu)建文件,然后使用make install命令安裝文件。

$ make
# sudo make install

安裝結(jié)束。所有文件都安裝在/usr/local/文件夾中。打開終端,然后嘗試導入cv2。

import cv2 as cv
print(cv.__version__)

在Windows中安裝OpenCV-Python |五

目標

在本教程中,我們將學習在你的Windows系統(tǒng)中設(shè)置OpenCV-Python。

下面的步驟在裝有Visual Studio 2010和Visual Studio 2012的Windows 7-64位計算機上進行了測試。屏幕截圖展示的是VS2012。

從預編譯的二進制文件安裝OpenCV

  1. 下面的Python軟件包將被下載并安裝到其默認位置。 Python的3.X(3.4+)或Python 2.7.x從這里下載:https://www.python.org/downloads/。 Numpy包(例如使用pip install numpy命令下載)。 Matplotlib( pip install matplotlib)(Matplotlib是可選的,但推薦它,因為我們使用了很多在我們的教程)。
  2. 將所有軟件包安裝到其默認位置。C:/Python27/如果使用Python 2.7,將安裝Python。
  3. 安裝后,打開Python IDLE。輸入import numpy并確保Numpy運行正常。
  4. 從GitHub:https://github.com/opencv/opencv/releases 或SourceForge網(wǎng)站:https://sourceforge.net/projects/opencvlibrary/files/ 下載最新的OpenCV版本,然后雙擊將其解壓縮。
  5. 轉(zhuǎn)到opencv/build/python/2.7文件夾。
  6. cv2.pyd復制到C:/Python27/lib/site-packages
  7. 打開Python IDLE,然后在Python終端中鍵入以下代碼。
>>> import cv2 as cv
>>> print( cv.__version__ )

如果打印出來的結(jié)果沒有任何錯誤,那就恭喜!你已經(jīng)成功安裝了OpenCV-Python。

從源代碼構(gòu)建OpenCV

  1. 下載并安裝Visual Studio和CMake。 Visual Studio 2012:http://go.microsoft.com/?linkid=9816768 CMake:https://cmake.org/download/
  2. 將必要的Python軟件包下載并安裝到其默認位置 Python Numpy

注意
在這種情況下,我們使用的是32位Python軟件包二進制文件。但是,如果要將OpenCV用于x64,則將安裝Python軟件包的64位二進制文件。問題在于,沒有Numpy的官方64位二進制文件。你必須自行構(gòu)建。為此,你必須使用與構(gòu)建Python相同的編譯器。啟動Python IDLE時,它會顯示編譯器詳細信息。你可以在此處:

http://stackoverflow.com/q/2676763/1134940 獲得更多信息。因此,你的系統(tǒng)必須具有相同的Visual Studio版本并從源代碼構(gòu)建Numpy。

擁有64位Python軟件包的另一種方法是使用來自第三方(如Anaconda:

http://www.continuum.io/downloads、 Enthought:https://www.enthought.com/downloads/)等現(xiàn)成Python發(fā)行版。它的大小會更大,但可以滿足你的所有需求。一切都在一個外殼中。你也可以下載32位版本。

  1. 確保Python和Numpy正常運行。
  2. 下載OpenCV源代碼。它可以來自Sourceforge:http://sourceforge.net/projects/opencvlibrary/(官方發(fā)行版)或來自Github:https://github.com/opencv/opencv (最新源)。
  3. 將其解壓縮到一個文件夾中,在opencv中創(chuàng)建一個新的文件夾。
  4. 打開CMake-gui(Start>All Programs> CMake-gui)
  5. 如下填寫字段(請參見下圖):

a. 單擊Browse Source然后找到opencv文件夾。

b. 單擊Browse Build然后找到我們創(chuàng)建的構(gòu)建文件夾。

c. 點擊Configure

OpenCV-Python教程上篇

 

d. 它將打開一個新窗口以選擇編譯器。選擇適當?shù)木幾g器(此處為Visual Studio 11),然后單擊Finish

OpenCV-Python教程上篇

 

e. 等待分析完成。

  1. 你將看到所有字段都標記為紅色。單擊WITH字段將其展開。它決定了你需要哪些額外的功能。因此,請標記適當?shù)淖侄巍R娤聢D:
OpenCV-Python教程上篇

 

  1. 現(xiàn)在,單擊BUILD字段以將其展開。前幾個字段配置構(gòu)建方法。見下圖:
OpenCV-Python教程上篇

 

  1. 其余字段指定要構(gòu)建的模塊。由于OpenCV-Python尚不支持GPU模塊,因此可以完全避免使用它以節(jié)省時間(但是如果使用它們,則將其保留在此處)。見下圖:
OpenCV-Python教程上篇

 

  1. 現(xiàn)在單擊 ENABLE字段將其展開。確保未選中ENABLESOLUTIONFOLDERS(Visual Studio Express版本不支持解決方案文件夾)。見下圖:
OpenCV-Python教程上篇

 

  1. 還要確保在PYTHON字段中,所有內(nèi)容都已填充。(忽略PYTHONDEBUGLIBRARY)。見下圖:
OpenCV-Python教程上篇

 

  1. 最后,單擊Generate按鈕。
  2. 現(xiàn)在轉(zhuǎn)到我們的opencv / build文件夾。在那里你將找到OpenCV.sln文件。用Visual Studio打開它。
  3. 將構(gòu)建模式檢查為Release而不是Debug
  4. 在解決方案資源管理器中,右鍵單擊Solution(或ALL_BUILD)并進行構(gòu)建。需要一些時間才能完成。
  5. 再次,右鍵單擊INSTALL并進行構(gòu)建。現(xiàn)在將安裝OpenCV-Python。
OpenCV-Python教程上篇

 

  1. 打開Python IDLE,然后輸入import cv2 as cv。如果沒有錯誤,則說明已正確安裝。

注意
我們沒有安裝其他支持如TBB、Eigen、Qt、Documentation等。在這里很難解釋清楚。我們將添加更詳細的視頻,或者你可以隨意修改。

練習題

如果你有Windows計算機,請從源代碼編譯OpenCV。做各種各樣極客。如果遇到任何問題,請訪問OpenCV論壇并描述你的問題。

OpenCV-Python 讀取顯示圖像 | 六

目標

  • 在這里,你將學習如何讀取圖像,如何顯示圖像以及如何將其保存回去
  • 你將學習以下功能:cv.imread()cv.imshow()cv.imwrite()
  • (可選)你將學習如何使用Matplotlib顯示圖像

使用OpenCV

讀取圖像

使用cv.imread()函數(shù)讀取圖像。圖像應該在工作目錄或圖像的完整路徑應給出。

第二個參數(shù)是一個標志,它指定了讀取圖像的方式。

  • cv.IMREAD_COLOR: 加載彩色圖像。任何圖像的透明度都會被忽視。它是默認標志。
  • cv.IMREAD_GRAYSCALE:以灰度模式加載圖像
  • cv.IMREAD_UNCHANGED:加載圖像,包括alpha通道

注意
除了這三個標志,你可以分別簡單地傳遞整數(shù)1、0或-1。

請參見下面的代碼:

import numpy as np
import cv2 as cv

#加載彩色灰度圖像
img = cv.imread('messi5.jpg',0)

注意

即使圖像路徑錯誤,它也不會引發(fā)任何錯誤,但是print(img)會給出None

顯示圖像

使用函數(shù)cv.imshow()在窗口中顯示圖像。窗口自動適合圖像尺寸。

第一個參數(shù)是窗口名稱,它是一個字符串。第二個參數(shù)是我們的對象。你可以根據(jù)需要創(chuàng)建任意多個窗口,但可以使用不同的窗口名稱。

cv.imshow('image',img)
cv.waitKey(0)
cv.destroyAllWindows()

窗口的屏幕截圖如下所示(在Fedora-Gnome機器中):

OpenCV-Python教程上篇

 

cv.waitKey()是一個鍵盤綁定函數(shù)。其參數(shù)是以毫秒為單位的時間。該函數(shù)等待任何鍵盤事件指定的毫秒。如果您在這段時間內(nèi)按下任何鍵,程序?qū)⒗^續(xù)運行。如果0被傳遞,它將無限期地等待一次敲擊鍵。它也可以設(shè)置為檢測特定的按鍵,例如,如果按下鍵 a 等,我們將在下面討論。

注意
除了鍵盤綁定事件外,此功能還處理許多其他GUI事件,因此你必須使用它來實際顯示圖像。

cv.destroyAllWindows()只會破壞我們創(chuàng)建的所有窗口。如果要銷毀任何特定的窗口,請使用函數(shù) cv.destroyWindow()在其中傳遞確切的窗口名稱作為參數(shù)。

注意
在特殊情況下,你可以創(chuàng)建一個空窗口,然后再將圖像加載到該窗口。在這種情況下,你可以指定窗口是否可調(diào)整大小。這是通過功能cv.namedWindow()完成的。默認情況下,該標志為cv.WINDOW_AUTOSIZE。但是,如果將標志指定為cv.WINDOW_NORMAL,則可以調(diào)整窗口大小。當圖像尺寸過大以及向窗口添加跟蹤欄時,這將很有幫助。

請參見下面的代碼:

cv.namedWindow('image',cv.WINDOW_NORMAL)
cv.imshow('image',img)
cv.waitKey(0)
cv.destroyAllWindows()

寫入圖像

使用函數(shù)cv.imwrite()保存圖像。

第一個參數(shù)是文件名,第二個參數(shù)是要保存的圖像。cv.imwrite('messigray.png',img)

這會將圖像以PNG格式保存在工作目錄中。

總結(jié)

在下面的程序中,以灰度加載圖像,顯示圖像,按s保存圖像并退出,或者按ESC鍵直接退出而不保存。

import numpy as np
import cv2 as cv
img = cv.imread('messi5.jpg',0)
cv.imshow('image',img)
k = cv.waitKey(0)
if k == 27: # 等待ESC退出
 cv.destroyAllWindows()
elif k == ord('s'): # 等待關(guān)鍵字,保存和退出
 cv.imwrite('messigray.png',img)
 cv.destroyAllWindows()

注意

如果使用的是64位計算機,則必須k = cv.waitKey(0)按如下所示修改行:k = cv.waitKey(0) & 0xFF

使用Matplotlib

Matplotlib是Python的繪圖庫,可為你提供多種繪圖方法。你將在接下來的文章中看到它們。在這里,你將學習如何使用Matplotlib顯示圖像。你可以使用Matplotlib縮放圖像,保存圖像等。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([]) # 隱藏 x 軸和 y 軸上的刻度值
plt.show()

窗口的屏幕截圖如下所示:

OpenCV-Python教程上篇

 

還可以看看

Matplotlib中提供了許多繪圖選項。請參考Matplotlib文檔以獲取更多詳細信息。

注意

OpenCV加載的彩色圖像處于BGR模式。但是Matplotlib以RGB模式顯示。因此,如果使用OpenCV讀取彩色圖像,則Matplotlib中將無法正確顯示彩色圖像。有關(guān)更多詳細信息,請參見練習。

其他資源

  1. Matplotlib繪圖樣式和功能:http://matplotlib.org/api/pyplot_api.html

練習題

  1. 當你嘗試在OpenCV中加載彩色圖像并將其顯示在Matplotlib中時,存在一些問題。閱讀此討論:http://stackoverflow.com/a/15074748/1134940)并理解它。

OpenCV-Python 讀取顯示視頻 | 七

目標

  • 學習讀取視頻,顯示視頻和保存視頻。
  • 學習從相機捕捉并顯示它。
  • 你將學習以下功能:cv.VideoCapture(),cv.VideoWriter()

從相機中讀取視頻

通常情況下,我們必須用攝像機捕捉實時畫面。提供了一個非常簡單的界面。讓我們從攝像頭捕捉一段視頻(我使用的是我筆記本電腦內(nèi)置的網(wǎng)絡攝像頭) ,將其轉(zhuǎn)換成灰度視頻并顯示出來。只是一個簡單的任務開始。

要捕獲視頻,你需要創(chuàng)建一個 VideoCapture 對象。它的參數(shù)可以是設(shè)備索引或視頻文件的名稱。設(shè)備索引就是指定哪個攝像頭的數(shù)字。正常情況下,一個攝像頭會被連接(就像我的情況一樣)。所以我簡單地傳0(或-1)。你可以通過傳遞1來選擇第二個相機,以此類推。在此之后,你可以逐幀捕獲。但是在最后,不要忘記釋放俘虜。

import numpy as np
import cv2 as cv
cap = cv.VideoCapture(0)
if not cap.isOpened():
 print("Cannot open camera")
 exit()
while True:
 # 逐幀捕獲
 ret, frame = cap.read()
 # 如果正確讀取幀,ret為True
 if not ret:
 print("Can't receive frame (stream end?). Exiting ...")
 break
 # 我們在框架上的操作到這里
 gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
 # 顯示結(jié)果幀e
 cv.imshow('frame', gray)
 if cv.waitKey(1) == ord('q'):
 break
# 完成所有操作后,釋放捕獲器
cap.release()
cv.destroyAllWindows()

cap.read()返回布爾值(True/ False)。如果正確讀取了幀,它將為True。因此,你可以通過檢查此返回值來檢查視頻的結(jié)尾。

有時,cap可能尚未初始化捕獲。在這種情況下,此代碼顯示錯誤。你可以通過cap.isOpened()方法檢查它是否已初始化。如果是True,那么確定。否則,使用cap.open()打開它。

你還可以使用cap.get(propId)方法訪問該視頻的某些功能,其中propId是0到18之間的一個數(shù)字。每個數(shù)字表示視頻的屬性(如果適用于該視頻),并且可以顯示完整的詳細信息在這里看到:cv::VideoCapture::get()。其中一些值可以使用cap.set(propId,value)進行修改。value是你想要的新值。

例如,我可以通過cap.get(cv.CAP_PROP_FRAME_WIDTH)和cap.get(cv.CAP_PROP_FRAME_HEIGHT)檢查框架的寬度和高度。默認情況下,它的分辨率為640x480。但我想將其修改為320x240。只需使用和即可。ret = cap.set(cv.CAP_PROP_FRAME_WIDTH,320) and ret = cap.set(cv.CAP_PROP_FRAME_HEIGHT,240).

注意
如果出現(xiàn)錯誤,請確保使用任何其他相機應用程序(例如Linux中的Cheese)都可以正常使用相機。

從文件播放視頻

它與從相機捕獲相同,只是用視頻文件名更改攝像機索引。另外,在顯示框架時,請使用適當?shù)臅r間cv.waitKey()。如果太小,則視頻將非常快,而如果太大,則視頻將變得很慢(嗯,這就是顯示慢動作的方式)。正常情況下25毫秒就可以了。

import numpy as np
import cv2 as cv
cap = cv.VideoCapture('vtest.avi')
while cap.isOpened():
 ret, frame = cap.read()
 # 如果正確讀取幀,ret為True
 if not ret:
 print("Can't receive frame (stream end?). Exiting ...")
 break
 gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
 cv.imshow('frame', gray)
 if cv.waitKey(1) == ord('q'):
 break
cap.release()
cv.destroyAllWindows()

注意
確保安裝了正確的 ffmpeg 或 gstreamer 版本。有時,使用視頻捕獲(Video Capture)是一件令人頭疼的事情,主要原因是錯誤地安裝了 ffmpeg / gstreamer。

保存視頻

所以我們捕捉一個視頻,一幀一幀地處理,我們想要保存這個視頻。對于圖像,它非常簡單,只需使用 cv.imwrite()。這里還需要做一些工作。

這次我們創(chuàng)建一個 VideoWriter 對象。我們應該指定輸出文件名(例如: output.avi)。然后我們應該指定 FourCC 代碼(詳見下一段)。然后傳遞幀率的數(shù)量和幀大小。最后一個是顏色標志。如果為 True,編碼器期望顏色幀,否則它與灰度幀一起工作。

FourCC:

http://en.wikipedia.org/wiki/FourCC 是用于指定視頻編解碼器的4字節(jié)代碼。可用代碼列表可在fourcc.org中:http://www.fourcc.org/codecs.php 找到。它取決于平臺。遵循編解碼器對我來說效果很好。

  • 在Fedora中:DIVX,XVID,MJPG,X264,WMV1,WMV2。(最好使用XVID。MJPG會生成大尺寸的視頻。X264會生成非常小的尺寸的視頻)
  • 在Windows中:DIVX(尚待測試和添加)
  • 在OSX中:MJPG(.mp4),DIVX(.avi),X264(.mkv)。

FourCC代碼作為MJPG的cv.VideoWriter_fourcc('M','J','P','G')or cv.VideoWriter_fourcc(*'MJPG')傳遞。

在從攝像機捕獲的代碼下面,沿垂直方向翻轉(zhuǎn)每一幀并保存。

import numpy as np
import cv2 as cv
cap = cv.VideoCapture(0)
# 定義編解碼器并創(chuàng)建VideoWriter對象
fourcc = cv.VideoWriter_fourcc(*'XVID')
out = cv.VideoWriter('output.avi', fourcc, 20.0, (640, 480))
while cap.isOpened():
 ret, frame = cap.read()
 if not ret:
 print("Can't receive frame (stream end?). Exiting ...")
 break
 frame = cv.flip(frame, 0)
 # 寫翻轉(zhuǎn)的框架
 out.write(frame)
 cv.imshow('frame', frame)
 if cv.waitKey(1) == ord('q'):
 break
# 完成工作后釋放所有內(nèi)容
cap.release()
out.release()
cv.destroyAllWindows()

OpenCV-Python 繪圖功能 | 八

目標

  • 學習使用OpenCV繪制不同的幾何形狀
  • 您將學習以下功能:cv.line()cv.circle()cv.rectangle()cv.ellipse()cv.putText()等。

代碼

在上述所有功能中,您將看到一些常見的參數(shù),如下所示:

  • img:您要繪制形狀的圖像
  • color:形狀的顏色。對于BGR,將其作為元組傳遞,例如:(255,0,0)對于藍色。對于灰度,只需傳遞標量值即可。
  • 厚度:線或圓等的粗細。如果對閉合圖形(如圓)傳遞-1 ,它將填充形狀。默認厚度= 1
  • lineType:線的類型,是否為8連接線,抗鋸齒線等。默認情況下,為8連接線。cv.LINE_AA給出了抗鋸齒的線條,看起來非常適合曲線。

畫線

要繪制一條線,您需要傳遞線的開始和結(jié)束坐標。我們將創(chuàng)建一個黑色圖像,并從左上角到右下角在其上繪制一條藍線。

import numpy as np
import cv2 as cv
# 創(chuàng)建黑色的圖像
img = np.zeros((512,512,3), np.uint8)
# 繪制一條厚度為5的藍色對角線
cv.line(img,(0,0),(511,511),(255,0,0),5)

畫矩形

要繪制矩形,您需要矩形的左上角和右下角。這次,我們將在圖像的右上角繪制一個綠色矩形。

cv.rectangle(img,(384,0),(510,128),(0,255,0),3)

畫圓圈

要繪制一個圓,需要其中心坐標和半徑。我們將在上面繪制的矩形內(nèi)繪制一個圓。

cv.circle(img,(447,63), 63, (0,0,255), -1)

畫橢圓

要繪制橢圓,我們需要傳遞幾個參數(shù)。一個參數(shù)是中心位置(x,y)。下一個參數(shù)是軸長度(長軸長度,短軸長度)。angle是橢圓沿逆時針方向旋轉(zhuǎn)的角度。startAngle和endAngle表示從主軸沿順時針方向測量的橢圓弧的開始和結(jié)束。即給出0和360給出完整的橢圓。有關(guān)更多詳細信息,請參閱cv.ellipse的文檔。下面的示例在圖像的中心繪制一個橢圓形。

cv.ellipse(img,(256,256),(100,50),0,0,180,255,-1)

畫多邊形

要繪制多邊形,首先需要頂點的坐標。將這些點組成形狀為ROWSx1x2的數(shù)組,其中ROWS是頂點數(shù),并且其類型應為int32。在這里,我們繪制了一個帶有四個頂點的黃色小多邊形。

pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
pts = pts.reshape((-1,1,2))
cv.polylines(img,[pts],True,(0,255,255))

注意
如果第三個參數(shù)為False,您將獲得一條連接所有點的折線,而不是閉合形狀。
cv.polylines()可用于繪制多條線。只需創(chuàng)建要繪制的所有線條的列表,然后將其傳遞給函數(shù)即可。所有線條將單獨繪制。與為每條線調(diào)用cv.line相比,繪制一組線是一種更好,更快的方法。

向圖像添加文本:

要將文本放入圖像中,需要指定以下內(nèi)容。

  • 您要寫入的文字數(shù)據(jù)
  • 您要放置它的位置坐標(即數(shù)據(jù)開始的左下角)。
  • 字體類型(檢查cv.putText文檔以獲取受支持的字體)
  • 字體比例(指定字體大小)
  • 常規(guī)的內(nèi)容,例如顏色,厚度,線條類型等。為了獲得更好的外觀,建議使用lineType = cv.LINE_AA

我們將在白色圖像上寫入OpenCV

font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv.LINE_AA)

結(jié)果

現(xiàn)在是時候查看我們繪圖的最終結(jié)果了。正如您在以前的文章中學習的那樣,顯示圖像以查看它。

OpenCV-Python教程上篇

 

練習題

  1. 嘗試使用OpenCV中可用的繪圖功能創(chuàng)建OpenCV的徽標。

OpenCV-Python 鼠標作畫 | 九

目標

  • 了解如何在OpenCV中處理鼠標事件
  • 您將學習以下功能:cv.setMouseCallback()

簡單演示

在這里,我們創(chuàng)建一個簡單的應用程序,無論我們在哪里雙擊它,都可以在圖像上繪制一個圓。

首先,我們創(chuàng)建一個鼠標回調(diào)函數(shù),該函數(shù)在發(fā)生鼠標事件時執(zhí)行。鼠標事件可以是與鼠標相關(guān)的任何事物,例如左鍵按下,左鍵按下,左鍵雙擊等。它為我們提供了每個鼠標事件的坐標(x,y)。通過此活動和地點,我們可以做任何我們喜歡的事情。要列出所有可用的可用事件,請在Python終端中運行以下代碼:

import cv2 as cv
events = [i for i in dir(cv) if 'EVENT' in i]
print( events )

創(chuàng)建鼠標回調(diào)函數(shù)具有特定的格式,該格式在所有地方都相同。它僅在功能上有所不同。因此,我們的鼠標回調(diào)函數(shù)可以做一件事,在我們雙擊的地方繪制一個圓圈。因此,請參見下面的代碼。代碼在注釋中是不言自明的:

import numpy as np
import cv2 as cv
# 鼠標回調(diào)函數(shù)
def draw_circle(event,x,y,flags,param):
 if event == cv.EVENT_LBUTTONDBLCLK:
 cv.circle(img,(x,y),100,(255,0,0),-1)
# 創(chuàng)建一個黑色的圖像,一個窗口,并綁定到窗口的功能
img = np.zeros((512,512,3), np.uint8)
cv.namedWindow('image')
cv.setMouseCallback('image',draw_circle)
while(1):
 cv.imshow('image',img)
 if cv.waitKey(20) & 0xFF == 27:
 break
cv.destroyAllWindows()

更高級的演示

現(xiàn)在我們?nèi)ふ乙粋€更好的應用。在這里,我們通過拖動鼠標來繪制矩形或圓形(取決于我們選擇的模式) ,就像我們在 Paint 應用程序中所做的那樣。所以我們的鼠標回調(diào)函數(shù)有兩部分,一部分用于繪制矩形,另一部分用于繪制圓形。這個具體的例子對于創(chuàng)建和理解一些交互式應用程序非常有幫助,比如目標跟蹤,圖像分割地圖等等。

import numpy as np
import cv2 as cv
drawing = False # 如果按下鼠標,則為真
mode = True # 如果為真,繪制矩形。按 m 鍵可以切換到曲線
ix,iy = -1,-1
# 鼠標回調(diào)函數(shù)
def draw_circle(event,x,y,flags,param):
 global ix,iy,drawing,mode
 if event == cv.EVENT_LBUTTONDOWN:
 drawing = True
 ix,iy = x,y
 elif event == cv.EVENT_MOUSEMOVE:
 if drawing == True:
 if mode == True:
 cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
 else:
 cv.circle(img,(x,y),5,(0,0,255),-1)
 elif event == cv.EVENT_LBUTTONUP:
 drawing = False
 if mode == True:
 cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
 else:
 cv.circle(img,(x,y),5,(0,0,255),-1)

練習題

  1. 在最后一個示例中,我們繪制了填充矩形。您修改代碼以繪制一個未填充的矩形。

OpenCV-Python | 圖像的基本操作 十

目標

  • 訪問像素值并修改它們
  • 訪問圖像屬性
  • 設(shè)置感興趣區(qū)域(ROI)
  • 分割和合并圖像

本節(jié)中的幾乎所有操作都主要與Numpy相關(guān),而不是與OpenCV相關(guān)。要使用OpenCV編寫更好的優(yōu)化代碼,需要Numpy的豐富知識。

(由于大多數(shù)示例都是單行代碼,因此示例在Python終端中顯示)

訪問和修改像素值

加載彩色圖像:

		>>> import numpy as np
>>> import cv2 as cv
>>> img = cv.imread('messi5.jpg')

你可以通過行和列坐標來訪問像素值。對于 BGR 圖像,它返回一個由藍色、綠色和紅色值組成的數(shù)組。對于灰度圖像,只返回相應的灰度。

>>> px = img[100,100]
>>> print( px )
[157 166 200]
# 僅訪問藍色像素
>>> blue = img[100,100,0]
>>> print( blue )
157

可以用相同的方式修改像素值。

>>> img[100,100] = [255,255,255]
>>> print( img[100,100] )
[255 255 255]

警告

Numpy是用于快速數(shù)組計算的優(yōu)化庫。因此,簡單地訪問每個像素值并對其進行修改將非常緩慢,因此不建議使用。

注意
上面的方法通常用于選擇數(shù)組的區(qū)域,例如前5行和后3列。對于單個像素訪問,Numpy數(shù)組方法array.item()和array.itemset())被認為更好,但是它們始終返回標量。如果要訪問所有B,G,R值,則需要分別調(diào)用所有的array.item()。

更好的像素訪問和編輯方法:

# 訪問 RED 值
>>> img.item(10,10,2)
59
# 修改 RED 值
>>> img.itemset((10,10,2),100)
>>> img.item(10,10,2)
100

訪問圖像屬性

圖像屬性包括行數(shù),列數(shù)和通道數(shù),圖像數(shù)據(jù)類型,像素數(shù)等。

圖像的形狀可通過img.shape訪問。它返回行,列和通道數(shù)的元組(如果圖像是彩色的):

>>> print( img.shape )
(342, 548, 3)

注意

如果圖像是灰度的,則返回的元組僅包含行數(shù)和列數(shù),因此這是檢查加載的圖像是灰度還是彩色的好方法。

像素總數(shù)可通過訪問img.size:

>>> print( img.size )
562248

圖像數(shù)據(jù)類型通過img.dtype獲得:

>>> print( img.dtype )
uint8

注意
img.dtype在調(diào)試時非常重要,因為OpenCV-Python代碼中的大量錯誤是由無效的數(shù)據(jù)類型引起的。

圖像感興趣區(qū)域ROI

有時候,你不得不處理一些特定區(qū)域的圖像。對于圖像中的眼睛檢測,首先對整個圖像進行人臉檢測。在獲取人臉圖像時,我們只選擇人臉區(qū)域,搜索其中的眼睛,而不是搜索整個圖像。它提高了準確性(因為眼睛總是在面部上:D )和性能(因為我們搜索的區(qū)域很小)。

使用Numpy索引再次獲得ROI。在這里,我要選擇球并將其復制到圖像中的另一個區(qū)域:

>>> ball = img[280:340, 330:390]
>>> img[273:333, 100:160] = ball 

檢查以下結(jié)果:

OpenCV-Python教程上篇

 

拆分和合并圖像通道

有時你需要分別處理圖像的B,G,R通道。在這種情況下,你需要將BGR圖像拆分為單個通道。在其他情況下,你可能需要將這些單獨的頻道加入BGR圖片。你可以通過以下方式簡單地做到這一點:

>>> b,g,r = cv.split(img) >>> img = cv.merge((b,g,r))

要么

>>> b = img [:, :, 0]

假設(shè)你要將所有紅色像素都設(shè)置為零,則無需先拆分通道。numpy索引更快:

>>> img [:, :, 2] = 0

警告

cv.split()是一項耗時的操作(就時間而言)。因此,僅在必要時才這樣做。否則請進行Numpy索引。

為圖像設(shè)置邊框(填充)

如果要在圖像周圍創(chuàng)建邊框(如相框),則可以使用cv.copyMakeBorder()。但是它在卷積運算,零填充等方面有更多應用。此函數(shù)采用以下參數(shù):

  • src - 輸入圖像
  • topbottomleftright 邊界寬度(以相應方向上的像素數(shù)為單位)
  • borderType - 定義要添加哪種邊框的標志。它可以是以下類型: cv.BORDER_CONSTANT - 添加恒定的彩色邊框。該值應作為下一個參數(shù)給出。 cv.BORDER_REFLECT - 邊框?qū)⑹沁吙蛟氐溺R像,如下所示: fedcba | abcdefgh | hgfedcb cv.BORDERREFLECT101或 cv.BORDER_DEFAULT與上述相同,但略有變化,例如: gfedcb | abcdefgh | gfedcba cv.BORDER_REPLICATE最后一個元素被復制,像這樣: aaaaaa | abcdefgh | hhhhhhh cv.BORDER_WRAP難以解釋,它看起來像這樣: cdefgh | abcdefgh | abcdefg
  • value -邊框的顏色,如果邊框類型為cv.BORDER_CONSTANT

下面是一個示例代碼,演示了所有這些邊框類型,以便更好地理解:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255,0,0]
img1 = cv.imread('opencv-logo.png')
replicate = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_WRAP)
constant= cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE)
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()

請參閱下面的結(jié)果。(圖像與matplotlib一起顯示。因此紅色和藍色通道將互換):

OpenCV-Python教程上篇

 

OpenCV-Python 圖像上的算術(shù)運算 | 十一

目標

  • 學習圖像的幾種算術(shù)運算,例如加法,減法,按位運算等。
  • cv.addcv.addWeighted等。

圖像加法

您可以通過OpenCV函數(shù)cv.add()或僅通過numpy操作res = img1 + img2添加兩個圖像。兩個圖像應具有相同的深度和類型,或者第二個圖像可以只是一個標量值。

注意
OpenCV加法和Numpy加法之間有區(qū)別。OpenCV加法是飽和運算,而Numpy加法是模運算。

例如,考慮以下示例:

>>> x = np.uint8([250])
>>> y = np.uint8([10])
>>> print( cv.add(x,y) ) # 250+10 = 260 => 255
[[255]]
>>> print( x+y ) # 250+10 = 260 % 256 = 4
[4]

當添加兩個圖像時,它將更加可見。OpenCV功能將提供更好的結(jié)果。因此,始終最好堅持使用OpenCV功能。

圖像融合

這也是圖像加法,但是對圖像賦予不同的權(quán)重,以使其具有融合或透明的感覺。根據(jù)以下等式添加圖像:

OpenCV-Python教程上篇

 

通過從 α 從 0→1 更改,您可以在一個圖像到另一個圖像之間執(zhí)行很酷的過渡。

在這里,我拍攝了兩個圖像,將它們?nèi)诤显谝黄稹5谝环鶊D像的權(quán)重為0.7,第二幅圖像的權(quán)重為0.3。cv.addWeighted()在圖像上應用以下公式。

OpenCV-Python教程上篇

 

在這里,γ 被視為零。

img1 = cv.imread('ml.png')
img2 = cv.imread('opencv-logo.png')
dst = cv.addWeighted(img1,0.7,img2,0.3,0)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()

檢查以下結(jié)果:

OpenCV-Python教程上篇

 

按位運算

這包括按位 AND、 OR、NOT 和 XOR 操作。它們在提取圖像的任何部分(我們將在后面的章節(jié)中看到)、定義和處理非矩形 ROI 等方面非常有用。 下面我們將看到一個例子,如何改變一個圖像的特定區(qū)域。我想把 OpenCV 的標志放在一個圖像上面。如果我添加兩個圖像,它會改變顏色。如果我混合它,我得到一個透明的效果。但我希望它是不透明的。如果是一個矩形區(qū)域,我可以使用 ROI,就像我們在上一章中所做的那樣。但是 OpenCV 的 logo 不是長方形的。所以你可以使用如下的按位操作來實現(xiàn):

我想在圖像上方放置OpenCV徽標。如果添加兩個圖像,它將改變顏色。如果混合它,我將獲得透明效果。但我希望它不透明。如果是矩形區(qū)域,則可以像上一章一樣使用ROI。但是OpenCV徽標不是矩形。因此,您可以按如下所示進行按位操作:

# 加載兩張圖片
img1 = cv.imread('messi5.jpg')
img2 = cv.imread('opencv-logo-white.png')
# 我想把logo放在左上角,所以我創(chuàng)建了ROI
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]
# 現(xiàn)在創(chuàng)建logo的掩碼,并同時創(chuàng)建其相反掩碼
img2gray = cv.cvtColor(img2,cv.COLOR_BGR2GRAY)
ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY)
mask_inv = cv.bitwise_not(mask)
# 現(xiàn)在將ROI中l(wèi)ogo的區(qū)域涂黑
img1_bg = cv.bitwise_and(roi,roi,mask = mask_inv)
# 僅從logo圖像中提取logo區(qū)域
img2_fg = cv.bitwise_and(img2,img2,mask = mask)
# 將logo放入ROI并修改主圖像
dst = cv.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst
cv.imshow('res',img1)
cv.waitKey(0)
cv.destroyAllWindows()

請看下面的結(jié)果。左圖顯示了我們創(chuàng)建的mask。右圖顯示最終結(jié)果。為了更好地理解,顯示上面代碼中的所有中間映像,特別是 img1bg 和 img2fg。

OpenCV-Python教程上篇

 

練習題

  1. 使用cv.addWeighted函數(shù)在文件夾中創(chuàng)建圖像的幻燈片放映,并在圖像之間進行平滑過渡

OpenCV -Python 性能衡量和提升技術(shù) | 十二

目標

在圖像處理中,由于每秒要處理大量操作,因此必須使代碼不僅提供正確的解決方案,而且還必須以最快的方式提供。因此,在本章中,你將學習

  • 衡量代碼的性能。
  • 一些提高代碼性能的技巧。
  • 你將看到以下功能:cv.getTickCountcv.getTickFrequency等。

除了OpenCV,Python還提供了一個模塊time,這有助于衡量執(zhí)行時間。另一個模塊profile有助于獲取有關(guān)代碼的詳細報告,例如代碼中每個函數(shù)花費了多少時間,調(diào)用了函數(shù)的次數(shù)等。但是,如果你使用的是IPython,則所有這些功能都集成在用戶友好的界面中方式。我們將看到一些重要的信息,有關(guān)更多詳細信息,請查看“ 其他資源”部分中的鏈接。

使用OpenCV衡量性能

cv.getTickCount函數(shù)返回從參考事件(如打開機器的那一刻)到調(diào)用此函數(shù)那一刻之間的時鐘周期數(shù)。因此,如果在函數(shù)執(zhí)行之前和之后調(diào)用它,則會獲得用于執(zhí)行函數(shù)的時鐘周期數(shù)。

cv.getTickFrequency函數(shù)返回時鐘周期的頻率或每秒的時鐘周期數(shù)。因此,要找到執(zhí)行時間(以秒為單位),你可以執(zhí)行以下操作:

e1 = cv.getTickCount()
# 你的執(zhí)行代碼
e2 = cv.getTickCount()
time = (e2 - e1)/ cv.getTickFrequency()

我們將通過以下示例進行演示。下面的示例應用中位數(shù)過濾,其內(nèi)核的奇數(shù)范圍為5到49。(不必擔心結(jié)果會是什么樣,這不是我們的目標):

img1 = cv.imread('messi5.jpg')
e1 = cv.getTickCount()
for i in range(5,49,2):
 img1 = cv.medianBlur(img1,i)
e2 = cv.getTickCount()
t = (e2 - e1)/cv.getTickFrequency()
print( t )
# 我得到的結(jié)果是0.521107655秒

注意
你可以使用時間模塊執(zhí)行相同的操作。代替cv.getTickCount,使用time.time()函數(shù)。然后取兩次相差。

OpenCV中的默認優(yōu)化

許多 OpenCV 函數(shù)都是使用 SSE2、 AVX 等進行優(yōu)化的。 它還包含未優(yōu)化的代碼。因此,如果我們的系統(tǒng)支持這些特性,我們就應該利用它們(幾乎所有現(xiàn)代的處理器都支持它們)。在編譯時默認啟用它。因此,如果啟用了 OpenCV,它將運行優(yōu)化的代碼,否則它將運行未優(yōu)化的代碼。你可以使用 cvUseoptimized 檢查是否啟用 / 禁用和 cvSetuseoptimized 以啟用 / 禁用它。讓我們看一個簡單的例子。

 

# 檢查是否啟用了優(yōu)化
In [5]: cv.useOptimized()
Out[5]: True
In [6]: %timeit res = cv.medianBlur(img,49)
10 loops, best of 3: 34.9 ms per loop
# 關(guān)閉它
In [7]: cv.setUseOptimized(False)
In [8]: cv.useOptimized()
Out[8]: False
In [9]: %timeit res = cv.medianBlur(img,49)
10 loops, best of 3: 64.1 ms per loop

看,優(yōu)化的中值濾波比未優(yōu)化的版本快2倍。如果你檢查其來源,你可以看到中值濾波是 SIMD 優(yōu)化。因此,你可以使用它在代碼頂部啟用優(yōu)化(請記住,它是默認啟用的)

在IPython中衡量性能

有時你可能需要比較兩個類似操作的性能。IPython為你提供了一個神奇的命令計時器來執(zhí)行此操作。它會多次運行代碼以獲得更準確的結(jié)果。同樣,它們適用于測量單行代碼。

例如,你知道以下哪個加法運算更好,x = 5; y = x**2, x = 5; y = x*x, x = np.uint8([5]); y = x*x或y = np.square(x)?我們將在IPython shell中使用timeit得到答案。

In [10]: x = 5

In [11]: %timeit y=x**2
10000000 loops, best of 3: 73 ns per loop

In [12]: %timeit y=x*x
10000000 loops, best of 3: 58.3 ns per loop

In [15]: z = np.uint8([5])

In [17]: %timeit y=z*z
1000000 loops, best of 3: 1.25 us per loop

In [19]: %timeit y=np.square(z)
1000000 loops, best of 3: 1.16 us per loop

你可以看到x = 5; y = x x最快,比Numpy快20倍左右。如果你還考慮陣列的創(chuàng)建,它可能會快100倍。酷吧?(大量開發(fā)人員正在研究此問題)*

注意
Python標量操作比Numpy標量操作快。因此,對于包含一兩個元素的運算,Python標量比Numpy數(shù)組好。當數(shù)組大小稍大時,Numpy會占優(yōu)勢。

我們將再嘗試一個示例。這次,我們將比較cv.countNonZeronp.count_nonzero對于同一張圖片的性能。

In [35]: %timeit z = cv.countNonZero(img)
100000 loops, best of 3: 15.8 us per loop
In [36]: %timeit z = np.count_nonzero(img)
1000 loops, best of 3: 370 us per loop

看,OpenCV 函數(shù)比 Numpy 函數(shù)快近25倍。

注意
通常,OpenCV函數(shù)比Numpy函數(shù)要快。因此,對于相同的操作,首選OpenCV功能。但是,可能會有例外,尤其是當Numpy處理視圖而不是副本時。

更多IPython魔術(shù)命令

還有其他一些魔術(shù)命令可以用來測量性能,性能分析,行性能分析,內(nèi)存測量等。它們都有很好的文檔記錄。因此,此處僅提供指向這些文檔的鏈接。建議有興趣的讀者嘗試一下。

性能優(yōu)化技術(shù)

有幾種技術(shù)和編碼方法可以充分利用 Python 和 Numpy 的最大性能。這里只注明相關(guān)信息,并提供重要信息來源的鏈接。這里要注意的主要事情是,首先嘗試以一種簡單的方式實現(xiàn)算法。一旦它運行起來,分析它,找到瓶頸并優(yōu)化它們。

  1. 盡量避免在Python中使用循環(huán),尤其是雙/三重循環(huán)等。它們本來就很慢。
  2. 由于Numpy和OpenCV已針對向量運算進行了優(yōu)化,因此將算法/代碼向量化到最大程度。
  3. 利用緩存一致性。
  4. 除非需要,否則切勿創(chuàng)建數(shù)組的副本。嘗試改用視圖。數(shù)組復制是一項昂貴的操作。

即使執(zhí)行了所有這些操作后,如果你的代碼仍然很慢,或者不可避免地需要使用大循環(huán),請使用Cython等其他庫來使其更快。

其他資源

  1. Python優(yōu)化技術(shù):http://wiki.python.org/moin/PythonSpeed/PerformanceTips
  2. Scipy講義- 高級Numpy:http://scipy-lectures.github.io/advanced/advanced_numpy/index.html#advanced-numpy
  3. IPython中的時序和性能分析:http://pynash.org/2013/03/06/timing-and-profiling/

OpenCV-Python 改變顏色空間 | 十三

目標

  • 在本教程中,你將學習如何將圖像從一個色彩空間轉(zhuǎn)換到另一個,像BGR↔灰色,BGR↔HSV等
  • 除此之外,我們還將創(chuàng)建一個應用程序,以提取視頻中的彩色對象
  • 你將學習以下功能:cv.cvtColorcv.inRange等。

改變顏色空間

OpenCV中有超過150種顏色空間轉(zhuǎn)換方法。但是我們將研究只有兩個最廣泛使用的,BGR↔灰色和BGR↔HSV。

對于顏色轉(zhuǎn)換,我們使用cv函數(shù)。cvtColor(input_image, flag),其中flag決定轉(zhuǎn)換的類型。

對于BGR→灰度轉(zhuǎn)換,我們使用標志cv.COLORBGR2GRAY。類似地,對于BGR→HSV,我們使用標志cv.COLORBGR2HSV。要獲取其他標記,只需在Python終端中運行以下命令:

>>> import cv2 as cv
>>> flags = [i for i in dir(cv) if i.startswith('COLOR_')]
>>> print( flags )

注意
HSV的色相范圍為[0,179],飽和度范圍為[0,255],值范圍為[0,255]。不同的軟件使用不同的規(guī)模。因此,如果你要將OpenCV值和它們比較,你需要將這些范圍標準化。

對象追蹤

現(xiàn)在我們知道了如何將BGR圖像轉(zhuǎn)換成HSV,我們可以使用它來提取一個有顏色的對象。在HSV中比在BGR顏色空間中更容易表示顏色。在我們的應用程序中,我們將嘗試提取一個藍色的對象。方法如下:

  • 取視頻的每一幀
  • 轉(zhuǎn)換從BGR到HSV顏色空間
  • 我們對HSV圖像設(shè)置藍色范圍的閾值
  • 現(xiàn)在單獨提取藍色對象,我們可以對圖像做任何我們想做的事情。

下面是詳細注釋的代碼:

import cv2 as cv
import numpy as np
cap = cv.VideoCapture(0)
while(1):
 # 讀取幀
 _, frame = cap.read()
 # 轉(zhuǎn)換顏色空間 BGR 到 HSV
 hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
 # 定義HSV中藍色的范圍
 lower_blue = np.array([110,50,50])
 upper_blue = np.array([130,255,255])
 # 設(shè)置HSV的閾值使得只取藍色
 mask = cv.inRange(hsv, lower_blue, upper_blue)
 # 將掩膜和圖像逐像素相加
 res = cv.bitwise_and(frame,frame, mask= mask)
 cv.imshow('frame',frame)
 cv.imshow('mask',mask)
 cv.imshow('res',res)
 k = cv.waitKey(5) & 0xFF
 if k == 27:
 break
cv.destroyAllWindows()

下圖顯示了對藍色對象的跟蹤:

OpenCV-Python教程上篇

 

注意
圖像中有一些噪點。我們將在后面的章節(jié)中看到如何刪除它們。
這是對象跟蹤中最簡單的方法。一旦學習了輪廓的功能,你就可以做很多事情,例如找到該對象的質(zhì)心并使用它來跟蹤對象,僅通過將手移到相機前面以及其他許多有趣的東西就可以繪制圖表。

如何找到要追蹤的HSV值?

這是在stackoverflow.com上發(fā)現(xiàn)的一個常見問題。它非常簡單,你可以使用相同的函數(shù)cv.cvtColor()。你只需傳遞你想要的BGR值,而不是傳遞圖像。例如,要查找綠色的HSV值,請在Python終端中嘗試以下命令:

>>> green = np.uint8([[[0,255,0 ]]])
>>> hsv_green = cv.cvtColor(green,cv.COLOR_BGR2HSV)
>>> print( hsv_green )
[[[ 60 255 255]]]

現(xiàn)在把[H- 10,100,100]和[H+ 10,255, 255]分別作為下界和上界。除了這個方法之外,你可以使用任何圖像編輯工具(如GIMP或任何在線轉(zhuǎn)換器)來查找這些值,但是不要忘記調(diào)整HSV范圍。

練習題

  1. 嘗試找到一種方法來提取多個彩色對象,例如,同時提取紅色,藍色,綠色對象。

OpenCV-Python 圖像的幾何變換 | 十四

目標

  • 學習將不同的幾何變換應用到圖像上,如平移、旋轉(zhuǎn)、仿射變換等。
  • 你會看到這些函數(shù): cv.getPerspectiveTransform

變換

OpenCV提供了兩個轉(zhuǎn)換函數(shù)cv.warpAffinecv.warpPerspective,您可以使用它們進行各種轉(zhuǎn)換。cv.warpAffine采用2x3轉(zhuǎn)換矩陣,而cv.warpPerspective采用3x3轉(zhuǎn)換矩陣作為輸入。

縮放

縮放只是調(diào)整圖像的大小。為此,OpenCV帶有一個函數(shù)cv.resize()。圖像的大小可以手動指定,也可以指定縮放比例。也可使用不同的插值方法。首選的插值方法是cv.INTER_AREA用于縮小,cv.INTER_CUBIC(慢)和cv.INTER_LINEAR用于縮放。默認情況下,出于所有調(diào)整大小的目的,使用的插值方法為cv.INTER_LINEAR。您可以使用以下方法調(diào)整輸入圖像的大小:

import numpy as np
import cv2 as cv
img = cv.imread('messi5.jpg')
res = cv.resize(img,None,fx=2, fy=2, interpolation = cv.INTER_CUBIC)
#或者
height, width = img.shape[:2]
res = cv.resize(img,(2*width, 2*height), interpolation = cv.INTER_CUBIC)

平移

平移是物體位置的移動。如果您知道在(x,y)方向上的位移,則將其設(shè)為(t_x,$ty$),你可以創(chuàng)建轉(zhuǎn)換矩陣M,如下所示:

OpenCV-Python教程上篇

 

您可以將其放入np.float32類型的Numpy數(shù)組中,并將其傳遞給cv.warpAffine函數(shù)。參見下面偏移為(100, 50)的示例:

import numpy as np
import cv2 as cv
img = cv.imread('messi5.jpg',0)
rows,cols = img.shape
M = np.float32([[1,0,100],[0,1,50]])
dst = cv.warpAffine(img,M,(cols,rows))
cv.imshow('img',dst)
cv.waitKey(0)
cv.destroyAllWindows()

注意

cv.warpAffine函數(shù)的第三個參數(shù)是輸出圖像的大小,其形式應為(width,height)。記住width =列數(shù),height =行數(shù)。

你將看到下面的結(jié)果:

OpenCV-Python教程上篇

 

旋轉(zhuǎn)

圖像旋轉(zhuǎn)角度為$θ$是通過以下形式的變換矩陣實現(xiàn)的:

OpenCV-Python教程上篇

 

但是OpenCV提供了可縮放的旋轉(zhuǎn)以及可調(diào)整的旋轉(zhuǎn)中心,因此您可以在自己喜歡的任何位置旋轉(zhuǎn)。修改后的變換矩陣為

OpenCV-Python教程上篇

 

其中:

OpenCV-Python教程上篇

 

為了找到此轉(zhuǎn)換矩陣,OpenCV提供了一個函數(shù)cv.getRotationMatrix2D。請檢查以下示例,該示例將圖像相對于中心旋轉(zhuǎn)90度而沒有任何縮放比例。

img = cv.imread('messi5.jpg',0)
rows,cols = img.shape
# cols-1 和 rows-1 是坐標限制
M = cv.getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0),90,1)
dst = cv.warpAffine(img,M,(cols,rows))

查看結(jié)果:

OpenCV-Python教程上篇

 

仿射變換

在仿射變換中,原始圖像中的所有平行線在輸出圖像中仍將平行。為了找到變換矩陣,我們需要輸入圖像中的三個點及其在輸出圖像中的對應位置。然后cv.getAffineTransform將創(chuàng)建一個2x3矩陣,該矩陣將傳遞給cv.warpAffine

查看以下示例,并查看我選擇的點(以綠色標記):

img = cv.imread('drawing.png')
rows,cols,ch = img.shape
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50],[100,250]])
M = cv.getAffineTransform(pts1,pts2)
dst = cv.warpAffine(img,M,(cols,rows))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')

查看結(jié)果:

OpenCV-Python教程上篇

 

透視變換

對于透視變換,您需要3x3變換矩陣。即使在轉(zhuǎn)換后,直線也將保持直線。要找到此變換矩陣,您需要在輸入圖像上有4個點,在輸出圖像上需要相應的點。在這四個點中,其中三個不應共線。然后可以通過函數(shù)

cv.getPerspectiveTransform找到變換矩陣。然后將cv.warpPerspective應用于此3x3轉(zhuǎn)換矩陣。

請參見下面的代碼:

img = cv.imread('sudoku.png')
rows,cols,ch = img.shape
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M = cv.getPerspectiveTransform(pts1,pts2)
dst = cv.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()

結(jié)果:

OpenCV-Python教程上篇

 

其他資源

  1. "Computer Vision: Algorithms and Applications", Richard Szeliski

OpenCV-Python 圖像閾值 | 十五

目標

  • 在本教程中,您將學習簡單閾值,自適應閾值和Otsu閾值。
  • 你將學習函數(shù)cv.thresholdcv.adaptiveThreshold

簡單閾值

在這里,問題直截了當。對于每個像素,應用相同的閾值。如果像素值小于閾值,則將其設(shè)置為0,否則將其設(shè)置為最大值。函數(shù)cv.threshold用于應用閾值。第一個參數(shù)是源圖像,它應該是灰度圖像。第二個參數(shù)是閾值,用于對像素值進行分類。第三個參數(shù)是分配給超過閾值的像素值的最大值。OpenCV提供了不同類型的閾值,這由函數(shù)的第四個參數(shù)給出。通過使用cv.THRESH_BINARY類型。所有簡單的閾值類型為:

  • cv.THRESH_BINARY
  • cv.THRESHBINARYINV
  • cv.THRESH_TRUNC
  • cv.THRESH_TOZERO
  • cv.THRESHTOZEROINV

該方法返回兩個輸出。第一個是使用的閾值,第二個輸出是閾值后的圖像

此代碼比較了不同的簡單閾值類型:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('gradient.png',0)
ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)
ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)
ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)
ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)
titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in xrange(6):
 plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
 plt.title(titles[i])
 plt.xticks([]),plt.yticks([])
plt.show()

 

注意

為了繪制多個圖像,我們使用plt.subplot()函數(shù)。請查看matplotlib文檔以獲取更多詳細信息。

該代碼產(chǎn)生以下結(jié)果:

OpenCV-Python教程上篇

 

自適應閾值

在上一節(jié)中,我們使用一個全局值作為閾值。但這可能并非在所有情況下都很好,例如,如果圖像在不同區(qū)域具有不同的光照條件。在這種情況下,自適應閾值閾值化可以提供幫助。在此,算法基于像素周圍的小區(qū)域確定像素的閾值。因此,對于同一圖像的不同區(qū)域,我們獲得了不同的閾值,這為光照度變化的圖像提供了更好的結(jié)果。

除上述參數(shù)外,方法cv.adaptiveThreshold還包含三個輸入?yún)?shù):

adaptiveMethod決定閾值是如何計算的:

cv.ADAPTIVETHRESHMEAN_C::閾值是鄰近區(qū)域的平均值減去常數(shù)C

cv.ADAPTIVETHRESHGAUSSIAN_C:閾值是鄰域值的高斯加權(quán)總和減去常數(shù)C

BLOCKSIZE確定附近區(qū)域的大小,C是從鄰域像素的平均或加權(quán)總和中減去的一個常數(shù)。

下面的代碼比較了光照變化的圖像的全局閾值和自適應閾值:

結(jié)果:

OpenCV-Python教程上篇

 

Otsu的二值化

在全局閾值化中,我們使用任意選擇的值作為閾值。相反,Otsu的方法避免了必須選擇一個值并自動確定它的情況。

考慮僅具有兩個不同圖像值的圖像(雙峰圖像),其中直方圖將僅包含兩個峰。一個好的閾值應該在這兩個值的中間。類似地,Otsu的方法從圖像直方圖中確定最佳全局閾值。

為此,使用了cv.threshold作為附加標志傳遞。閾值可以任意選擇。然后,算法找到最佳閾值,該閾值作為第一輸出返回。

查看以下示例。輸入圖像為噪點圖像。在第一種情況下,采用值為127的全局閾值。在第二種情況下,直接采用Otsu閾值法。在第三種情況下,首先使用5x5高斯核對圖像進行濾波以去除噪聲,然后應用Otsu閾值處理。了解噪聲濾波如何改善結(jié)果。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('noisy2.png',0)
# 全局閾值
ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
# Otsu閾值
ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# 高斯濾波后再采用Otsu閾值
blur = cv.GaussianBlur(img,(5,5),0)
ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# 繪制所有圖像及其直方圖
images = [img, 0, th1,
 img, 0, th2,
 blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
 'Original Noisy Image','Histogram',"Otsu's Thresholding",
 'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
for i in xrange(3):
 plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
 plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
 plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
 plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
 plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
 plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()

結(jié)果:

OpenCV-Python教程上篇

 

Otsu的二值化如何實現(xiàn)?

本節(jié)演示了Otsu二值化的Python實現(xiàn),以展示其實際工作方式。如果您不感興趣,可以跳過此步驟。

由于我們正在處理雙峰圖像,因此Otsu的算法嘗試找到一個閾值(t),該閾值將由關(guān)系式給出的加權(quán)類內(nèi)方差最小化:

OpenCV-Python教程上篇

 

其中

OpenCV-Python教程上篇

 

實際上,它找到位于兩個峰值之間的t值,以使兩個類別的差異最小。它可以簡單地在Python中實現(xiàn),如下所示:

img = cv.imread('noisy2.png',0)
blur = cv.GaussianBlur(img,(5,5),0)
# 尋找歸一化直方圖和對應的累積分布函數(shù)
hist = cv.calcHist([blur],[0],None,[256],[0,256])
hist_norm = hist.ravel()/hist.max()
Q = hist_norm.cumsum()
bins = np.arange(256)
fn_min = np.inf
thresh = -1
for i in xrange(1,256):
 p1,p2 = np.hsplit(hist_norm,[i]) # 概率
 q1,q2 = Q[i],Q[255]-Q[i] # 對類求和
 b1,b2 = np.hsplit(bins,[i]) # 權(quán)重
 # 尋找均值和方差
 m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2
 v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2
 # 計算最小化函數(shù)
 fn = v1*q1 + v2*q2
 if fn < fn_min:
 fn_min = fn
 thresh = i
# 使用OpenCV函數(shù)找到otsu的閾值
ret, otsu = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
print( "{} {}".format(thresh,ret) )

 

其他資源

  1. Digital Image Processing, Rafael C. Gonzalez

練習題

  1. Otsu的二值化有一些優(yōu)化。您可以搜索并實現(xiàn)它。

OpenCV-Python 圖像平滑 | 十六

目標

學會:

  • 使用各種低通濾鏡模糊圖像
  • 將定制的濾鏡應用于圖像(2D卷積)

2D卷積(圖像過濾)

與一維信號一樣,還可以使用各種低通濾波器(LPF),高通濾波器(HPF)等對圖像進行濾波。LPF有助于消除噪聲,使圖像模糊等。HPF濾波器有助于在圖像中找到邊緣。

OpenCV提供了一個函數(shù)cv.filter2D來將內(nèi)核與圖像進行卷積。例如,我們將嘗試對圖像進行平均濾波。5x5平均濾波器內(nèi)核如下所示:

OpenCV-Python教程上篇

 

操作如下:保持這個內(nèi)核在一個像素上,將所有低于這個內(nèi)核的25個像素相加,取其平均值,然后用新的平均值替換中心像素。它將對圖像中的所有像素繼續(xù)此操作。試試這個代碼,并檢查結(jié)果:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('opencv_logo.png')
kernel = np.ones((5,5),np.float32)/25
dst = cv.filter2D(img,-1,kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dst),plt.title('Averaging')
plt.xticks([]), plt.yticks([])
plt.show()

結(jié)果:

OpenCV-Python教程上篇

 

圖像模糊(圖像平滑)

通過將圖像與低通濾波器內(nèi)核進行卷積來實現(xiàn)圖像模糊。這對于消除噪音很有用。它實際上從圖像中消除了高頻部分(例如噪聲,邊緣)。因此,在此操作中邊緣有些模糊。(有一些模糊技術(shù)也可以不模糊邊緣)。OpenCV主要提供四種類型的模糊技術(shù)。

1.平均

這是通過將圖像與歸一化框濾鏡進行卷積來完成的。它僅獲取內(nèi)核區(qū)域下所有像素的平均值,并替換中心元素。這是通過功能cv.blur()cv.boxFilter()完成的。檢查文檔以獲取有關(guān)內(nèi)核的更多詳細信息。我們應該指定內(nèi)核的寬度和高度。3x3歸一化框式過濾器如下所示:

OpenCV-Python教程上篇

 

注意
如果您不想使用標準化的框式過濾器,請使用cv.boxFilter()。將參數(shù)normalize = False傳遞給函數(shù)。

查看下面的示例演示,其內(nèi)核大小為5x5:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('opencv-logo-white.png')
blur = cv.blur(img,(5,5))
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()

結(jié)果:

OpenCV-Python教程上篇

 

2.高斯模糊

在這種情況下,代替盒式濾波器,使用了高斯核。這是通過功能cv.GaussianBlur() 完成的。我們應指定內(nèi)核的寬度和高度,該寬度和高度應為正數(shù)和奇數(shù)。我們還應指定X和Y方向的標準偏差,分別為sigmaX和sigmaY。如果僅指定sigmaX,則將sigmaY與sigmaX相同。如果兩個都為零,則根據(jù)內(nèi)核大小進行計算。高斯模糊對于從圖像中去除高斯噪聲非常有效。

如果需要,可以使用函數(shù)cv.getGaussianKernel() 創(chuàng)建高斯內(nèi)核。

可以修改以上代碼以實現(xiàn)高斯模糊:

blur = cv.GaussianBlur(img,(5,5),0)

結(jié)果:

OpenCV-Python教程上篇

 

3.中位模糊

在這里,函數(shù)cv.medianBlur() 提取內(nèi)核區(qū)域下所有像素的中值,并將中心元素替換為該中值。這對于消除圖像中的椒鹽噪聲非常有效。有趣的是,在上述過濾器中,中心元素是新計算的值,該值可以是圖像中的像素值或新值。但是在中值模糊中,中心元素總是被圖像中的某些像素值代替。有效降低噪音。其內(nèi)核大小應為正奇數(shù)整數(shù)。

在此演示中,我向原始圖像添加了50%的噪聲并應用了中值模糊。檢查結(jié)果:

median = cv.medianBlur(img,5)

結(jié)果:

OpenCV-Python教程上篇

 

4.雙邊濾波

cv.bilateralFilter() 在去除噪聲的同時保持邊緣清晰銳利非常有效。但是,與其他過濾器相比,該操作速度較慢。我們已經(jīng)看到,高斯濾波器采用像素周圍的鄰域并找到其高斯加權(quán)平均值。高斯濾波器僅是空間的函數(shù),也就是說,濾波時會考慮附近的像素。它不考慮像素是否具有幾乎相同的強度。它不考慮像素是否是邊緣像素。因此它也模糊了邊緣,這是我們不想做的。

雙邊濾波器在空間中也采用高斯濾波器,但是又有一個高斯濾波器,它是像素差的函數(shù)。空間的高斯函數(shù)確保僅考慮附近像素的模糊,而強度差的高斯函數(shù)確保僅考慮強度與中心像素相似的那些像素的模糊。由于邊緣的像素強度變化較大,因此可以保留邊緣。

以下示例顯示了使用雙邊過濾器(有關(guān)參數(shù)的詳細信息,請訪問docs)。

blur = cv.bilateralFilter(img,9,75,75)

結(jié)果:

OpenCV-Python教程上篇

 

看到,表面上的紋理消失了,但是邊緣仍然保留。

其他資源

  1. 有關(guān)雙邊過濾的詳細信息:http://people.csail.mit.edu/sparis/bf_course/

OpenCV-Python 形態(tài)學轉(zhuǎn)換 | 十七

目標

在這一章當中, 我們將學習不同的形態(tài)學操作,例如侵蝕,膨脹,開運算,閉運算等。 我們將看到不同的功能,例如:cv.erode(),cv.dilate(), cv.morphologyEx()等。

理論

形態(tài)變換是一些基于圖像形狀的簡單操作。通常在二進制圖像上執(zhí)行。它需要兩個輸入,一個是我們的原始圖像,第二個是決定操作性質(zhì)的結(jié)構(gòu)元素內(nèi)核。兩種基本的形態(tài)學算子是侵蝕和膨脹。然后,它的變體形式(如“打開”,“關(guān)閉”,“漸變”等)也開始起作用。在下圖的幫助下,我們將一一看到它們:

OpenCV-Python教程上篇

 

1. 侵蝕

侵蝕的基本思想就像土壤侵蝕一樣,它侵蝕前景物體的邊界(盡量使前景保持白色)。它是做什么的呢?內(nèi)核滑動通過圖像(在2D卷積中)。原始圖像中的一個像素(無論是1還是0)只有當內(nèi)核下的所有像素都是1時才被認為是1,否則它就會被侵蝕(變成0)。

結(jié)果是,根據(jù)內(nèi)核的大小,邊界附近的所有像素都會被丟棄。因此,前景物體的厚度或大小減小,或只是圖像中的白色區(qū)域減小。它有助于去除小的白色噪聲(正如我們在顏色空間章節(jié)中看到的),分離兩個連接的對象等。

在這里,作為一個例子,我將使用一個5x5內(nèi)核,它包含了所有的1。讓我們看看它是如何工作的:

import cv2 as cv
import numpy as np
img = cv.imread('j.png',0)
kernel = np.ones((5,5),np.uint8)
erosion = cv.erode(img,kernel,iterations = 1)

結(jié)果:

OpenCV-Python教程上篇

 

2. 擴張

它與侵蝕正好相反。如果內(nèi)核下的至少一個像素為“ 1”,則像素元素為“ 1”。因此,它會增加圖像中的白色區(qū)域或增加前景對象的大小。通常,在消除噪音的情況下,腐蝕后會膨脹。因為腐蝕會消除白噪聲,但也會縮小物體。因此,我們對其進行了擴展。由于噪音消失了,它們不會回來,但是我們的目標區(qū)域增加了。在連接對象的損壞部分時也很有用。

dilation = cv.dilate(img,kernel,iterations = 1) 

結(jié)果:

OpenCV-Python教程上篇

 

3. 開運算

開放只是侵蝕然后擴張的另一個名稱。如上文所述,它對于消除噪音很有用。在這里,我們使用函數(shù)cv.morphologyEx()

opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel) 

結(jié)果:

OpenCV-Python教程上篇

 

4. 閉運算

閉運算與開運算相反,先擴張然后再侵蝕。在關(guān)閉前景對象內(nèi)部的小孔或?qū)ο笊系男『邳c時很有用。

closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel) 
OpenCV-Python教程上篇

 

5. 形態(tài)學梯度

這是圖像擴張和侵蝕之間的區(qū)別。

結(jié)果將看起來像對象的輪廓。

gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel) 

 

OpenCV-Python教程上篇

 

6. 頂帽

它是輸入圖像和圖像開運算之差。下面的示例針對9x9內(nèi)核完成。

tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel) 

結(jié)果:

OpenCV-Python教程上篇

 

7. 黑帽

這是輸入圖像和圖像閉運算之差。

blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel) 

結(jié)果:

OpenCV-Python教程上篇

 

結(jié)構(gòu)元素

在Numpy的幫助下,我們在前面的示例中手動創(chuàng)建了一個結(jié)構(gòu)元素。它是矩形。但是在某些情況下,您可能需要橢圓形/圓形的內(nèi)核。因此,為此,OpenCV具有一個函數(shù)cv.getStructuringElement()。您只需傳遞內(nèi)核的形狀和大小,即可獲得所需的內(nèi)核。

# 矩形內(nèi)核
>>> cv.getStructuringElement(cv.MORPH_RECT,(5,5))
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1]], dtype=uint8)
# 橢圓內(nèi)核
>>> cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
array([[0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0]], dtype=uint8)
# 十字內(nèi)核
>>> cv.getStructuringElement(cv.MORPH_CROSS,(5,5))
array([[0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0]], dtype=uint8)

 

其他資源

 

  1. Morphological Operations:http://homepages.inf.ed.ac.uk/rbf/HIPR2/morops.htm at HIPR2

OpenCV-Python 圖像梯度 | 十八

目標

在本章中,我們將學習:

  • 查找圖像梯度,邊緣等
  • 我們將看到以下函數(shù):cv.Sobel(),cv.Scharr(),cv.Laplacian()等

理論

OpenCV提供三種類型的梯度濾波器或高通濾波器,即Sobel,Scharr和Laplacian。我們將看到他們每一種。

1. Sobel 和 Scharr 算子

Sobel算子是高斯平滑加微分運算的聯(lián)合運算,因此它更抗噪聲。逆可以指定要采用的導數(shù)方向,垂直或水平(分別通過參數(shù)yorder和xorder)。逆還可以通過參數(shù)ksize指定內(nèi)核的大小。如果ksize = -1,則使用3x3 Scharr濾波器,比3x3 Sobel濾波器具有更好的結(jié)果。請參閱文檔以了解所使用的內(nèi)核。

2. Laplacian 算子

它計算了由關(guān)系$Delta src = frac{partial ^2{src}}{partial x^2} + frac{partial ^2{src}}{partial y^2}$給出的圖像的拉普拉斯圖,它是每一階導數(shù)通過Sobel算子計算。如果ksize = 1,然后使用以下內(nèi)核用于過濾:

OpenCV-Python教程上篇

 

代碼

下面的代碼顯示了單個圖表中的所有算子。所有內(nèi)核都是5x5大小。輸出圖像的深度通過-1得到結(jié)果的np.uint8型。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('dave.jpg',0)
laplacian = cv.Laplacian(img,cv.CV_64F)
sobelx = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
sobely = cv.Sobel(img,cv.CV_64F,0,1,ksize=5)
plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
plt.show()

結(jié)果:

OpenCV-Python教程上篇

 

一個重要事項

在我們的最后一個示例中,輸出數(shù)據(jù)類型為cv.CV_8U或np.uint8。但這有一個小問題。黑色到白色的過渡被視為正斜率(具有正值),而白色到黑色的過渡被視為負斜率(具有負值)。因此,當您將數(shù)據(jù)轉(zhuǎn)換為np.uint8時,所有負斜率均?設(shè)為零。簡而言之,您會錯過這一邊緣信息。

如果要檢測兩個邊緣,更好的選擇是將輸出數(shù)據(jù)類型保留為更高的形式,例如cv.CV_16S,cv.CV_64F等,取其絕對值,然后轉(zhuǎn)換回cv.CV_8U。下面的代碼演示了用于水平Sobel濾波器和結(jié)果差異的此過程。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('box.png',0)
# Output dtype = cv.CV_8U
sobelx8u = cv.Sobel(img,cv.CV_8U,1,0,ksize=5)
# Output dtype = cv.CV_64F. Then take its absolute and convert to cv.CV_8U
sobelx64f = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)
plt.subplot(1,3,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1,3,2),plt.imshow(sobelx8u,cmap = 'gray')
plt.title('Sobel CV_8U'), plt.xticks([]), plt.yticks([])
plt.subplot(1,3,3),plt.imshow(sobel_8u,cmap = 'gray')
plt.title('Sobel abs(CV_64F)'), plt.xticks([]), plt.yticks([])
plt.show()

結(jié)果:

OpenCV-Python教程上篇

 

OpenCV-Python Canny邊緣檢測 | 十九

目標

在本章中,我們將學習

  • Canny邊緣檢測的概念
  • OpenCV函數(shù): cv.Canny()

理論

Canny Edge Detection是一種流行的邊緣檢測算法。它由John F. Canny發(fā)明

這是一個多階段算法,我們將經(jīng)歷每個階段。

降噪

由于邊緣檢測容易受到圖像中噪聲的影響,因此第一步是使用5x5高斯濾波器消除圖像中的噪聲。我們已經(jīng)在前面的章節(jié)中看到了這一點。

查找圖像的強度梯度

然后使用Sobel核在水平和垂直方向上對平滑的圖像進行濾波,以在水平方向(Gx)和垂直方向(Gy)上獲得一階導數(shù)。從這兩張圖片中,我們可以找到每個像素的邊緣漸變和方向,如下所示:

OpenCV-Python教程上篇

 

漸變方向始終垂直于邊緣。將其舍入為代表垂直,水平和兩個對角線方向的四個角度之一。

非極大值抑制
在獲得梯度大小和方向后,將對圖像進行全面掃描,以去除可能不構(gòu)成邊緣的所有不需要的像素。為此,在每個像素處,檢查像素是否是其在梯度方向上附近的局部最大值。查看下面的圖片:

OpenCV-Python教程上篇

 

點A在邊緣(垂直方向)上。漸變方向垂直于邊緣。點B和C在梯度方向上。因此,將A點與B點和C點進行檢查,看是否形成局部最大值。如果是這樣,則考慮將其用于下一階段,否則將其抑制(置為零)。 簡而言之,你得到的結(jié)果是帶有“細邊”的二進制圖像。

磁滯閾值

該階段確定哪些邊緣全部是真正的邊緣,哪些不是。為此,我們需要兩個閾值minVal和maxVal。強度梯度大于maxVal的任何邊緣必定是邊緣,而小于minVal的那些邊緣必定是非邊緣,因此將其丟棄。介于這兩個閾值之間的對象根據(jù)其連通性被分類為邊緣或非邊緣。如果將它們連接到“邊緣”像素,則將它們視為邊緣的一部分。否則,它們也將被丟棄。見下圖:

OpenCV-Python教程上篇

 

邊緣A在maxVal之上,因此被視為“確定邊緣”。盡管邊C低于maxVal,但它連接到邊A,因此也被視為有效邊,我們得到了完整的曲線。但是邊緣B盡管在minVal之上并且與邊緣C處于同一區(qū)域,但是它沒有連接到任何“確保邊緣”,因此被丟棄。因此,非常重要的一點是我們必須相應地選擇minVal和maxVal以獲得正確的結(jié)果。

在邊緣為長線的假設(shè)下,該階段還消除了小像素噪聲。

因此,我們最終得到的是圖像中的強邊緣。

OpenCV中的Canny Edge檢測

OpenCV將以上所有內(nèi)容放在單個函數(shù)cv.Canny()中。我們將看到如何使用它。第一個參數(shù)是我們的輸入圖像。第二個和第三個參數(shù)分別是我們的minVal和maxVal。第三個參數(shù)是perture_size。它是用于查找圖像漸變的Sobel內(nèi)核的大小。默認情況下為3。最后一個參數(shù)是L2gradient,它指定用于查找梯度幅度的方程式。如果為True,則使用上面提到的更精確的公式,否則使用以下函數(shù):$Edge_Gradient ; (G) = |Gx| + |Gy|$。默認情況下,它為False。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
edges = cv.Canny(img,100,200)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()

附加資源

  1. Canny edge detector at Wikipedia:http://en.wikipedia.org/wiki/Cannyedgedetector
  2. Canny Edge Detection Tutorial:http://dasl.unlv.edu/daslDrexel/alumni/bGreen/www.pages.drexel.edu/weg22/cantut.html by Bill Green, 2002.

練習

  1. 編寫一個小應用程序以找到Canny邊緣檢測,該檢測的閾值可以使用兩個跟蹤欄進行更改。這樣,您可以了解閾值的影響。

OpenCV-Python 圖像金字塔 | 二十

目標

在本章中,

  • 我們將學習圖像金字塔
  • 我們將使用圖像金字塔創(chuàng)建一個新的水果“Orapple”
  • 我們將看到以下功能:cv.pyrUp(),cv.pyrDown()

理論

通常,我們過去使用的是恒定大小的圖像。但是在某些情況下,我們需要使用不同分辨率的(相同)圖像。例如,當在圖像中搜索某些東西(例如人臉)時,我們不確定對象將以多大的尺寸顯示在圖像中。在這種情況下,我們將需要創(chuàng)建一組具有不同分辨率的相同圖像,并在所有圖像中搜索對象。這些具有不同分辨率的圖像集稱為“圖像金字塔”(因為當它們堆疊在底部時,最高分辨率的圖像位于頂部,最低分辨率的圖像位于頂部時,看起來像金字塔)。

有兩種圖像金字塔:1)高斯金字塔和2)拉普拉斯金字塔

高斯金字塔中的較高級別(低分辨率)是通過刪除較低級別(較高分辨率)圖像中的連續(xù)行和列而形成的。然后,較高級別的每個像素由基礎(chǔ)級別的5個像素的貢獻與高斯權(quán)重形成。通過這樣做,$M×N$圖像變成M/2 × N/2圖像。因此面積減少到原始面積的四分之一。它稱為Octave。當我們在金字塔中越靠上時(即分辨率下降),這種模式就會繼續(xù)。同樣,在擴展時,每個級別的面積變?yōu)?倍。我們可以使用cv.pyrDown()和cv.pyrUp()函數(shù)找到高斯金字塔。

img = cv.imread('messi5.jpg') 
lower_reso = cv.pyrDown(higher_reso)

以下是圖像金字塔中的4個級別。

OpenCV-Python教程上篇

 

現(xiàn)在,您可以使用cv.pyrUp()函數(shù)查看圖像金字塔。

higher_reso2 = cv.pyrUp(lower_reso) 

記住,higherreso2不等于higherreso,因為一旦降低了分辨率,就會丟失信息。下面的圖像是3層的金字塔從最小的圖像在前面的情況下創(chuàng)建。與原圖對比:

OpenCV-Python教程上篇

 

拉普拉斯金字塔由高斯金字塔形成。沒有專用功能。拉普拉斯金字塔圖像僅像邊緣圖像。它的大多數(shù)元素為零。它們用于圖像壓縮。拉普拉斯金字塔的層由高斯金字塔的層與高斯金字塔的高層的擴展版本之間的差形成。拉普拉斯等級的三個等級如下所示(調(diào)整對比度以增強內(nèi)容):

OpenCV-Python教程上篇

 

使用金字塔進行圖像融合

金字塔的一種應用是圖像融合。例如,在圖像拼接中,您需要將兩個圖像堆疊在一起,但是由于圖像之間的不連續(xù)性,可能看起來不太好。在這種情況下,使用金字塔混合圖像可以無縫混合,而不會在圖像中保留大量數(shù)據(jù)。一個經(jīng)典的例子是將兩種水果,橙和蘋果混合在一起。現(xiàn)在查看結(jié)果本身,以了解我在說什么:

OpenCV-Python教程上篇

 

請檢查其他資源中的第一個參考,它具有圖像混合,拉普拉斯金字塔等的完整圖解詳細信息。只需完成以下步驟即可:

  1. 加載蘋果和橙子的兩個圖像
  2. 查找蘋果和橙子的高斯金字塔(在此示例中, 級別數(shù)為6)
  3. 在高斯金字塔中,找到其拉普拉斯金字塔
  4. 然后在每個拉普拉斯金字塔級別中加入蘋果的左半部分和橙子的右半部分
  5. 最后從此聯(lián)合圖像金字塔中重建原始圖像。

下面是完整的代碼。(為簡單起見,每個步驟都是單獨進行的,這可能會占用更多的內(nèi)存。如果需要,可以對其進行優(yōu)化)。

import cv2 as cv
import numpy as np,sys
A = cv.imread('apple.jpg')
B = cv.imread('orange.jpg')
# 生成A的高斯金字塔
G = A.copy()
gpA = [G]
for i in xrange(6):
    G = cv.pyrDown(G)
    gpA.append(G)
# 生成B的高斯金字塔
G = B.copy()
gpB = [G]
for i in xrange(6):
    G = cv.pyrDown(G)
    gpB.append(G)
# 生成A的拉普拉斯金字塔
lpA = [gpA[5]]
for i in xrange(5,0,-1):
    GE = cv.pyrUp(gpA[i])
    L = cv.subtract(gpA[i-1],GE)
    lpA.append(L)
# 生成B的拉普拉斯金字塔
lpB = [gpB[5]]
for i in xrange(5,0,-1):
    GE = cv.pyrUp(gpB[i])
    L = cv.subtract(gpB[i-1],GE)
    lpB.append(L)
# 現(xiàn)在在每個級別中添加左右兩半圖像 
LS = []
for la,lb in zip(lpA,lpB):
    rows,cols,dpt = la.shape
    ls = np.hstack((la[:,0:cols/2], lb[:,cols/2:]))
    LS.append(ls)
# 現(xiàn)在重建
ls_ = LS[0]
for i in xrange(1,6):
    ls_ = cv.pyrUp(ls_)
    ls_ = cv.add(ls_, LS[i])
# 圖像與直接連接的每一半
real = np.hstack((A[:,:cols/2],B[:,cols/2:]))
cv.imwrite('Pyramid_blending2.jpg',ls_)
cv.imwrite('Direct_blending.jpg',real)
## 

附加資源

  1. Image Blending:http://pages.cs.wisc.edu/~csverma/CS766_09/ImageMosaic/imagemosaic.html

OpenCV-Python 輪廓:入門 | 二十一

目標

  • 了解輪廓是什么。
  • 學習查找輪廓,繪制輪廓等。
  • 你將看到以下功能:cv.findContours(),cv.drawContours()

什么是輪廓?

輪廓可以簡單地解釋為連接具有相同顏色或強度的所有連續(xù)點(沿邊界)的曲線。輪廓是用于形狀分析以及對象檢測和識別的有用工具。

  • 為了獲得更高的準確性,請使用二進制圖像。因此,在找到輪廓之前,請應用閾值或canny邊緣檢測。
  • 從OpenCV 3.2開始,findContours()不再修改源圖像。
  • 在OpenCV中,找到輪廓就像從黑色背景中找到白色物體。因此請記住,要找到的對象應該是白色,背景應該是黑色。

讓我們看看如何找到二進制圖像的輪廓:

import numpy as np
import cv2 as cv
im = cv.imread('test.jpg')
imgray = cv.cvtColor(im, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

findcontour()函數(shù)中有三個參數(shù),第一個是源圖像,第二個是輪廓檢索模式,第三個是輪廓逼近方法。輸出等高線和層次結(jié)構(gòu)。輪廓是圖像中所有輪廓的Python列表。每個單獨的輪廓是一個(x,y)坐標的Numpy數(shù)組的邊界點的對象。

注意
稍后我們將詳細討論第二和第三個參數(shù)以及有關(guān)層次結(jié)構(gòu)。在此之前,代碼示例中賦予它們的值將適用于所有圖像。

如何繪制輪廓?

要繪制輪廓,請使用cv.drawContours函數(shù)。只要有邊界點,它也可以用來繪制任何形狀。它的第一個參數(shù)是源圖像,第二個參數(shù)是應該作為Python列表傳遞的輪廓,第三個參數(shù)是輪廓的索引(在繪制單個輪廓時有用。要繪制所有輪廓,請傳遞-1),其余參數(shù)是顏色,厚度等等

  • 在圖像中繪制所有輪廓:
  cv.drawContours(img, contours, -1, (0,255,0), 3)
  • 繪制單個輪廓,如第四個輪廓:
  cv.drawContours(img, contours, 3, (0,255,0), 3) 
  • 但是在大多數(shù)情況下,以下方法會很有用:
  cnt = contours[4]
  cv.drawContours(img, [cnt], 0, (0,255,0), 3)

注意
最后兩種方法相似,但是前進時,您會發(fā)現(xiàn)最后一種更有用。

輪廓近似方法

這是cv.findContours函數(shù)中的第三個參數(shù)。它實際上表示什么?

上面我們告訴我們輪廓是強度相同的形狀的邊界。它存儲形狀邊界的(x,y)坐標。但是它存儲所有坐標嗎?這是通過這種輪廓近似方法指定的。

如果傳遞cv.CHAINAPPROXNONE,則將存儲所有邊界點。但是實際上我們需要所有這些要點嗎?例如,您找到了一條直線的輪廓。您是否需要線上的所有點來代表該線?不,我們只需要該線的兩個端點即可。這就是cv.CHAINAPPROXSIMPLE所做的。它刪除所有冗余點并壓縮輪廓,從而節(jié)省內(nèi)存。

下面的矩形圖像演示了此技術(shù)。只需在輪廓數(shù)組中的所有坐標上繪制一個圓(以藍色繪制)。第一幅圖像顯示了我用cv.CHAINAPPROXNONE獲得的積分(734個點),第二幅圖像顯示了我用cv.CHAINAPPROXSIMPLE獲得的效果(只有4個點)。看,它可以節(jié)省多少內(nèi)存!!!

OpenCV-Python教程上篇

 

OpenCV-Python 輪廓特征 | 二十二

目標

在本文中,我們將學習

  • 如何找到輪廓的不同特征,例如面積,周長,質(zhì)心,邊界框等。
  • 您將看到大量與輪廓有關(guān)的功能。

1. 特征矩

特征矩可以幫助您計算一些特征,例如物體的質(zhì)心,物體的面積等。請查看特征矩上的維基百科頁面。函數(shù)cv.moments()提供了所有計算出的矩值的字典。見下文:

import numpy as np
import cv2 as cv
img = cv.imread('star.jpg',0)
ret,thresh = cv.threshold(img,127,255,0)
contours,hierarchy = cv.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv.moments(cnt)
print( M )

從這一刻起,您可以提取有用的數(shù)據(jù),例如面積,質(zhì)心等。質(zhì)心由關(guān)系給出,$Cx = frac{M{10}}{M{00}}$ 和 $Cy = frac{M{01}}{M{00}}$。可以按照以下步驟進行:

cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])

2. 輪廓面積

輪廓區(qū)域由函數(shù)cv.contourArea()或從矩M['m00']中給出。

area = cv.contourArea(cnt) 

3. 輪廓周長

也稱為弧長。可以使用cv.arcLength()函數(shù)找到它。第二個參數(shù)指定形狀是閉合輪廓(True)還是曲線。

perimeter = cv.arcLength(cnt,True)

4. 輪廓近似

根據(jù)我們指定的精度,它可以將輪廓形狀近似為頂點數(shù)量較少的其他形狀。它是Douglas-Peucker算法的實現(xiàn)。檢查維基百科頁面上的算法和演示。

為了理解這一點,假設(shè)您試圖在圖像中找到一個正方形,但是由于圖像中的某些問題,您沒有得到一個完美的正方形,而是一個“壞形狀”(如下圖所示)。現(xiàn)在,您可以使用此功能來近似形狀。在這種情況下,第二個參數(shù)稱為epsilon,它是從輪廓到近似輪廓的最大距離。它是一個精度參數(shù)。需要正確選擇epsilon才能獲得正確的輸出。

epsilon = 0.1*cv.arcLength(cnt,True) 
approx = cv.approxPolyDP(cnt,epsilon,True)

下面,在第二張圖片中,綠線顯示了ε=弧長的10%時的近似曲線。第三幅圖顯示了ε=弧長度的1%時的情況。第三個參數(shù)指定曲線是否閉合。

OpenCV-Python教程上篇

 

5. 輪廓凸包

凸包外觀看起來與輪廓逼近相似,但不相似(在某些情況下兩者可能提供相同的結(jié)果)。在這里,cv.convexHull()函數(shù)檢查曲線是否存在凸凹缺陷并對其進行校正。一般而言,凸曲線是始終凸出或至少平坦的曲線。如果在內(nèi)部凸出,則稱為凸度缺陷。例如,檢查下面的手的圖像。紅線顯示手的凸包。雙向箭頭標記顯示凸度缺陷,這是凸包與輪廓線之間的局部最大偏差。

OpenCV-Python教程上篇

 

關(guān)于它的語法,有一些需要討論:

hull = cv.convexHull(points[, hull[, clockwise[, returnPoints]] 

參數(shù)詳細信息:

  • 是我們傳遞到的輪廓。
  • 凸包是輸出,通常我們忽略它。
  • 順時針方向:方向標記。如果為True,則輸出凸包為順時針方向。否則,其方向為逆時針方向。
  • returnPoints:默認情況下為True。然后返回凸包的坐標。如果為False,則返回與凸包點相對應的輪廓點的索引。

因此,要獲得如上圖所示的凸包,以下內(nèi)容就足夠了:

hull = cv.convexHull(cnt) 

但是,如果要查找凸度缺陷,則需要傳遞returnPoints = False。為了理解它,我們將拍攝上面的矩形圖像。首先,我發(fā)現(xiàn)它的輪廓為cnt。現(xiàn)在,我發(fā)現(xiàn)它的帶有returnPoints = True的凸包,得到以下值:[[[234 202]],[[51 202]],[[51 79]],[[234 79]]],它們是四個角 矩形的點。現(xiàn)在,如果對returnPoints = False執(zhí)行相同的操作,則會得到以下結(jié)果:[[129],[67],[0],[142]]。這些是輪廓中相應點的索引。例如,檢查第一個值:cnt [129] = [[234,202]]與第一個結(jié)果相同(對于其他結(jié)果依此類推)。

當我們討論凸度缺陷時,您將再次看到它。

6. 檢查凸度

cv.isContourConvex()具有檢查曲線是否凸出的功能。它只是返回True還是False。沒什么大不了的。

k = cv.isContourConvex(cnt) 

7. 邊界矩形

有兩種類型的邊界矩形。

7.a.直角矩形

它是一個矩形,不考慮物體的旋轉(zhuǎn)。所以邊界矩形的面積不是最小的。它是由函數(shù)cv.boundingRect()找到的。

令(x,y)為矩形的左上角坐標,而(w,h)為矩形的寬度和高度。

x,y,w,h = cv.boundingRect(cnt)
cv.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

7.b. 旋轉(zhuǎn)矩形

這里,邊界矩形是用最小面積繪制的,所以它也考慮了旋轉(zhuǎn)。使用的函數(shù)是cv.minAreaRect()。它返回一個Box2D結(jié)構(gòu),其中包含以下細節(jié) -(中心(x,y),(寬度,高度),旋轉(zhuǎn)角度)。但要畫出這個矩形,我們需要矩形的四個角。它由函數(shù)cv.boxPoints()獲得

rect = cv.minAreaRect(cnt)
box = cv.boxPoints(rect)
box = np.int0(box)
cv.drawContours(img,[box],0,(0,0,255),2)

兩個矩形都顯示在一張單獨的圖像中。綠色矩形顯示正常的邊界矩形。紅色矩形是旋轉(zhuǎn)后的矩形。

OpenCV-Python教程上篇

 

8. 最小閉合圈

接下來,使用函數(shù)**cv.minEnclosingCircle(*()查找對象的圓周。它是一個以最小面積完全覆蓋物體的圓。

(x,y),radius = cv.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv.circle(img,center,radius,(0,255,0),2)
OpenCV-Python教程上篇

 

9. 擬合一個橢圓

下一個是把一個橢圓擬合到一個物體上。它返回內(nèi)接橢圓的旋轉(zhuǎn)矩形。

ellipse = cv.fitEllipse(cnt)
cv.ellipse(img,ellipse,(0,255,0),2)
OpenCV-Python教程上篇

 

10. 擬合直線

同樣,我們可以將一條直線擬合到一組點。下圖包含一組白點。我們可以近似一條直線。

rows,cols = img.shape[:2]
[vx,vy,x,y] = cv.fitLine(cnt, cv.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
cv.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)

OpenCV-Python 輪廓屬性 | 二十三

目標

在這里,我們將學習提取一些常用的物體屬性,如堅實度,等效直徑,掩模圖像,平均強度等。更多的功能可以在Matlab regionprops文檔中找到。

(注:質(zhì)心、面積、周長等也屬于這一類,但我們在上一章已經(jīng)見過)

1. 長寬比

它是對象邊界矩形的寬度與高度的比值。

OpenCV-Python教程上篇

 

x,y,w,h = cv.boundingRect(cnt)
aspect_ratio = float(w)/h

2. 范圍

范圍是輪廓區(qū)域與邊界矩形區(qū)域的比值。

OpenCV-Python教程上篇

 

area = cv.contourArea(cnt)
x,y,w,h = cv.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area

3. 堅實度

堅實度是等高線面積與其凸包面積之比。

OpenCV-Python教程上篇

 

area = cv.contourArea(cnt)
hull = cv.convexHull(cnt)
hull_area = cv.contourArea(hull)
solidity = float(area)/hull_area

4. 等效直徑

等效直徑是面積與輪廓面積相同的圓的直徑。

OpenCV-Python教程上篇

 

area = cv.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)

5. 取向

取向是物體指向的角度。以下方法還給出了主軸和副軸的長度。

(x,y),(MA,ma),angle = cv.fitEllipse(cnt)

 

6. 掩碼和像素點

在某些情況下,我們可能需要構(gòu)成該對象的所有點。可以按照以下步驟完成:

mask = np.zeros(imgray.shape,np.uint8)
cv.drawContours(mask,[cnt],0,255,-1)
pixelpoints = np.transpose(np.nonzero(mask))
#pixelpoints = cv.findNonZero(mask)

這里提供了兩個方法,一個使用Numpy函數(shù),另一個使用OpenCV函數(shù)(最后的注釋行)。結(jié)果也是一樣的,只是略有不同。Numpy給出的坐標是(行、列)格式,而OpenCV給出的坐標是(x,y)格式。所以基本上答案是可以互換的。注意,row = x, column = y。

7. 最大值,最小值和它們的位置

我們可以使用掩碼圖像找到這些參數(shù)。

min_val, max_val, min_loc, max_loc = cv.minMaxLoc(imgray,mask = mask)

 

8. 平均顏色或平均強度

在這里,我們可以找到對象的平均顏色。或者可以是灰度模式下物體的平均強度。我們再次使用相同的掩碼進行此操作。

mean_val = cv.mean(im,mask = mask)

 

9. 極端點

極點是指對象的最頂部,最底部,最右側(cè)和最左側(cè)的點。

leftmost = tuple(cnt[cnt[:,:,0].argmin()][0])
rightmost = tuple(cnt[cnt[:,:,0].argmax()][0])
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
bottommost = tuple(cnt[cnt[:,:,1].argmax()][0])

例如,如果我將其應用于印度地圖,則會得到以下結(jié)果:

OpenCV-Python教程上篇

 

練習

  1. matlab的regionprops doc中仍然有一些特性。試著去實現(xiàn)它們。

OpenCV-Python 輪廓:更多的屬性 | 二十四

目標

在本章中,我們將學習

  • 凸性缺陷以及如何找到它們
  • 查找點到多邊形的最短距離
  • 匹配不同的形狀

理論和代碼

1. 凸性缺陷

我們看到了關(guān)于輪廓的第二章的凸包。從這個凸包上的任何偏差都可以被認為是凸性缺陷。OpenCV有一個函數(shù)來找到這個,cv.convexityDefects()。一個基本的函數(shù)調(diào)用如下:

hull = cv.convexHull(cnt,returnPoints = False)
defects = cv.convexityDefects(cnt,hull)

 

注意
記住,我們必須在發(fā)現(xiàn)凸包時,傳遞returnPoints= False,以找到凸性缺陷。

它返回一個數(shù)組,其中每行包含這些值—[起點、終點、最遠點、到最遠點的近似距離]。我們可以用圖像把它形象化。我們畫一條連接起點和終點的線,然后在最遠處畫一個圓。記住,返回的前三個值是cnt的索引。所以我們必須從cnt中獲取這些值。

import cv2 as cv
import numpy as np
img = cv.imread('star.jpg')
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret,thresh = cv.threshold(img_gray, 127, 255,0)
contours,hierarchy = cv.findContours(thresh,2,1)
cnt = contours[0]
hull = cv.convexHull(cnt,returnPoints = False)
defects = cv.convexityDefects(cnt,hull)
for i in range(defects.shape[0]):
    s,e,f,d = defects[i,0]
    start = tuple(cnt[s][0])
    end = tuple(cnt[e][0])
    far = tuple(cnt[f][0])
    cv.line(img,start,end,[0,255,0],2)
    cv.circle(img,far,5,[0,0,255],-1)
cv.imshow('img',img)
cv.waitKey(0)
cv.destroyAllWindows()

查看結(jié)果:

OpenCV-Python教程上篇

 

2. 點多邊形測試

這個函數(shù)找出圖像中一點到輪廓線的最短距離。它返回的距離,點在輪廓線外時為負,點在輪廓線內(nèi)時為正,點在輪廓線上時為零。

例如,我們可以檢查點(50,50)如下:

dist = cv.pointPolygonTest(cnt,(50,50),True)

在函數(shù)中,第三個參數(shù)是measuredist。如果它是真的,它會找到有符號的距離。如果為假,則查找該點是在輪廓線內(nèi)部還是外部(分別返回+1、-1和0)。

注意
如果您不想找到距離,請確保第三個參數(shù)為False,因為這是一個耗時的過程。因此,將其設(shè)置為False可使速度提高2-3倍。

3. 形狀匹配

OpenCV附帶一個函數(shù)cv.matchShapes(),該函數(shù)使我們能夠比較兩個形狀或兩個輪廓,并返回一個顯示相似性的度量。結(jié)果越低,匹配越好。它是根據(jù)矩值計算出來的。不同的測量方法在文檔中有解釋。

import cv2 as cv
import numpy as np
img1 = cv.imread('star.jpg',0)
img2 = cv.imread('star2.jpg',0)
ret, thresh = cv.threshold(img1, 127, 255,0)
ret, thresh2 = cv.threshold(img2, 127, 255,0)
contours,hierarchy = cv.findContours(thresh,2,1)
cnt1 = contours[0]
contours,hierarchy = cv.findContours(thresh2,2,1)
cnt2 = contours[0]
ret = cv.matchShapes(cnt1,cnt2,1,0.0)
print( ret )

我嘗試過匹配下面給出的不同形狀的形狀:

OpenCV-Python教程上篇

 

我得到以下結(jié)果:

  • 匹配的圖像A與本身= 0.0
  • 匹配圖像A與圖像B = 0.001946
  • 匹配圖像A與圖像C = 0.326911

看,即使是圖像旋轉(zhuǎn)也不會對這個比較產(chǎn)生很大的影響。

參考Hu矩是平移、旋轉(zhuǎn)和比例不變的七個矩。第七個是無偏斜量。這些值可以使用cpu.HuMoments()函數(shù)找到。

練習

  1. 檢查文檔中的cv.pointPolygonTest(),您可以找到紅色和藍色的漂亮圖像。它表示從所有像素到白色曲線的距離。曲線內(nèi)的所有像素都是藍色的,這取決于距離。外面的點也是紅色的。輪廓邊緣用白色標記。所以問題很簡單。編寫一個代碼來創(chuàng)建這樣的距離表示。
  2. 使用cv.matchShapes()比較數(shù)字或字母的圖像。(這是邁向OCR的簡單一步)

OpenCV-Python 輪廓分層 | 二十五

目標

這次我們學習輪廓的層次,即輪廓中的父子關(guān)系。

理論

在前幾篇關(guān)于輪廓的文章中,我們已經(jīng)討論了與OpenCV提供的輪廓相關(guān)的幾個函數(shù)。但是當我們使用cv.findcontour()函數(shù)在圖像中找到輪廓時,我們已經(jīng)傳遞了一個參數(shù),輪廓檢索模式。我們通常通過了cv.RETR_LISTcv.RETR_TREE,效果很好。但這到底意味著什么呢?

另外,在輸出中,我們得到了三個數(shù)組,第一個是圖像,第二個是輪廓,還有一個我們命名為hierarchy的輸出(請檢查前面文章中的代碼)。但我們從未在任何地方使用過這種層次結(jié)構(gòu)。那么這個層級是什么?它是用來做什么的?它與前面提到的函數(shù)參數(shù)有什么關(guān)系?

這就是我們在本文中要討論的內(nèi)容。

層次結(jié)構(gòu)是什么?

通常我們使用cv.findcontour()函數(shù)來檢測圖像中的對象,對吧?有時對象在不同的位置。但在某些情況下,某些形狀在其他形狀中。就像嵌套的圖形一樣。在這種情況下,我們把外部的稱為父類,把內(nèi)部的稱為子類。這樣,圖像中的輪廓就有了一定的相互關(guān)系。我們可以指定一個輪廓是如何相互連接的,比如,它是另一個輪廓的子輪廓,還是父輪廓等等。這種關(guān)系的表示稱為層次結(jié)構(gòu)

下面是一個例子:

OpenCV-Python教程上篇

 

在這張圖中,有一些形狀我已經(jīng)從0-5開始編號。2和2a表示最外層盒子的外部和內(nèi)部輪廓。

這里,等高線0,1,2在外部或最外面。我們可以說,它們在層級-0中,或者簡單地說,它們在同一個層級中。

其次是contour-2a。它可以被認為是contour-2的子級(或者反過來,contour-2是contour-2a的父級)。假設(shè)它在層級-1中。類似地,contour-3是contour-2的子級,它位于下一個層次結(jié)構(gòu)中。最后,輪廓4,5是contour-3a的子級,他們在最后一個層級。從對方框的編號來看,我認為contour-4是contour-3a的第一個子級(它也可以是contour-5)。

我提到這些是為了理解一些術(shù)語,比如相同層級外部輪廓子輪廓父輪廓第一個子輪廓等等。現(xiàn)在讓我們進入OpenCV。

OpenCV中的分級表示

所以每個輪廓都有它自己的信息關(guān)于它是什么層次,誰是它的孩子,誰是它的父母等等。OpenCV將它表示為一個包含四個值的數(shù)組:[Next, Previous, First_Child, Parent]

“Next表示同一層次的下一個輪廓。”

例如,在我們的圖片中取contour-0。誰是下一個同級別的等高線?這是contour-1。簡單地令Next = 1。類似地,Contour-1也是contour-2。所以Next = 2。contour-2呢?同一水平線上沒有下一條等高線。簡單地,讓Next = -1。contour-4呢?它與contour-5處于同一級別。它的下一條等高線是contour-5,所以next = 5。

“Previous表示同一層次上的先前輪廓。”

和上面一樣。contour-1之前的等值線為同級別的contour-0。類似地,contour-2也是contour-1。對于contour-0,沒有前項,所以設(shè)為-1。

“First_Child表示它的第一個子輪廓。”

沒有必要作任何解釋。對于contour-2, child是contour-2a。從而得到contour-2a對應的指標值。contour-3a呢?它有兩個孩子。但我們只關(guān)注第一個孩子。它是contour-4。那么First_Child = 4 對contour-3a而言。

“Parent表示其父輪廓的索引。”

它與First_Child相反。對于輪廓線-4和輪廓線-5,父輪廓線都是輪廓線-3a。對于輪廓3a,它是輪廓-3,以此類推。

注意
如果沒有子元素或父元素,則該字段被視為-1

現(xiàn)在我們已經(jīng)了解了OpenCV中使用的層次樣式,我們可以借助上面給出的相同圖像來檢查OpenCV中的輪廓檢索模式。一些標志如 cv.RETR_LISTcv.RETR_TREE,cv.RETR_CCOMPcv.RETR_EXTERNAL等等的含義。

輪廓檢索模式

 

1. RETR_LIST

這是四個標志中最簡單的一個(從解釋的角度來看)。它只是檢索所有的輪廓,但不創(chuàng)建任何親子關(guān)系。在這個規(guī)則下,父輪廓和子輪廓是平等的,他們只是輪廓。他們都屬于同一層級。

這里,第3和第4項總是-1。但是很明顯,下一項和上一項都有對應的值。你自己檢查一下就可以了。

下面是我得到的結(jié)果,每一行是對應輪廓的層次細節(jié)。例如,第一行對應于輪廓0。下一條輪廓是輪廓1。所以Next = 1。沒有先前的輪廓,所以Previous=-1。剩下的兩個,如前所述,是-1。

>>> hierarchy
array([[[ 1, -1, -1, -1],
        [ 2,  0, -1, -1],
        [ 3,  1, -1, -1],
        [ 4,  2, -1, -1],
        [ 5,  3, -1, -1],
        [ 6,  4, -1, -1],
        [ 7,  5, -1, -1],
        [-1,  6, -1, -1]]])

如果您沒有使用任何層次結(jié)構(gòu)特性,那么這是在您的代碼中使用的最佳選擇。

2. RETR_EXTERNAL

如果使用此標志,它只返回極端外部標志。所有孩子的輪廓都被留下了。我們可以說,根據(jù)這項規(guī)則,每個家庭只有長子得到關(guān)注。它不關(guān)心家庭的其他成員:)

所以在我們的圖像中,有多少個極端的外輪廓?在等級0級?有3個,即等值線是0 1 2,對吧?現(xiàn)在試著用這個標志找出等高線。這里,給每個元素的值與上面相同。并與上述結(jié)果進行了比較。以下是我得到的:

>>> hierarchy
array([[[ 1, -1, -1, -1],
        [ 2,  0, -1, -1],
        [-1,  1, -1, -1]]])

如果只想提取外部輪廓,可以使用此標志。它在某些情況下可能有用。

3. RETR_CCOMP

此標志檢索所有輪廓并將其排列為2級層次結(jié)構(gòu)。物體的外部輪廓(即物體的邊界)放在層次結(jié)構(gòu)-1中。對象內(nèi)部孔洞的輪廓(如果有)放在層次結(jié)構(gòu)-2中。如果其中有任何對象,則其輪廓僅在層次結(jié)構(gòu)1中重新放置。以及它在層級2中的漏洞等等。

只需考慮在黑色背景上的“白色的零”圖像。零的外圓屬于第一級,零的內(nèi)圓屬于第二級。

我們可以用一個簡單的圖像來解釋它。這里我用紅色標注了等高線的順序和它們所屬的層次,用綠色標注(1或2),順序與OpenCV檢測等高線的順序相同。

OpenCV-Python教程上篇

 

考慮第一個輪廓,即contour-0。這是hierarchy-1。它有兩個孔,分別是等高線1和2,屬于第二級。因此,對于輪廓-0,在同一層次的下一個輪廓是輪廓-3。previous也沒有。在hierarchy-2中,它的第一個子結(jié)點是contour-1。它沒有父類,因為它在hierarchy-1中。所以它的層次數(shù)組是[3,-1,1,-1]

現(xiàn)在contour-1。它在層級-2中。相同層次結(jié)構(gòu)中的下一個(在contour-1的父母關(guān)系下)是contour-2。沒有previous。沒有child,但是parent是contour-0。所以數(shù)組是[2,-1,-1,0]

類似的contour-2:它在hierarchy-2中。在contour-0下,同一層次結(jié)構(gòu)中沒有下一個輪廓。所以沒有Next。previous是contour-1。沒有child,parent是contour0。所以數(shù)組是[-1,1,-1,0]

contour-3:層次-1的下一個是輪廓-5。以前是contour-0。child是contour4,沒有parent。所以數(shù)組是[5,0,4,-1]

contour-4:它在contour-3下的層次結(jié)構(gòu)2中,它沒有兄弟姐妹。沒有next,沒有previous,沒有child,parent是contour-3。所以數(shù)組是[-1,-1,-1,3]

剩下的你可以補充。這是我得到的最終答案:

>>> hierarchy
array([[[ 3, -1,  1, -1],
        [ 2, -1, -1,  0],
        [-1,  1, -1,  0],
        [ 5,  0,  4, -1],
        [-1, -1, -1,  3],
        [ 7,  3,  6, -1],
        [-1, -1, -1,  5],
        [ 8,  5, -1, -1],
        [-1,  7, -1, -1]]])

 

4. RETR_TREE

這是最后一個家伙,完美先生。它檢索所有的輪廓并創(chuàng)建一個完整的家族層次結(jié)構(gòu)列表。它甚至告訴,誰是爺爺,父親,兒子,孫子,甚至更多…:)。

例如,我拿上面的圖片,重寫了cv的代碼。RETR_TREE,根據(jù)OpenCV給出的結(jié)果重新排序等高線并進行分析。同樣,紅色的字母表示輪廓數(shù),綠色的字母表示層次順序。

OpenCV-Python教程上篇

 

取contour-0:它在hierarchy-0中。同一層次結(jié)構(gòu)的next輪廓是輪廓-7。沒有previous的輪廓。child是contour-1,沒有parent。所以數(shù)組是[7,-1,1,-1]

以contour-2為例:它在hierarchy-1中。沒有輪廓在同一水平。沒有previous。child是contour-3。父母是contour-1。所以數(shù)組是[-1,-1,3,1]

剩下的,你自己試試。以下是完整答案:

>>> hierarchy
array([[[ 7, -1,  1, -1],
        [-1, -1,  2,  0],
        [-1, -1,  3,  1],
        [-1, -1,  4,  2],
        [-1, -1,  5,  3],
        [ 6, -1, -1,  4],
        [-1,  5, -1,  4],
        [ 8,  0, -1, -1],
        [-1,  7, -1, -1]]])

OpenCV-Python 直方圖-1:查找、繪制和分析 | 二十六

目標

學會

  • 使用OpenCV和Numpy函數(shù)查找直方圖
  • 使用OpenCV和Matplotlib函數(shù)繪制直方圖
  • 你將看到以下函數(shù):cv.calcHist(),np.histogram()等。

理論

那么直方圖是什么?您可以將直方圖視為圖形或繪圖,從而可以總體了解圖像的強度分布。它是在X軸上具有像素值(不總是從0到255的范圍),在Y軸上具有圖像中相應像素數(shù)的圖。

這只是理解圖像的另一種方式。通過查看圖像的直方圖,您可以直觀地了解該圖像的對比度,亮度,強度分布等。當今幾乎所有圖像處理工具都提供直方圖功能。以下是劍橋彩色網(wǎng)站的圖片,我建議您訪問該網(wǎng)站以獲取更多詳細信息。

OpenCV-Python教程上篇

 

您可以看到圖像及其直方圖。(請記住,此直方圖是針對灰度圖像而非彩色圖像繪制的)。直方圖的左側(cè)區(qū)域顯示圖像中較暗像素的數(shù)量,而右側(cè)區(qū)域則顯示明亮像素的數(shù)量。從直方圖中,您可以看到暗區(qū)域多于亮區(qū)域,而中間調(diào)的數(shù)量(中間值的像素值,例如127附近)則非常少。

尋找直方圖

現(xiàn)在我們有了一個關(guān)于直方圖的想法,我們可以研究如何找到它。OpenCV和Numpy都為此內(nèi)置了功能。在使用這些功能之前,我們需要了解一些與直方圖有關(guān)的術(shù)語。

BINS:上面的直方圖顯示每個像素值的像素數(shù),即從0到255。即,您需要256個值來顯示上面的直方圖。但是考慮一下,如果您不需要分別找到所有像素值的像素數(shù),而是找到像素值間隔中的像素數(shù)怎么辦?例如,您需要找到介于0到15之間的像素數(shù),然后找到16到31之間,...,240到255之間的像素數(shù)。只需要16個值即可表示直方圖。這就是在OpenCV教程中有關(guān)直方圖的示例中顯示的內(nèi)容。

因此,您要做的就是將整個直方圖分成16個子部分,每個子部分的值就是其中所有像素數(shù)的總和。每個子部分都稱為“ BIN”。在第一種情況下,bin的數(shù)量為256個(每個像素一個),而在第二種情況下,bin的數(shù)量僅為16個。BINS由OpenCV文檔中的histSize術(shù)語表示。

DIMS:這是我們?yōu)槠涫占瘮?shù)據(jù)的參數(shù)的數(shù)量。在這種情況下,我們僅收集關(guān)于強度值的一件事的數(shù)據(jù)。所以這里是1。

RANGE:這是您要測量的強度值的范圍。通常,它是[0,256],即所有強度值。

1. OpenCV中的直方圖計算

因此,現(xiàn)在我們使用cv.calcHist()函數(shù)查找直方圖。讓我們熟悉一下該函數(shù)及其參數(shù):

cv.calcHist(images,channels,mask,histSize,ranges [,hist [,accumulate]])

  1. images:它是uint8或float32類型的源圖像。它應該放在方括號中,即“ [img]”。
  2. channels:也以方括號給出。它是我們計算直方圖的通道的索引。例如,如果輸入為灰度圖像,則其值為[0]。對于彩色圖像,您可以傳遞[0],[1]或[2]分別計算藍色,綠色或紅色通道的直方圖。
  3. mask:圖像掩碼。為了找到完整圖像的直方圖,將其指定為“無”。但是,如果要查找圖像特定區(qū)域的直方圖,則必須為此創(chuàng)建一個掩碼圖像并將其作為掩碼。(我將在后面顯示一個示例。)
  4. histSize:這表示我們的BIN計數(shù)。需要放在方括號中。對于全尺寸,我們通過[256]。
  5. ranges:這是我們的RANGE。通常為[0,256]。

因此,讓我們從示例圖像開始。只需以灰度模式加載圖像并找到其完整直方圖即可。

img = cv.imread('home.jpg',0)
hist = cv.calcHist([img],[0],None,[256],[0,256])

hist是256x1的數(shù)組,每個值對應于該圖像中具有相應像素值的像素數(shù)。

2. numpy的直方圖計算

Numpy還為您提供了一個函數(shù)np.histogram()。因此,除了calcHist()函數(shù)外,您可以嘗試下面的代碼:

hist,bins = np.histogram(img.ravel(),256,[0,256])

hist與我們之前計算的相同。但是bin將具有257個元素,因為Numpy計算出bin的范圍為0-0.99、1-1.99、2-2.99等。因此最終范圍為255-255.99。為了表示這一點,他們還在最后添加了256。但是我們不需要256。最多255就足夠了。

  • 另外
    Numpy還有另一個函數(shù)np.bincount(),它比np.histogram()快10倍左右。因此,對于一維直方圖,您可以更好地嘗試一下。不要忘記在np.bincount中設(shè)置minlength = 256。例如,hist = np.bincount(img.ravel(),minlength = 256)

注意
OpenCV函數(shù)比np.histogram()快大約40倍。因此,盡可能使用OpenCV函數(shù)。

現(xiàn)在我們應該繪制直方圖,但是怎么繪制?

繪制直方圖

有兩種方法,

  1. 簡短的方法:使用Matplotlib繪圖功能
  2. 稍長的方法:使用OpenCV繪圖功能

1. 使用Matplotlib

Matplotlib帶有直方圖繪圖功能:matplotlib.pyplot.hist()它直接找到直方圖并將其繪制。您無需使用calcHist()或np.histogram()函數(shù)來查找直方圖。請參見下面的代碼:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('home.jpg',0)
plt.hist(img.ravel(),256,[0,256]); plt.show()

你將得到如下的結(jié)果:

OpenCV-Python教程上篇

 

或者,您可以使用matplotlib的法線圖,這對于BGR圖是很好的。為此,您需要首先找到直方圖數(shù)據(jù)。試試下面的代碼:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('home.jpg')
color = ('b','g','r')
for i,col in enumerate(color):
    histr = cv.calcHist([img],[i],None,[256],[0,256])
    plt.plot(histr,color = col)
    plt.xlim([0,256])
plt.show()

結(jié)果:

OpenCV-Python教程上篇

 

您可以從上圖中得出,藍色在圖像中具有一些高值域(顯然這應該是由于天空)

2. 使用 OpenCV

好吧,在這里您可以調(diào)整直方圖的值及其bin值,使其看起來像x,y坐標,以便您可以使用cv.line()或cv.polyline()函數(shù)繪制它以生成與上述相同的圖像。OpenCV-Python2官方示例已經(jīng)提供了此功能。檢查示例/python/hist.py中的代碼。

掩碼的應用

我們使用了cv.calcHist()來查找整個圖像的直方圖。如果你想找到圖像某些區(qū)域的直方圖呢?只需創(chuàng)建一個掩碼圖像,在你要找到直方圖為白色,否則黑色。然后把這個作為掩碼傳遞。

img = cv.imread('home.jpg',0)
# create a mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
masked_img = cv.bitwise_and(img,img,mask = mask)
# 計算掩碼區(qū)域和非掩碼區(qū)域的直方圖
# 檢查作為掩碼的第三個參數(shù)
hist_full = cv.calcHist([img],[0],None,[256],[0,256])
hist_mask = cv.calcHist([img],[0],mask,[256],[0,256])
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask,'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0,256])
plt.show()

查看結(jié)果。在直方圖中,藍線表示完整圖像的直方圖,綠線表示掩碼區(qū)域的直方圖。

OpenCV-Python教程上篇

 

附加資源

  1. Cambridge in Color website:http://www.cambridgeincolour.com/tutorials/histograms1.htm

OpenCV-Python 直方圖-2:直方圖均衡 | 二十七

目標

在本節(jié)中,我們將學習直方圖均衡化的概念,并利用它來提高圖像的對比度。

理論

考慮這樣一個圖像,它的像素值僅局限于某個特定的值范圍。例如,較亮的圖像將把所有像素限制在高值上。但是一幅好的圖像會有來自圖像所有區(qū)域的像素。因此,您需要將這個直方圖拉伸到兩端(如下圖所示,來自wikipedia),這就是直方圖均衡化的作用(簡單來說)。這通常會提高圖像的對比度。

OpenCV-Python教程上篇

 

我建議您閱讀直方圖均衡化上的Wikipedia頁面,以獲取有關(guān)它的更多詳細信息。它很好地解釋了示例,使您在閱讀完之后幾乎可以理解所有內(nèi)容。相反,在這里我們將看到其Numpy實現(xiàn)。之后,我們將看到OpenCV功能。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('wiki.jpg',0)
hist,bins = np.histogram(img.flatten(),256,[0,256])
cdf = hist.cumsum()
cdf_normalized = cdf * float(hist.max()) / cdf.max()
plt.plot(cdf_normalized, color = 'b')
plt.hist(img.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()
OpenCV-Python教程上篇

 

你可以看到直方圖位于較亮的區(qū)域。我們需要全頻譜。為此,我們需要一個轉(zhuǎn)換函數(shù),將亮區(qū)域的輸入像素映射到整個區(qū)域的輸出像素。這就是直方圖均衡化的作用。

現(xiàn)在我們找到最小的直方圖值(不包括0),并應用wiki頁面中給出的直方圖均衡化方程。但我在這里用過,來自Numpy的掩碼數(shù)組概念數(shù)組。對于掩碼數(shù)組,所有操作都在非掩碼元素上執(zhí)行。您可以從Numpy文檔中了解更多關(guān)于掩碼數(shù)組的信息。

cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
cdf = np.ma.filled(cdf_m,0).astype('uint8')

現(xiàn)在我們有了查找表,該表為我們提供了有關(guān)每個輸入像素值的輸出像素值是什么的信息。因此,我們僅應用變換。

img2 = cdf[img] 

現(xiàn)在,我們像以前一樣計算其直方圖和cdf(您這樣做),結(jié)果如下所示:

OpenCV-Python教程上篇

 

另一個重要的特征是,即使圖像是一個較暗的圖像(而不是我們使用的一個較亮的圖像),經(jīng)過均衡后,我們將得到幾乎相同的圖像。因此,這是作為一個“參考工具”,使所有的圖像具有相同的照明條件。這在很多情況下都很有用。例如,在人臉識別中,在對人臉數(shù)據(jù)進行訓練之前,對人臉圖像進行直方圖均衡化處理,使其具有相同的光照條件。

OpenCV中的直方圖均衡

OpenCV具有執(zhí)行此操作的功能cv.equalizeHist()。它的輸入只是灰度圖像,輸出是我們的直方圖均衡圖像。 下面是一個簡單的代碼片段,顯示了它與我們使用的同一圖像的用法:

img = cv.imread('wiki.jpg',0)
equ = cv.equalizeHist(img)
res = np.hstack((img,equ)) #stacking images side-by-side
cv.imwrite('res.png',res)
OpenCV-Python教程上篇

 

因此,現(xiàn)在您可以在不同的光照條件下拍攝不同的圖像,對其進行均衡并檢查結(jié)果。

當圖像的直方圖限制在特定區(qū)域時,直方圖均衡化效果很好。在直方圖覆蓋較大區(qū)域(即同時存在亮像素和暗像素)的強度變化較大的地方,效果不好。請檢查其他資源中的SOF鏈接。

CLAHE(對比度受限的自適應直方圖均衡)

我們剛剛看到的第一個直方圖均衡化考慮了圖像的整體對比度。在許多情況下,這不是一個好主意。例如,下圖顯示了輸入圖像及其在全局直方圖均衡后的結(jié)果。

OpenCV-Python教程上篇

 

直方圖均衡后,背景對比度確實得到了改善。但是在兩個圖像中比較雕像的臉。由于亮度過高,我們在那里丟失了大多數(shù)信息。這是因為它的直方圖不像我們在前面的案例中所看到的那樣局限于特定區(qū)域(嘗試繪制輸入圖像的直方圖,您將獲得更多的直覺)。

因此,為了解決這個問題,使用了自適應直方圖均衡。在這種情況下,圖像被分成稱為“tiles”的小塊(在OpenCV中,tileSize默認為8x8)。然后,像往常一樣對這些塊中的每一個進行直方圖均衡。因此,在較小的區(qū)域中,直方圖將限制在一個較小的區(qū)域中(除非存在噪聲)。如果有噪音,它將被放大。為了避免這種情況,應用了對比度限制。如果任何直方圖bin超出指定的對比度限制(在OpenCV中默認為40),則在應用直方圖均衡之前,將這些像素裁剪并均勻地分布到其他bin。均衡后,要消除圖塊邊界中的偽影,請應用雙線性插值。

下面的代碼片段顯示了如何在OpenCV中應用CLAHE:

import numpy as np
import cv2 as cv
img = cv.imread('tsukuba_l.png',0)
# create a CLAHE object (Arguments are optional).
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
cv.imwrite('clahe_2.jpg',cl1)

查看下面的結(jié)果,并將其與上面的結(jié)果進行比較,尤其是雕像區(qū)域:

OpenCV-Python教程上篇

 

附加資源

  1. Wikipedia page on Histogram Equalization:http://en.wikipedia.org/wiki/Histogram_equalization
  2. Masked Arrays in Numpy:http://docs.scipy.org/doc/numpy/reference/maskedarray.html)

有關(guān)對比度調(diào)整的問題:

  1. 如何在C中的OpenCV中調(diào)整對比度? http://stackoverflow.com/questions/10549245/how-can-i-adjust-contrast-in-opencv-in-c
  2. 如何使用opencv均衡圖像的對比度和亮度?http://stackoverflow.com/questions/10561222/how-do-i-equalize-contrast-brightness-of-images-using-opencv)

OpenCV-Python 直方圖-3:二維直方圖 | 二十八

目標

在本章中,我們將學習查找和繪制2D直方圖。這將在以后的章節(jié)中有所幫助。

介紹

在第一篇文章中,我們計算并繪制了一維直方圖。 之所以稱為一維,是因為我們僅考慮一個特征,即像素的灰度強度值。 但是在二維直方圖中,您要考慮兩個特征。 通常,它用于查找顏色直方圖,其中兩個特征是每個像素的色相和飽和度值。

已經(jīng)有一個python示例(samples / python / color_histogram.py)用于查找顏色直方圖。 我們將嘗試了解如何創(chuàng)建這種顏色直方圖,這對于理解諸如直方圖反向投影之類的更多主題將很有用。

OpenCV中的二維直方圖

它非常簡單,并且使用相同的函數(shù)cv.calcHist()進行計算。 對于顏色直方圖,我們需要將圖像從BGR轉(zhuǎn)換為HSV。(請記住,對于一維直方圖,我們從BGR轉(zhuǎn)換為灰度)。對于二維直方圖,其參數(shù)將進行如下修改:

  • channel = [0,1],因為我們需要同時處理H和S平面。
  • bins = [180,256] 對于H平面為180,對于S平面為256。
  • range = [0,180,0,256] 色相值介于0和180之間,飽和度介于0和256之間。

現(xiàn)在檢查以下代碼:

import numpy as np
import cv2 as cv
img = cv.imread('home.jpg')
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
hist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])

就是這樣。

Numpy中的二維直方圖

Numpy還為此提供了一個特定的函數(shù):np.histogram2d()。(記住,對于一維直方圖我們使用了np.histogram())。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('home.jpg')
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])

第一個參數(shù)是H平面,第二個是S平面,第三個是每個箱子的數(shù)量,第四個是它們的范圍。

現(xiàn)在我們可以檢查如何繪制這個顏色直方圖。

繪制二維直方圖

方法1:使用 cv.imshow()

我們得到的結(jié)果是尺寸為80x256的二維數(shù)組。因此,可以使用cv.imshow()函數(shù)像平常一樣顯示它們。它將是一幅灰度圖像,除非您知道不同顏色的色相值,否則不會對其中的顏色有太多了解。

方法2:使用Matplotlib

我們可以使用matplotlib.pyplot.imshow()函數(shù)繪制具有不同顏色圖的2D直方圖。它使我們對不同的像素密度有了更好的了解。但是,除非您知道不同顏色的色相值,否則乍一看并不能使我們知道到底是什么顏色。我還是更喜歡這種方法。它簡單而更好。

注意
使用此功能時,請記住,插值法應采用最近鄰以獲得更好的結(jié)果。

考慮下面的代碼:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('home.jpg')
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
hist = cv.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )
plt.imshow(hist,interpolation = 'nearest')
plt.show()

下面是輸入圖像及其顏色直方圖。X軸顯示S值,Y軸顯示色相。

OpenCV-Python教程上篇

 

在直方圖中,您可以在H = 100和S = 200附近看到一些較高的值。它對應于天空的藍色。同樣,在H = 25和S = 100附近可以看到另一個峰值。它對應于宮殿的黃色。您可以使用GIMP等任何圖像編輯工具進行驗證。

方法3:OpenCV示例樣式

OpenCV-Python2示例中有一個顏色直方圖的示例代碼(samples / python / color_histogram.py)。如果運行代碼,則可以看到直方圖也顯示了相應的顏色。或者簡單地,它輸出顏色編碼的直方圖。其結(jié)果非常好(盡管您需要添加額外的線束)。

在該代碼中,作者在HSV中創(chuàng)建了一個顏色圖。然后將其轉(zhuǎn)換為BGR。將所得的直方圖圖像與此顏色圖相乘。他還使用一些預處理步驟來刪除小的孤立像素,從而獲得良好的直方圖。

我將其留給讀者來運行代碼,對其進行分析并擁有自己的解決方法。下面是與上面相同的圖像的代碼輸出:

OpenCV-Python教程上篇

 

您可以在直方圖中清楚地看到存在什么顏色,那里是藍色,那里是黃色,并且由于棋盤的存在而有些白色。很好!

OpenCV-Python 直方圖-4:直方圖反投影 | 二十九

目標

在本章中,我們將學習直方圖反投影。

理論

這是由Michael J. SwainDana H. Ballard在他們的論文《通過顏色直方圖索引》中提出的。

用簡單的話說是什么意思?它用于圖像分割或在圖像中查找感興趣的對象。簡而言之,它創(chuàng)建的圖像大小與輸入圖像相同(但只有一個通道),其中每個像素對應于該像素屬于我們物體的概率。用更簡單的話來說,與其余部分相比,輸出圖像將在可能有對象的區(qū)域具有更多的白色值。好吧,這是一個直觀的解釋。(我無法使其更簡單)。直方圖反投影與camshift算法等配合使用。

我們該怎么做呢?我們創(chuàng)建一個圖像的直方圖,其中包含我們感興趣的對象(在我們的示例中是背景,離開播放器等)。對象應盡可能填充圖像以獲得更好的效果。而且顏色直方圖比灰度直方圖更可取,因為對象的顏色對比灰度強度是定義對象的好方法。然后,我們將該直方圖“反投影”到需要找到對象的測試圖像上,換句話說,我們計算出屬于背景的每個像素的概率并將其顯示出來。在適當?shù)拈撝迪庐a(chǎn)生的輸出使我們僅獲得背景。

Numpy中的算法

 

1.首先,我們需要計算我們要查找的對象(使其為“ M”)和要搜索的圖像(使其為“ I”)的顏色直方圖。

import numpy as np
import cv2 as cvfrom matplotlib import pyplot as plt
#roi是我們需要找到的對象或?qū)ο髤^(qū)域
roi = cv.imread('rose_red.png')
hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV)
#目標是我們搜索的圖像
target = cv.imread('rose.png')
hsvt = cv.cvtColor(target,cv.COLOR_BGR2HSV)
# 使用calcHist查找直方圖。也可以使用np.histogram2d完成
M = cv.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
I = cv.calcHist([hsvt],[0, 1], None, [180, 256], [0, 180, 0, 256] )

2.求出比值R=M/I。然后反向投影R,即使用R作為調(diào)色板,并以每個像素作為其對應的目標概率創(chuàng)建一個新圖像。即B(x,y) = R[h(x,y),s(x,y)] 其中h是色調(diào),s是像素在(x,y)的飽和度。之后,應用條件B(x,y) = min[B(x,y), 1]。

h,s,v = cv.split(hsvt)
B = R[h.ravel(),s.ravel()]
B = np.minimum(B,1)
B = B.reshape(hsvt.shape[:2])

3.現(xiàn)在對圓盤應用卷積,B = D * B,其中D是圓盤內(nèi)核。

disc = cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
cv.filter2D(B,-1,disc,B)
B = np.uint8(B)
cv.normalize(B,B,0,255,cv.NORM_MINMAX)

4.現(xiàn)在最大強度的位置給了我們物體的位置。如果我們期望圖像中有一個區(qū)域,則對合適的值進行閾值處理將獲得不錯的結(jié)果。

ret,thresh = cv.threshold(B,50,255,0) 

就是這樣!!

OpenCV的反投影

OpenCV提供了一個內(nèi)建的函數(shù)cv.calcBackProject()。它的參數(shù)幾乎與cv.calchist()函數(shù)相同。它的一個參數(shù)是直方圖,也就是物體的直方圖,我們必須找到它。另外,在傳遞給backproject函數(shù)之前,應該對對象直方圖進行歸一化。它返回概率圖像。然后我們用圓盤內(nèi)核對圖像進行卷積并應用閾值。下面是我的代碼和結(jié)果:

import numpy as np
import cv2 as cv
roi = cv.imread('rose_red.png')
hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV)
target = cv.imread('rose.png')
hsvt = cv.cvtColor(target,cv.COLOR_BGR2HSV)
# 計算對象的直方圖
roihist = cv.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
# 直方圖歸一化并利用反傳算法
cv.normalize(roihist,roihist,0,255,cv.NORM_MINMAX)
dst = cv.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)
# 用圓盤進行卷積
disc = cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
cv.filter2D(dst,-1,disc,dst)
# 應用閾值作與操作
ret,thresh = cv.threshold(dst,50,255,0)
thresh = cv.merge((thresh,thresh,thresh))
res = cv.bitwise_and(target,thresh)
res = np.vstack((target,thresh,res))
cv.imwrite('res.jpg',res)

以下是我處理過的一個示例。我將藍色矩形內(nèi)的區(qū)域用作示例對象,我想提取整個地面。

OpenCV-Python教程上篇

 

附加資源

  1. "Indexing via color histograms", Swain, Michael J. , Third international conference on computer vision,1990.

OpenCV-Python 傅里葉變換 | 三十

目標

在本節(jié)中,我們將學習

  • 使用OpenCV查找圖像的傅立葉變換
  • 利用Numpy中可用的FFT函數(shù)
  • 傅立葉變換的某些應用程序
  • 我們將看到以下函數(shù):cv.dft(),cv.idft()等

理論

傅立葉變換用于分析各種濾波器的頻率特性。對于圖像,使用2D離散傅里葉變換(DFT)查找頻域。一種稱為快速傅立葉變換(FFT)的快速算法用于DFT的計算。關(guān)于這些的詳細信息可以在任何圖像處理或信號處理教科書中找到。請參閱其他資源部分。

對于正弦信號$x(t) = A sin(2 pi ft)$,我們可以說$f$是信號的頻率,如果采用其頻域,則可以看到$f$的尖峰。如果對信號進行采樣以形成離散信號,我們將獲得相同的頻域,但是在$[-π,π]$或$[0,2π]$范圍內(nèi)(對于N點DFT為$[0,N]$)是周期性的。您可以將圖像視為在兩個方向上采樣的信號。因此,在X和Y方向都進行傅立葉變換,可以得到圖像的頻率表示。

更直觀地說,對于正弦信號,如果幅度在短時間內(nèi)變化如此之快,則可以說它是高頻信號。如果變化緩慢,則為低頻信號。您可以將相同的想法擴展到圖像。圖像中的振幅在哪里急劇變化?在邊緣點或噪聲。因此,可以說邊緣和噪聲是圖像中的高頻內(nèi)容。如果幅度沒有太大變化,則它是低頻分量。(一些鏈接已添加到“其他資源”,其中通過示例直觀地說明了頻率變換)。

現(xiàn)在,我們將看到如何找到傅立葉變換。

Numpy中的傅里葉變換

首先,我們將看到如何使用Numpy查找傅立葉變換。Numpy具有FFT軟件包來執(zhí)行此操作。np.fft.fft2()為我們提供了頻率轉(zhuǎn)換,它將是一個復雜的數(shù)組。它的第一個參數(shù)是輸入圖像,即灰度圖像。第二個參數(shù)是可選的,它決定輸出數(shù)組的大小。如果它大于輸入圖像的大小,則在計算FFT之前用零填充輸入圖像。如果小于輸入圖像,將裁切輸入圖像。如果未傳遞任何參數(shù),則輸出數(shù)組的大小將與輸入的大小相同。

現(xiàn)在,一旦獲得結(jié)果,零頻率分量(DC分量)將位于左上角。如果要使其居中,則需要在兩個方向上將結(jié)果都移動$frac{N}{2}$。只需通過函數(shù)np.fft.fftshift()即可完成。(它更容易分析)。找到頻率變換后,就可以找到幅度譜。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
Result look like below:

結(jié)果看起來像下面這樣:

OpenCV-Python教程上篇

 

看,您可以在中心看到更多白色區(qū)域,這表明低頻內(nèi)容更多。

因此,您發(fā)現(xiàn)了頻率變換現(xiàn)在,您可以在頻域中進行一些操作,例如高通濾波和重建圖像,即找到逆DFT。為此,您只需用尺寸為60x60的矩形窗口遮罩即可消除低頻。然后,使用np.fft.ifftshift()應用反向移位,以使DC分量再次出現(xiàn)在左上角。然后使用np.ifft2()函數(shù)找到逆FFT。同樣,結(jié)果將是一個復數(shù)。您可以采用其絕對值。

rows, cols = img.shape
crow,ccol = rows//2 , cols//2
fshift[crow-30:crow+31, ccol-30:ccol+31] = 0
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.real(img_back)
plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(img_back, cmap = 'gray')
plt.title('Image after HPF'), plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])
plt.show()

結(jié)果看起來像下面這樣:

OpenCV-Python教程上篇

 

結(jié)果表明高通濾波是邊緣檢測操作。這就是我們在“圖像漸變”一章中看到的。這也表明大多數(shù)圖像數(shù)據(jù)都存在于頻譜的低頻區(qū)域。無論如何,我們已經(jīng)看到了如何在Numpy中找到DFT,IDFT等。現(xiàn)在,讓我們看看如何在OpenCV中進行操作。如果您仔細觀察結(jié)果,尤其是最后一張JET顏色的圖像,您會看到一些偽像(我用紅色箭頭標記的一個實例)。它在那里顯示出一些波紋狀結(jié)構(gòu),稱為振鈴效應。這是由我們用于遮罩的矩形窗口引起的。此掩碼轉(zhuǎn)換為正弦形狀,從而導致此問題。因此,矩形窗口不用于過濾。更好的選擇是高斯窗口。

OpenCV中的傅里葉變換

OpenCV為此提供了cv.dft()和cv.idft()函數(shù)。它返回與前一個相同的結(jié)果,但是有兩個通道。第一個通道是結(jié)果的實部,第二個通道是結(jié)果的虛部。輸入圖像首先應轉(zhuǎn)換為np.float32。我們來看看怎么做。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = 20*np.log(cv.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

 

注意
您還可以使用cv.cartToPolar(),它在單個鏡頭中同時返回幅值和相位

現(xiàn)在我們要做DFT的逆變換。在上一節(jié)中,我們創(chuàng)建了一個HPF,這次我們將看到如何刪除圖像中的高頻內(nèi)容,即我們將LPF應用到圖像中。它實際上模糊了圖像。為此,我們首先創(chuàng)建一個高值(1)在低頻部分,即我們過濾低頻內(nèi)容,0在高頻區(qū)。

rows, cols = img.shape
crow,ccol = rows/2 , cols/2
# 首先創(chuàng)建一個掩碼,中心正方形為1,其余全為零
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
# 應用掩碼和逆DFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv.idft(f_ishift)
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

看看結(jié)果:

OpenCV-Python教程上篇

 

注意
通常,OpenCV函數(shù)cv.dft()和cv.idft()比Numpy函數(shù)更快。但是Numpy函數(shù)更容易使用。有關(guān)性能問題的更多細節(jié),請參見下面的部分。

DFT的性能優(yōu)化

對于某些數(shù)組尺寸,DFT的計算性能較好。當數(shù)組大小為2的冪時,速度最快。對于大小為2、3和5的乘積的數(shù)組,也可以非常有效地進行處理。因此,如果您擔心代碼的性能,可以在找到DFT之前將數(shù)組的大小修改為任何最佳大小(通過填充零)。對于OpenCV,您必須手動填充零。但是對于Numpy,您指定FFT計算的新大小,它將自動為您填充零。

那么如何找到最優(yōu)的大小呢?OpenCV為此提供了一個函數(shù),cv.getOptimalDFTSize()。它同時適用于cv.dft()和np.fft.fft2()。讓我們使用IPython魔術(shù)命令timeit來檢查它們的性能。

In [16]: img = cv.imread('messi5.jpg',0)
In [17]: rows,cols = img.shape
In [18]: print("{} {}".format(rows,cols))
342 548
In [19]: nrows = cv.getOptimalDFTSize(rows)
In [20]: ncols = cv.getOptimalDFTSize(cols)
In [21]: print("{} {}".format(nrows,ncols))
360 576

參見,將大小(342,548)修改為(360,576)。現(xiàn)在讓我們用零填充(對于OpenCV),并找到其DFT計算性能。您可以通過創(chuàng)建一個新的零數(shù)組并將數(shù)據(jù)復制到其中來完成此操作,或者使用cv.copyMakeBorder()。

nimg = np.zeros((nrows,ncols))
nimg[:rows,:cols] = img

或者:

right = ncols - cols
bottom = nrows - rows
bordertype = cv.BORDER_CONSTANT #只是為了避免PDF文件中的行中斷
nimg = cv.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0)

現(xiàn)在,我們計算Numpy函數(shù)的DFT性能比較:

In [22]: %timeit fft1 = np.fft.fft2(img)
10 loops, best of 3: 40.9 ms per loop
In [23]: %timeit fft2 = np.fft.fft2(img,[nrows,ncols])
100 loops, best of 3: 10.4 ms per loop

它顯示了4倍的加速。現(xiàn)在,我們將嘗試使用OpenCV函數(shù)。

In [24]: %timeit dft1= cv.dft(np.float32(img),flags=cv.DFT_COMPLEX_OUTPUT)
100 loops, best of 3: 13.5 ms per loop
In [27]: %timeit dft2= cv.dft(np.float32(nimg),flags=cv.DFT_COMPLEX_OUTPUT)
100 loops, best of 3: 3.11 ms per loop

它還顯示了4倍的加速。您還可以看到OpenCV函數(shù)比Numpy函數(shù)快3倍左右。也可以對逆FFT進行測試,這留給您練習。

為什么拉普拉斯算子是高通濾波器?

在一個論壇上也有人提出了類似的問題。問題是,為什么拉普拉斯變換是高通濾波器?為什么Sobel是HPF?等。第一個答案是關(guān)于傅里葉變換的。對于更大的FFT只需要拉普拉斯變換。分析下面的代碼:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 沒有縮放參數(shù)的簡單均值濾波器
mean_filter = np.ones((3,3))
# 創(chuàng)建高斯濾波器
x = cv.getGaussianKernel(5,10)
gaussian = x*x.T
# 不同的邊緣檢測濾波器
# x方向上的scharr
scharr = np.array([[-3, 0, 3],
                   [-10,0,10],
                   [-3, 0, 3]])
# x方向上的sobel
sobel_x= np.array([[-1, 0, 1],
                   [-2, 0, 2],
                   [-1, 0, 1]])
# y方向上的sobel
sobel_y= np.array([[-1,-2,-1],
                   [0, 0, 0],
                   [1, 2, 1]])
# 拉普拉斯變換
laplacian=np.array([[0, 1, 0],
                    [1,-4, 1],
                    [0, 1, 0]])
filters = [mean_filter, gaussian, laplacian, sobel_x, sobel_y, scharr]
filter_name = ['mean_filter', 'gaussian','laplacian', 'sobel_x', 
                'sobel_y', 'scharr_x']
fft_filters = [np.fft.fft2(x) for x in filters]
fft_shift = [np.fft.fftshift(y) for y in fft_filters]
mag_spectrum = [np.log(np.abs(z)+1) for z in fft_shift]
for i in xrange(6):
    plt.subplot(2,3,i+1),plt.imshow(mag_spectrum[i],cmap = 'gray')
    plt.title(filter_name[i]), plt.xticks([]), plt.yticks([])
plt.show()

看看結(jié)果:

OpenCV-Python教程上篇

 

從圖像中,您可以看到每種內(nèi)核阻止的頻率區(qū)域以及它允許經(jīng)過的區(qū)域。從這些信息中,我們可以說出為什么每個內(nèi)核都是HPF或LPF

附加資源

1.傅里葉變換的直觀解釋:

http://cns-alumni.bu.edu/~slehar/fourier/fourier.html by Steven Lehar

  1. 傅里葉變換:http://homepages.inf.ed.ac.uk/rbf/HIPR2/fourier.htm at HIPR
  2. 圖像中的頻率域指什么?http://dsp.stackexchange.com/q/1637/818

OpenCV-Python 模板匹配 | 三十一

目標

在本章中,您將學習

  • 使用模板匹配在圖像中查找對象
  • 你將看到以下功能:cv.matchTemplate(),cv.minMaxLoc()

理論

模板匹配是一種用于在較大圖像中搜索和查找模板圖像位置的方法。為此,OpenCV帶有一個函數(shù)cv.matchTemplate()。它只是將模板圖??像滑動到輸入圖像上(就像在2D卷積中一樣),然后在模板圖像下比較模板和輸入圖像的拼圖。OpenCV中實現(xiàn)了幾種比較方法。(您可以檢查文檔以了解更多詳細信息)。它返回一個灰度圖像,其中每個像素表示該像素的鄰域與模板匹配的程度。

如果輸入圖像的大小為(WxH),而模板圖像的大小為(wxh),則輸出圖像的大小將為(W-w + 1,H-h + 1)。得到結(jié)果后,可以使用cv.minMaxLoc()函數(shù)查找最大/最小值在哪。將其作為矩形的左上角,并以(w,h)作為矩形的寬度和高度。該矩形是您模板的區(qū)域。

注意
如果使用cv.TM_SQDIFF作為比較方法,則最小值提供最佳匹配。

OpenCV中的模板匹配

作為示例,我們將在梅西的照片中搜索他的臉。所以我創(chuàng)建了一個模板,如下所示:

OpenCV-Python教程上篇

 

我們將嘗試所有比較方法,以便我們可以看到它們的結(jié)果如何:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
img2 = img.copy()
template = cv.imread('template.jpg',0)
w, h = template.shape[::-1]
# 列表中所有的6種比較方法
methods = ['cv.TM_CCOEFF', 'cv.TM_CCOEFF_NORMED', 'cv.TM_CCORR',
            'cv.TM_CCORR_NORMED', 'cv.TM_SQDIFF', 'cv.TM_SQDIFF_NORMED']
for meth in methods:
    img = img2.copy()
    method = eval(meth)
    # 應用模板匹配
    res = cv.matchTemplate(img,template,method)
    min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
    # 如果方法是TM_SQDIFF或TM_SQDIFF_NORMED,則取最小值
    if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)
    cv.rectangle(img,top_left, bottom_right, 255, 2)
    plt.subplot(121),plt.imshow(res,cmap = 'gray')
    plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(img,cmap = 'gray')
    plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
    plt.suptitle(meth)
    plt.show()

查看以下結(jié)果:

  • cv.TM_CCOEFF
OpenCV-Python教程上篇

 

  • cv.TMCCOEFFNORMED
  • cv.TM_CCORR
  • cv.TMCCORRNORMED
  • cv.TM_SQDIFF
  • cv.TMSQDIFFNORMED

您會看到,使用cv.TM_CCORR的結(jié)果并不理想。

多對象的模板匹配

在上一節(jié)中,我們在圖像中搜索了梅西的臉,該臉在圖像中僅出現(xiàn)一次。假設(shè)您正在搜索具有多次出現(xiàn)的對象,則cv.minMaxLoc()不會為您提供所有位置。在這種情況下,我們將使用閾值化。因此,在此示例中,我們將使用著名游戲Mario的屏幕截圖,并在其中找到硬幣。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img_rgb = cv.imread('mario.png')
img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
template = cv.imread('mario_coin.png',0)
w, h = template.shape[::-1]
res = cv.matchTemplate(img_gray,template,cv.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
    cv.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
cv.imwrite('res.png',img_rgb)

結(jié)果:

OpenCV-Python教程上篇

 

OpenCV-Python 霍夫線變換 | 三十二

目標

在這一章當中,

  • 我們將了解霍夫變換的概念。
  • 我們將看到如何使用它來檢測圖像中的線條。
  • 我們將看到以下函數(shù):cv.HoughLines(),cv.HoughLinesP()

理論

如果可以用數(shù)學形式表示形狀,則霍夫變換是一種檢測任何形狀的流行技術(shù)。即使形狀有些破損或變形,也可以檢測出形狀。我們將看到它如何作用于一條線。

一條線可以表示為$y = mx + c$或以參數(shù)形式表示為$rho=xcosθ+ysinθ$,其中$rho$是從原點到該線的垂直距離,而$theta$是由該垂直線和水平軸形成的角度以逆時針方向測量(該方向隨您如何表示坐標系而變化。此表示形式在OpenCV中使用)。查看下面的圖片:

OpenCV-Python教程上篇

 

因此,如果線在原點下方通過,則它將具有正的$rho$且角度小于180。如果線在原點上方,則將角度取為小于180,而不是大于180的角度。$rho$取負值。任何垂直線將具有0度,水平線將具有90度。

現(xiàn)在,讓我們看一下霍夫變換如何處理線條。任何一條線都可以用$(ρ,θ)$這兩個術(shù)語表示。因此,首先創(chuàng)建2D數(shù)組或累加器(以保存兩個參數(shù)的值),并將其初始設(shè)置為$0$。讓行表示$ρ$,列表示$θ$。陣列的大小取決于所需的精度。假設(shè)您希望角度的精度為1度,則需要180列。對于$ρ$,最大距離可能是圖像的對角線長度。因此,以一個像素精度為準,行數(shù)可以是圖像的對角線長度。

考慮一個100x100的圖像,中間有一條水平線。取直線的第一點。您知道它的(x,y)值。現(xiàn)在在線性方程式中,將值$θ$= 0,1,2,..... 180放進去,然后檢查得到$ρ$。對于每對$(ρ,θ)$,在累加器中對應的$(ρ,θ)$單元格將值增加1。所以現(xiàn)在在累加器中,單元格(50,90)= 1以及其他一些單元格。

現(xiàn)在,對行的第二個點。執(zhí)行與上述相同的操作。遞增$(rho,theta)$對應的單元格中的值。這次,單元格(50,90)=2。實際上,您正在對$(ρ,θ)$值進行投票。您對線路上的每個點都繼續(xù)執(zhí)行此過程。在每個點上,單元格(50,90)都會增加或投票,而其他單元格可能會或可能不會投票。這樣一來,最后,單元格(50,90)的投票數(shù)將最高。因此,如果您在累加器中搜索最大票數(shù),則將獲得(50,90)值,該值表示該圖像中的一條線與原點的距離為50,角度為90度。在下面的動畫中很好地顯示了該圖片(圖片提供:Amos Storkey)

OpenCV-Python教程上篇

 

這就是霍夫變換對線條的工作方式。它很簡單,也許您可??以自己使用Numpy來實現(xiàn)它。下圖顯示了累加器。某些位置的亮點表示它們是圖像中可能的線條的參數(shù)。(圖片由維基百科提供)

OpenCV-Python教程上篇

 

OpenCV中的霍夫曼變換

上面說明的所有內(nèi)容都封裝在OpenCV函數(shù)cv.HoughLines()中。它只是返回一個:math:(rho,theta)值的數(shù)組。$ρ$以像素為單位,$θ$以弧度為單位。第一個參數(shù),輸入圖像應該是二進制圖像,因此在應用霍夫變換之前,請應用閾值或使用Canny邊緣檢測。第二和第三參數(shù)分別是$ρ$和$θ$精度。第四個參數(shù)是閾值,這意味著應該將其視為行的最低投票。請記住,票數(shù)取決于線上的點數(shù)。因此,它表示應檢測到的最小線長。

import cv2 as cv
import numpy as np
img = cv.imread(cv.samples.findFile('sudoku.png'))
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150,apertureSize = 3)
lines = cv.HoughLines(edges,1,np.pi/180,200)
for line in lines:
    rho,theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a*rho
    y0 = b*rho
    x1 = int(x0 + 1000*(-b))
    y1 = int(y0 + 1000*(a))
    x2 = int(x0 - 1000*(-b))
    y2 = int(y0 - 1000*(a))
    cv.line(img,(x1,y1),(x2,y2),(0,0,255),2)
cv.imwrite('houghlines3.jpg',img)

檢查下面的結(jié)果

OpenCV-Python教程上篇

 

概率霍夫變換

在霍夫變換中,您可以看到,即使對于帶有兩個參數(shù)的行,也需要大量計算。概率霍夫變換是我們看到的霍夫變換的優(yōu)化。它沒有考慮所有要點。取而代之的是,它僅采用隨機的點子集,足以進行線檢測。只是我們必須降低閾值。參見下圖,比較了霍夫空間中的霍夫變換和概率霍夫變換。(圖片提供:Franck Bettinger的主頁)

OpenCV-Python教程上篇

 

OpenCV的實現(xiàn)基于Matas,J.和Galambos,C.和Kittler, J.V.使用漸進概率霍夫變換對行進行的穩(wěn)健檢測[145]。使用的函數(shù)是**cv.HoughLinesP**()。它有兩個新的論點。

  • minLineLength - 最小行長。小于此長度的線段將被拒絕。
  • maxLineGap - 線段之間允許將它們視為一條線的最大間隙。

最好的是,它直接返回行的兩個端點。在以前的情況下,您僅獲得線的參數(shù),并且必須找到所有點。在這里,一切都是直接而簡單的。

import cv2 as cv
import numpy as np
img = cv.imread(cv.samples.findFile('sudoku.png'))
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150,apertureSize = 3)
lines = cv.HoughLinesP(edges,1,np.pi/180,100,minLineLength=100,maxLineGap=10)
for line in lines:
    x1,y1,x2,y2 = line[0]
    cv.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv.imwrite('houghlines5.jpg',img)

看到如下結(jié)果:

OpenCV-Python教程上篇

 

附加資源

  1. Hough Transform on Wikipedia:http://en.wikipedia.org/wiki/Hough_transform

OpenCV-Python 霍夫圈變換 | 三十三

學習目標

在本章中,

  • 我們將學習使用霍夫變換來查找圖像中的圓。
  • 我們將看到以下函數(shù):cv.HoughCircles()

理論

圓在數(shù)學上表示為(x-x_center)^2+(y-y_center)^2 = r^2,其中(x_center,y_center)是圓的中心,r是圓的半徑。從等式中,我們可以看到我們有3個參數(shù),因此我們需要3D累加器進行霍夫變換,這將非常低效。因此,OpenCV使用更加技巧性的方法,即使用邊緣的梯度信息的Hough梯度方法

我們在這里使用的函數(shù)是cv.HoughCircles()。它有很多參數(shù),這些參數(shù)在文檔中有很好的解釋。因此,我們直接轉(zhuǎn)到代碼。

import numpy as np
import cv2 as cv
img = cv.imread('opencv-logo-white.png',0)
img = cv.medianBlur(img,5)
cimg = cv.cvtColor(img,cv.COLOR_GRAY2BGR)
circles = cv.HoughCircles(img,cv.HOUGH_GRADIENT,1,20,
                            param1=50,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
    # 繪制外圓
    cv.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
    # 繪制圓心
    cv.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv.imshow('detected circles',cimg)
cv.waitKey(0)
cv.destroyAllWindows()

結(jié)果如下:

OpenCV-Python教程上篇

 

OpenCV-Python 圖像分割與Watershed算法 | 三十四

目標

在本章中,

  • 我們將學習使用分水嶺算法實現(xiàn)基于標記的圖像分割
  • 我們將看到:cv.watershed()

理論

任何灰度圖像都可以看作是一個地形表面,其中高強度表示山峰,低強度表示山谷。你開始用不同顏色的水(標簽)填充每個孤立的山谷(局部最小值)。隨著水位的上升,根據(jù)附近的山峰(坡度),來自不同山谷的水明顯會開始合并,顏色也不同。為了避免這種情況,你要在水融合的地方建造屏障。你繼續(xù)填滿水,建造障礙,直到所有的山峰都在水下。然后你創(chuàng)建的屏障將返回你的分割結(jié)果。這就是Watershed背后的“思想”。你可以訪問Watershed的CMM網(wǎng)頁,了解它與一些動畫的幫助。

但是這種方法會由于圖像中的噪聲或其他不規(guī)則性而產(chǎn)生過度分割的結(jié)果。因此OpenCV實現(xiàn)了一個基于標記的分水嶺算法,你可以指定哪些是要合并的山谷點,哪些不是。這是一個交互式的圖像分割。我們所做的是給我們知道的對象賦予不同的標簽。用一種顏色(或強度)標記我們確定為前景或?qū)ο蟮膮^(qū)域,用另一種顏色標記我們確定為背景或非對象的區(qū)域,最后用0標記我們不確定的區(qū)域。這是我們的標記。然后應用分水嶺算法。然后我們的標記將使用我們給出的標簽進行更新,對象的邊界值將為-1。

代碼

下面我們將看到一個有關(guān)如何使用距離變換和分水嶺來分割相互接觸的對象的示例。

考慮下面的硬幣圖像,硬幣彼此接觸。即使你設(shè)置閾值,它也會彼此接觸。

OpenCV-Python教程上篇

 

我們先從尋找硬幣的近似估計開始。因此,我們可以使用Otsu的二值化。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('coins.png')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV+cv.THRESH_OTSU)
OpenCV-Python教程上篇

 

現(xiàn)在我們需要去除圖像中的任何白點噪聲。為此,我們可以使用形態(tài)學擴張。要去除對象中的任何小孔,我們可以使用形態(tài)學侵蝕。因此,現(xiàn)在我們可以確定,靠近對象中心的區(qū)域是前景,而離對象中心很遠的區(qū)域是背景。我們不確定的唯一區(qū)域是硬幣的邊界區(qū)域。

因此,我們需要提取我們可確定為硬幣的區(qū)域。侵蝕會去除邊界像素。因此,無論剩余多少,我們都可以肯定它是硬幣。如果物體彼此不接觸,那將起作用。但是,由于它們彼此接觸,因此另一個好選擇是找到距離變換并應用適當?shù)拈撝怠=酉聛恚覀冃枰业轿覀兇_定它們不是硬幣的區(qū)域。為此,我們擴張了結(jié)果。膨脹將對象邊界增加到背景。這樣,由于邊界區(qū)域已刪除,因此我們可以確保結(jié)果中背景中的任何區(qū)域?qū)嶋H上都是背景。參見下圖。

OpenCV-Python教程上篇

 

剩下的區(qū)域是我們不知道的區(qū)域,無論是硬幣還是背景。分水嶺算法應該找到它。這些區(qū)域通常位于前景和背景相遇(甚至兩個不同的硬幣相遇)的硬幣邊界附近。我們稱之為邊界。可以通過從sure_bg區(qū)域中減去sure_fg區(qū)域來獲得。

# 噪聲去除
kernel = np.ones((3,3),np.uint8)
opening = cv.morphologyEx(thresh,cv.MORPH_OPEN,kernel, iterations = 2)
# 確定背景區(qū)域
sure_bg = cv.dilate(opening,kernel,iterations=3)
# 尋找前景區(qū)域
dist_transform = cv.distanceTransform(opening,cv.DIST_L2,5)
ret, sure_fg = cv.threshold(dist_transform,0.7*dist_transform.max(),255,0)
# 找到未知區(qū)域
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg,sure_fg)

查看結(jié)果。在閾值圖像中,我們得到了一些硬幣區(qū)域,我們確定它們是硬幣,并且現(xiàn)在已分離它們。(在某些情況下,你可能只對前景分割感興趣,而不對分離相互接觸的對象感興趣。在那種情況下,你無需使用距離變換,只需侵蝕就足夠了。侵蝕只是提取確定前景區(qū)域的另一種方法。)

OpenCV-Python教程上篇

 

現(xiàn)在我們可以確定哪些是硬幣的區(qū)域,哪些是背景。因此,我們創(chuàng)建了標記(它的大小與原始圖像的大小相同,但具有int32數(shù)據(jù)類型),并標記其中的區(qū)域。我們肯定知道的區(qū)域(無論是前景還是背景)都標有任何正整數(shù),但是帶有不同的整數(shù),而我們不確定的區(qū)域則保留為零。為此,我們使用cv.connectedComponents()。它用0標記圖像的背景,然后其他對象用從1開始的整數(shù)標記。

但是我們知道,如果背景標記為0,則分水嶺會將其視為未知區(qū)域。所以我們想用不同的整數(shù)來標記它。相反,我們將未知定義的未知區(qū)域標記為0。

# 類別標記
ret, markers = cv.connectedComponents(sure_fg)
# 為所有的標記加1,保證背景是0而不是1
markers = markers+1
# 現(xiàn)在讓所有的未知區(qū)域為0
markers[unknown==255] = 0

參見JET colormap中顯示的結(jié)果。深藍色區(qū)域顯示未知區(qū)域。當然,硬幣的顏色不同。剩下,肯定為背景的區(qū)域顯示在較淺的藍色,跟未知區(qū)域相比。

OpenCV-Python教程上篇

 

現(xiàn)在我們的標記已準備就緒。現(xiàn)在是最后一步的時候了,使用分水嶺算法。然后標記圖像將被修改。邊界區(qū)域?qū)擞洖?1。

markers = cv.watershed(img,markers) 
img[markers == -1] = [255,0,0]

請參閱下面的結(jié)果。對某些硬幣,它們接觸的區(qū)域被正確地分割,而對于某些硬幣,卻不是。

OpenCV-Python教程上篇

 

附加資源

  1. CMM page on http://cmm.ensmp.fr/~beucher/wtshed.html

練習

  1. OpenCV samples has an interactive sample on watershed segmentation, watershed.py. Run it, Enjoy it, then learn it.

OpenCV-Python 交互式前景提取使用GrabCut算法 | 三十五

目標

在本章中,

  • 我們將看到GrabCut算法來提取圖像中的前景
  • 我們將為此創(chuàng)建一個交互式應用程序。

理論

GrabCut算法由英國微軟研究院的Carsten Rother,Vladimir Kolmogorov和Andrew Blake設(shè)計。在他們的論文“GrabCut”中:使用迭代圖割的交互式前景提取。需要用最少的用戶交互進行前景提取的算法,結(jié)果是GrabCut。

從用戶角度來看,它是如何工作的?最初,用戶在前景區(qū)域周圍繪制一個矩形(前景區(qū)域應完全位于矩形內(nèi)部)。然后,算法會對其進行迭代分割,以獲得最佳結(jié)果。做完了但在某些情況下,分割可能不會很好,例如,可能已將某些前景區(qū)域標記為背景,反之亦然。在這種情況下,需要用戶進行精修。只需在圖像錯誤分割區(qū)域上畫些筆畫。筆畫基本上說 “嘿,該區(qū)域應該是前景,你將其標記為背景,在下一次迭代中對其進行校正”或與背景相反。然后在下一次迭代中,你將獲得更好的結(jié)果。

參見下圖。第一名球員和橄欖球被封閉在一個藍色矩形中。然后用白色筆劃(表示前景)和黑色筆劃(表示背景)進行最后的修飾。而且我們得到了不錯的結(jié)果。

OpenCV-Python教程上篇

 

那么背景發(fā)生了什么呢?

  • 用戶輸入矩形。此矩形外部的所有內(nèi)容都將作為背景(這是在矩形應包含所有對象之前提到的原因)。矩形內(nèi)的所有內(nèi)容都是未知的。同樣,任何指定前景和背景的用戶輸入都被視為硬標簽,這意味著它們在此過程中不會更改。
  • 計算機根據(jù)我們提供的數(shù)據(jù)進行初始標記。它標記前景和背景像素(或?qū)ζ溥M行硬標記),現(xiàn)在使用高斯混合模型(GMM)對前景和背景進行建模。
  • 根據(jù)我們提供的數(shù)據(jù),GMM可以學習并創(chuàng)建新的像素分布。也就是說,未知像素根據(jù)顏色統(tǒng)計上與其他硬標記像素的關(guān)系而被標記為可能的前景或可能的背景(就像聚類一樣)。
  • 根據(jù)此像素分布構(gòu)建圖形。圖中的節(jié)點為像素。添加了另外兩個節(jié)點,即“源”節(jié)點和“接收器”節(jié)點。每個前景像素都連接到源節(jié)點,每個背景像素都連接到接收器節(jié)點。
  • 通過像素是前景/背景的概率來定義將像素連接到源節(jié)點/末端節(jié)點的邊緣的權(quán)重。像素之間的權(quán)重由邊緣信息或像素相似度定義。如果像素顏色差異很大,則它們之間的邊緣將變低。
  • 然后使用mincut算法對圖進行分割。它將圖切成具有最小成本函數(shù)的兩個分離的源節(jié)點和宿節(jié)點。成本函數(shù)是被切割邊緣的所有權(quán)重的總和。剪切后,連接到“源”節(jié)點的所有像素都變?yōu)榍熬埃B接到“接收器”節(jié)點的像素都變?yōu)楸尘啊?/li>
  • 繼續(xù)該過程,直到分類收斂為止。

如下圖所示(圖片提供:

http://www.cs.ru.ac.za/research/g02m1682/)

OpenCV-Python教程上篇

 

示例

現(xiàn)在我們使用OpenCV進行抓取算法。OpenCV為此具有功能cv.grabCut(),我們將首先看到其參數(shù):

  • img - 輸入圖像
  • mask - 這是一個掩碼圖像,在其中我們指定哪些區(qū)域是背景,前景或可能的背景/前景等。這是通過以下標志完成的:cv.GC_BGD,cv.GC_FGDcv.GCPRBGD,cv.GCPRFGD,或直接將0,1,2,3傳遞給圖像。
  • rect - 它是矩形的坐標,其中包括前景對象,格式為(x,y,w,h)
  • bdgModel, fgdModel - 這些是算法內(nèi)部使用的數(shù)組。你只需創(chuàng)建兩個大小為(1,65)的np.float64類型零數(shù)組。
  • iterCount - 算法應運行的迭代次數(shù)。
  • model - 應該是cv.GCINITWITH_RECTcv.GCINITWITH_MASK或兩者結(jié)合,決定我們要繪制矩形還是最終的修飾筆觸。

首先讓我們看看矩形模式。我們加載圖像,創(chuàng)建類似的mask圖像。我們創(chuàng)建fgdModel和bgdModel。我們給出矩形參數(shù)。一切都是直截了當?shù)摹W屗惴ㄟ\行5次迭代。模式應為cv.GCINITWITH_RECT, 因為我們使用的是矩形。然后運行g(shù)rabcut。修改mask圖像。在新的mask圖像中,像素將被標記有四個標記,分別表示上面指定的背景/前景。因此,我們修改mask,使所有0像素和2像素都置為0(即背景),而所有1像素和3像素均置為1(即前景像素)。現(xiàn)在,我們的最終mask已經(jīng)準備就緒。只需將其與輸入圖像相乘即可得到分割的圖像。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg')
mask = np.zeros(img.shape[:2],np.uint8)
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
rect = (50,50,450,290)
cv.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis]
plt.imshow(img),plt.colorbar(),plt.show()

查看以下結(jié)果:

OpenCV-Python教程上篇

 

糟糕,梅西的頭發(fā)不見了。誰會喜歡沒有頭發(fā)的梅西?我們需要把它找回來。因此,我們將使用1像素(確保前景)進行精細修飾。同時,一些不需要的地面也出現(xiàn)在圖片里。我們需要刪除它們。在那里,我們給出了一些0像素的修飾(確保背景)。因此,如現(xiàn)在所說,我們在以前的情況下修改生成的mask。

我實際上所做的是,我在paint應用程序中打開了輸入圖像,并在圖像中添加了另一層。使用畫筆中的畫筆工具,我在新圖層上用白色標記了錯過的前景(頭發(fā),鞋子,球等),而用白色標記了不需要的背景(例如logo,地面等)。然后用灰色填充剩余的背景。然后將該mask圖像加載到OpenCV中,編輯我們在新添加的mask圖像中具有相應值的原始mask圖像。

檢查以下代碼:

#newmask是我手動標記過的mask圖像
newmask = cv.imread('newmask.png',0)
# 標記為白色(確保前景)的地方,更改mask = 1
# 標記為黑色(確保背景)的地方,更改mask = 0
mask[newmask == 0] = 0
mask[newmask == 255] = 1
mask, bgdModel, fgdModel = cv.grabCut(img,mask,None,bgdModel,fgdModel,5,cv.GC_INIT_WITH_MASK)
mask = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask[:,:,np.newaxis]
plt.imshow(img),plt.colorbar(),plt.show()

查看以下結(jié)果:

OpenCV-Python教程上篇

 

就是這樣了。在這里,你無需直接在rect模式下初始化,而可以直接進入mask模式。只需用2像素或3像素(可能的背景/前景)標記mask圖像中的矩形區(qū)域。然后像在第二個示例中一樣,將我們的sure_foreground標記為1像素。然后直接在mask模式下應用grabCut功能。

練習

  1. OpenCV示例包含一個示例catchcut.py,這是一個使用grabcut的交互式工具。檢查。另請觀看有關(guān)如何使用它的youtube視頻。
  2. 在這里,你可以通過繪制矩形和使用鼠標筆觸使其成為交互式示例,創(chuàng)建軌跡欄以調(diào)整筆觸寬度等。

OpenCV-Python 理解特征 | 三十六

目標

在本章中,我們將嘗試理解什么是特征,為什么拐角重要等等

解釋

你們大多數(shù)人都會玩拼圖游戲。你會得到很多小圖像,需要正確組裝它們以形成大的真實圖像。問題是,你怎么做?將相同的理論投影到計算機程序上,以便計算機可以玩拼圖游戲呢?如果計算機可以玩拼圖游戲,為什么我們不能給計算機提供很多自然風光的真實圖像,并告訴計算機將所有這些圖像拼接成一個大圖像呢?如果計算機可以將多個自然圖像縫合在一起,那么如何給建筑物或任何結(jié)構(gòu)提供大量圖片并告訴計算機從中創(chuàng)建3D模型呢?

好了,問題和想象力還在繼續(xù)。但這全都取決于最基本的問題:你如何玩拼圖游戲?你如何將許多被擾的圖像片段排列成一個大的單張圖像?你如何將許多自然圖像拼接到一張圖像上?

答案是,我們正在尋找獨特的,易于跟蹤和比較的特定模板或特定特征。如果我們對這種特征進行定義,可能會發(fā)現(xiàn)很難用語言來表達它,但是我們知道它們是什么。如果有人要求你指出一項可以在多張圖像中進行比較的良好特征,則可以指出其中一項。這就是為什么即使是小孩也可以玩這些游戲的原因。我們在圖像中搜索這些特征,找到它們,在其他圖像中尋找相同的特征并將它們對齊。僅此而已。(在拼圖游戲中,我們更多地研究了不同圖像的連續(xù)性)。所有這些屬性都是我們固有的。

因此,我們的一個基本問題擴展到更多,但變得更加具體。這些特征是什么?(答案對于計算機也應該是可以理解的。)

很難說人類如何發(fā)現(xiàn)這些特征。這已經(jīng)在我們的大腦中進行了編碼。但是,如果我們深入研究某些圖片并搜索不同的模板,我們會發(fā)現(xiàn)一些有趣的東西。例如,看以下的圖片:

OpenCV-Python教程上篇

 

圖像非常簡單。在圖像的頂部,給出了六個小圖像塊。你的問題是在原始圖像中找到這些補丁的確切位置。你可以找到多少正確的結(jié)果?

A和B是平坦的表面,它們散布在很多區(qū)域上。很難找到這些補丁的確切位置。

C和D更簡單。它們是建筑物的邊緣。你可以找到一個大概的位置,但是準確的位置仍然很困難。這是因為沿著邊緣的每個地方的圖案都是相同的。但是,在邊緣,情況有所不同。因此,與平坦區(qū)域相比,邊緣是更好的特征,但不夠好(在拼圖游戲中比較邊緣的連續(xù)性很好)。

最后,E和F是建筑物的某些角落。而且很容易找到它們。因為在拐角處,無論將此修補程序移動到何處,它的外觀都將有所不同。因此,它們可以被視為很好的特征。因此,現(xiàn)在我們進入更簡單(且被廣泛使用的圖像)以更好地理解。

OpenCV-Python教程上篇

 

就像上面一樣,藍色補丁是平坦區(qū)域,很難找到和跟蹤。無論你將藍色補丁移到何處,它看起來都一樣。黑色補丁有一個邊緣。如果你沿垂直方向(即沿漸變)移動它,則它會發(fā)生變化。沿著邊緣(平行于邊緣)移動,看起來相同。對于紅色補丁,這是一個角落。無論你將補丁移動到何處,它看起來都不同,這意味著它是唯一的。因此,基本上,拐點被認為是圖像中的良好特征。(不僅是角落,在某些情況下,斑點也被認為是不錯的功能)。

因此,現(xiàn)在我們回答了我們的問題,“這些特征是什么?”。但是出現(xiàn)了下一個問題。我們?nèi)绾握业剿鼈儯窟€是我們?nèi)绾握业浇锹洌课覀円砸环N直觀的方式回答了這一問題,即尋找圖像中在其周圍所有區(qū)域中移動(少量)變化最大的區(qū)域。在接下來的章節(jié)中,這將被投影到計算機語言中。因此,找到這些圖像特征稱為特征檢測。

我們在圖像中找到了特征。找到它之后,你應該能夠在其他圖像中找到相同的圖像。怎么做?我們圍繞該特征采取一個區(qū)域,我們用自己的語言解釋它,例如“上部是藍天,下部是建筑物的區(qū)域,在建筑物上有玻璃等”,而你在另一個建筑物中搜索相同的區(qū)域圖片。基本上,你是在描述特征。同樣,計算機還應該描述特征周圍的區(qū)域,以便可以在其他圖像中找到它。所謂的描述稱為特征描述。獲得特征及其描述后,你可以在所有圖像中找到相同的功能并將它們對齊,縫合在一起或進行所需的操作。

因此,在此模塊中,我們正在尋找OpenCV中的不同算法來查找功能,對其進行描述,進行匹配等。

OpenCV-Python Shi-tomas拐角檢測器和益于跟蹤的特征 | 三十七

目標

在本章中,

  • 我們將學習另一個拐角檢測器:Shi-Tomasi拐角檢測器
  • 我們將看到以下函數(shù):cv.goodFeaturesToTrack()

理論

在上一章中,我們看到了Harris Corner Detector。1994年下半年,J。Shi和C. Tomasi在他們的論文《有益于跟蹤的特征》中做了一個小修改,與Harris Harris Detector相比,顯示了更好的結(jié)果。哈里斯角落探測器的計分功能由下式給出:

OpenCV-Python教程上篇

 

取而代之的是,史托馬西提出:

OpenCV-Python教程上篇

 

如果大于閾值,則將其視為拐角。如果像在Harris Corner Detector中那樣在$lambda1-lambda2$空間中繪制它,則會得到如下圖像:

OpenCV-Python教程上篇

 

從圖中可以看到,只有當λ_1和λ_2大于最小值λ_min時,才將其視為拐角(綠色區(qū)域)。

代碼

OpenCV有一個函數(shù)cv.goodFeaturesToTrack()。它通過Shi-Tomasi方法(或哈里斯角檢測,如果指定)找到圖像中的N個最強角。像往常一樣,圖像應該是灰度圖像。然后,指定要查找的角數(shù)。然后,您指定質(zhì)量級別,該值是介于0-1之間的值,該值表示每個角落都被拒絕的最低拐角質(zhì)量。然后,我們提供檢測到的角之間的最小歐式距離。利用所有這些信息,該功能可以找到圖像中的拐角。低于平均質(zhì)量的所有拐角點均被拒絕。然后,它會根據(jù)質(zhì)量以降序?qū)κS嗟慕沁M行排序。然后函數(shù)首先獲取最佳拐角,然后丟棄最小距離范圍內(nèi)的所有附近拐角,然后返回N個最佳拐角。在下面的示例中,我們將嘗試找到25個最佳彎角:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('blox.jpg')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
corners = cv.goodFeaturesToTrack(gray,25,0.01,10)
corners = np.int0(corners)
for i in corners:
    x,y = i.ravel()
    cv.circle(img,(x,y),3,255,-1)
plt.imshow(img),plt.show()

查看以下結(jié)果:

OpenCV-Python教程上篇

 

此功能更適合跟蹤。我們將看到使用它的時機

OpenCV-Python SIFT尺度不變特征變換 | 三十八

目標

在這一章當中,

  • 我們將學習SIFT算法的概念
  • 我們將學習找到SIFT關(guān)鍵點和描述算符。

理論

在前兩章中,我們看到了一些像Harris這樣的拐角檢測器。它們是旋轉(zhuǎn)不變的,這意味著即使圖像旋轉(zhuǎn)了,我們也可以找到相同的角。很明顯,因為轉(zhuǎn)角在旋轉(zhuǎn)的圖像中也仍然是轉(zhuǎn)角。但是縮放呢?如果縮放圖像,則拐角可能不是角。例如,檢查下面的簡單圖像。在同一窗口中放大小窗口中小圖像中的拐角時,該角是平坦的。因此,Harris拐角不是尺度不變的。

OpenCV-Python教程上篇

 

因此,在2004年,不列顛哥倫比亞大學的D.Lowe在他的論文《尺度不變關(guān)鍵點中的獨特圖像特征》中提出了一種新算法,即尺度不變特征變換(SIFT),該算法提取關(guān)鍵點并計算其描述算符。 (改論文易于理解,被認為是學習SIFT的最佳材料。因此,本文只是該論文的簡短摘要)。 SIFT算法主要包括四個步驟。 我們將一一看到它們。

SIFT算法主要包括四個步驟。我們將一一看到它們。

1. 尺度空間極值檢測

從上圖可以明顯看出,我們不能使用相同的窗口來檢測具有不同比例的關(guān)鍵點。即便小拐角可以。但是要檢測更大的拐角,我們將需要更大的窗口。為此,使用了比例空間濾波。在其中,找到具有各種$σ$值的圖像的高斯拉普拉斯算子。LoG用作斑點檢測器,可檢測由于$σ$的變化而導致的各種大小的斑點。簡而言之,$σ$用作縮放參數(shù)。例如,在上圖中,低$σ$的高斯核對于較小的拐角給出較高的值,而高$σ$的高斯核對于較大的拐角而言非常合適。因此,我們可以找到整個尺度和空間上的局部最大值,這給了我們$(x,y,σ)$值的列表,這意味著在$(x,y)$在$σ$尺度上有一個潛在的關(guān)鍵點。

但是這種LoG代價昂貴,因此SIFT算法使用的是高斯差值,它是LoG的近似值。高斯差是作為具有兩個不同$σ$的圖像的高斯模糊差而獲得的,設(shè)為$σ$和$kσ$。此過程是針對高斯金字塔中圖像的不同八度完成的。如下圖所示:

OpenCV-Python教程上篇

 

一旦找到該DoG,便會在圖像上搜索比例和空間上的局部極值。例如,將圖像中的一個像素與其8個相鄰像素以及下一個比例的9個像素和前一個比例的9個像素進行比較。如果是局部極值,則可能是關(guān)鍵點。從根本上說,關(guān)鍵點是最好的代表。如下圖所示:

OpenCV-Python教程上篇

 

對于不同的參數(shù),本文給出了一些經(jīng)驗數(shù)據(jù),可以概括為:octaves=4,縮放尺度=5,初始$σ=1.6$,$k=sqrt{2}$等作為最佳值。

2. 關(guān)鍵點定位

一旦找到潛在的關(guān)鍵點位置,就必須對其進行優(yōu)化以獲取更準確的結(jié)果。他們使用了標度空間的泰勒級數(shù)展開來獲得更精確的極值位置,如果該極值處的強度小于閾值(根據(jù)論文為0.03),則將其拒絕。在OpenCV DoG中,此閾值稱為ContrastThreshold,它對邊緣的響應較高,因此也需要刪除邊緣。

為此,使用類似于哈里斯拐角檢測器的概念。他們使用2x2的Hessian矩陣(H)計算主曲率。從哈里斯拐角檢測器我們知道,對于邊緣,一個特征值大于另一個特征值。因此,這里他們使用了一個簡單的函數(shù)。

如果該比率大于一個閾值(在OpenCV中稱為edgeThreshold),則該關(guān)鍵點將被丟棄。論文上寫的值為10。

因此,它消除了任何低對比度的關(guān)鍵點和邊緣關(guān)鍵點,剩下的就是很可能的目標點。

3. 方向分配

現(xiàn)在,將方向分配給每個關(guān)鍵點,以實現(xiàn)圖像旋轉(zhuǎn)的不變性。根據(jù)比例在關(guān)鍵點位置附近采取鄰域,并在該區(qū)域中計算梯度大小和方向。創(chuàng)建了一個具有36個覆蓋360度的bin的方向直方圖(通過梯度幅度和$σ$等于關(guān)鍵點比例的1.5的高斯加權(quán)圓窗加權(quán))。提取直方圖中的最高峰,并且將其超過80%的任何峰也視為計算方向。它創(chuàng)建的位置和比例相同但方向不同的關(guān)鍵點。它有助于匹配的穩(wěn)定性。

4. 關(guān)鍵點描述

現(xiàn)在創(chuàng)建了關(guān)鍵點描述符。在關(guān)鍵點周圍采用了16x16的鄰域。它分為16個4x4大小的子塊。對于每個子塊,創(chuàng)建8 bin方向直方圖。因此共有128個bin值可用。它被表示為形成關(guān)鍵點描述符的向量。除此之外,還采取了幾種措施來實現(xiàn)針對照明變化,旋轉(zhuǎn)等的魯棒性。

5. 關(guān)鍵點匹配

通過識別兩個圖像的最近鄰,可以匹配兩個圖像之間的關(guān)鍵點。但是在某些情況下,第二個最接近的匹配可能非常接近第一個。它可能是由于噪音或其他原因而發(fā)生的。在那種情況下,采用最接近距離與第二最接近距離之比。如果大于0.8,將被拒絕。根據(jù)論文,它可以消除大約90%的錯誤匹配,而僅丟棄5%的正確匹配。因此,這是SIFT算法的總結(jié)。有關(guān)更多詳細信息和理解,強烈建議閱讀原始論文。記住一件事,該算法已申請專利。所以這個算法包含在opencv contrib repo中

OpenCV中的SIFT

現(xiàn)在,讓我們來看一下OpenCV中可用的SIFT功能。讓我們從關(guān)鍵點檢測開始并進行繪制。首先,我們必須構(gòu)造一個SIFT對象。我們可以將不同的參數(shù)傳遞給它,這些參數(shù)是可選的,它們在docs中已得到很好的解釋。

import numpy as np
import cv2 as cv
img = cv.imread('home.jpg')
gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)
sift = cv.xfeatures2d.SIFT_create()
kp = sift.detect(gray,None)
img=cv.drawKeypoints(gray,kp,img)
cv.imwrite('sift_keypoints.jpg',img)

sift.detect()函數(shù)在圖像中找到關(guān)鍵點。如果只想搜索圖像的一部分,則可以通過掩碼。每個關(guān)鍵點是一個特殊的結(jié)構(gòu),具有許多屬性,例如其(x,y)坐標,有意義的鄰域的大小,指定其方向的角度,指定關(guān)鍵點強度的響應等。

OpenCV還提供cv.drawKeyPoints()函數(shù),該函數(shù)在關(guān)鍵點的位置繪制小圓圈。如果將標志

cv.DRAWMATCHESFLAGSDRAWRICH_KEYPOINTS傳遞給它,它將繪制一個具有關(guān)鍵點大小的圓,甚至會顯示其方向。請參見以下示例。

img=cv.drawKeypoints(gray,kp,img,flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) cv.imwrite('sift_keypoints.jpg',img)

查看下面的結(jié)果:

OpenCV-Python教程上篇

 

現(xiàn)在要計算描述符,OpenCV提供了兩種方法。

  1. 由于已經(jīng)找到關(guān)鍵點,因此可以調(diào)用sift.compute(),該函數(shù)根據(jù)我們找到的關(guān)鍵點來計算描述符。例如:kp,des = sift.compute(gray,kp)
  2. 如果找不到關(guān)鍵點,則可以使用sift.detectAndCompute()函數(shù)在單步驟中直接找到關(guān)鍵點和描述符。

我們將看到第二種方法:

sift = cv.xfeatures2d.SIFT_create() 
kp, des = sift.detectAndCompute(gray,None)

這里的kp將是一個關(guān)鍵點列表,而des是一個形狀為$NumberofKeypoints×128$的數(shù)字數(shù)組。

這樣我們得到了關(guān)鍵點,描述符等。現(xiàn)在我們想看看如何在不同圖像中匹配關(guān)鍵點。我們將在接下來的章節(jié)中學習。

OpenCV最新中文版官方教程|三十九

OpenCV是計算機視覺中經(jīng)典的專用庫,然而其中文版官方教程久久不來。近日,一款最新OpenCV4.1 版本的完整中文版官方教程出爐,讀者朋友可以更好的學習了解OpenCV相關(guān)細節(jié)。教程來自objectdetection.cn。

最新Opencv-Python中文版官方文檔:

http://woshicver.com

教程里有什么

教程根據(jù)官方提供的文檔,盡量完整的進行了還原。包括簡單的OpenCV-Python安裝,如何顯示和保存圖像和視頻,圖像的基本操作,OpenCV內(nèi)部的不同圖像處理函數(shù),有關(guān)特征檢測和描述符的信息。以及機器學習與目標檢測部分等等。

部分內(nèi)容如下

  • 最小閉合圓:
OpenCV-Python教程上篇

 

  • 多對象模板匹配
OpenCV-Python教程上篇

 

  • 手寫數(shù)字:
OpenCV-Python教程上篇

 

  • 級聯(lián)分類器可視化:
OpenCV-Python教程上篇

 

教程目錄

OpenCV簡介

  • 0_OpenCV-Python Tutorials

OpenCV安裝

  • 1_1_OpenCV-Python教程簡介
  • 1_2_在Windows中安裝OpenCV-Python
  • 1_3_在Fedora中安裝OpenCV-Python
  • 1_4_在Ubuntu中安裝OpenCV-Python

OpenCV中的GUI特性

  • 2_1_圖像入門
  • 2_2_視頻入門
  • 2_3_OpenCV中的繪圖功能
  • 2_4_鼠標作為畫筆
  • 2_5_軌跡欄作為調(diào)色板

核心操作

  • 3_1_圖像的基本操作
  • 3_2_圖像上的算法運算
  • 3_3_性能衡量和提升技術(shù)

OpenCV中的圖像處理

4_1_改變顏色空間

  • 4_2_圖像幾何變換
  • 4_3_圖像閾值
  • 4_4_圖像平滑
  • 4_5_形態(tài)轉(zhuǎn)換
  • 4_6_圖像梯度
  • 4_7_Canny邊緣檢測
  • 4_8_圖像金字塔
  • 4_9_1_OpenCV中的輪廓
  • 4_9_2_輪廓特征
  • 4_9_3_輪廓屬性
  • 4_9_4_輪廓:更多屬性
  • 4_9_5_輪廓分層
  • 4_10_1_直方圖-1:查找,繪制,分析
  • 4_10_2_直方圖-2:直方圖均衡
  • 4_10_3_直方圖3:二維直方圖
  • 4_10_4_直方圖-4:直方圖反投影
  • 4_11_傅里葉變換
  • 4_12_模板匹配
  • 4_13_霍夫線變換
  • 4_14_霍夫圈變換
  • 4_15_圖像分割與分水嶺算法
  • 4_16_交互式前景提取使用GrabCut算法

特征檢測與描述

5_1_理解特征

  • 5_2_哈里斯角檢測
  • 5_3_Shi-Tomasi拐角探測器和良好的跟蹤功能
  • 5_4_SIFT(尺度不變特征變換)簡介
  • 5_5_SURF簡介(加速的強大功能)
  • 5_6_用于角點檢測的FAST算法
  • 5_7_BRIEF(二進制的魯棒獨立基本特征)
  • 5_8_ORB(定向快速和旋轉(zhuǎn)簡要)
  • 5_9_特征匹配
  • 5_10_特征匹配+單應性查找對象

視頻分析

  • 6_1_如何使用背景分離方法
  • 6_2_Meanshift和Camshift
  • 6_3_光流

相機校準和3D重建

  • 7_1_相機校準
  • 7_2_姿態(tài)估計
  • 7_3_對極幾何
  • 7_4_立體圖像的深度圖

機器學習

  • 8_1_理解KNN
  • 8_2_使用OCR手寫數(shù)據(jù)集運行KNN
  • 8_3_理解SVM
  • 8_4_使用OCR手寫數(shù)據(jù)集運行SVM
  • 8_5_理解K均值聚類
  • 8_6_OpenCV中的K均值

計算攝影學

  • 9_1_圖像去噪
  • 9_2_圖像修補
  • 9_3_高動態(tài)范圍

目標檢測

  • 10_1_級聯(lián)分類器
  • 10_2_級聯(lián)分類器訓練

OpenCV-Python Binding

  • 11_1_OpenCV-Python Bindings

最新Opencv-Python中文版官方文檔:

http://woshicver.com

原創(chuàng):人工智能遇見磐創(chuàng)

編輯:IT智能化專欄編輯

分享到:
標簽:OpenCV Python
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定