Python-OpenCV——進(jìn)階操作一網(wǎng)打盡

cv2.add()——將兩張圖片的像素疊加起來,與兩張圖片直接相加結(jié)果不同
>>> x = np.uint8([250])
>>> y = np.uint8([10])

>>> print cv2.add(x,y) # 250+10 = 260 => 255 最高為255
[[255]]

>>> print x+y          # 250+10 = 260 % 256 = 4
[4]
cv2.addWeighted() —— 以一定權(quán)重相加
img1 = cv2.imread('ml.png')
img2 = cv2.imread('opencv_logo.jpg')
#圖片1 0.7   圖片2 0.3
dst = cv2.addWeighted(img1,0.7,img2,0.3,0)

cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
示例
  • cv2.bitwise() —— 位圖操作,包括AND OR NOT XOR
# 載入兩張圖片
img1 = cv2.imread('messi5.jpg')
img2 = cv2.imread('opencv_logo.png')

# 創(chuàng)建一個(gè)ROI:region of image即圖片的一部分區(qū)域
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]

# 轉(zhuǎn)換顏色模式為灰度模式网棍;用cv2.threshold將圖片二值化處理痛侍,
#即將像素值高于或者低于設(shè)定閾值的像素置為0厅各,然后將低于或者高于的值置為其它顏色虫埂,
#需要四個(gè)參數(shù)cv2.threshold(灰度圖贷盲,閾值坏匪,設(shè)定值拟逮,方法),方法有五種:
#cv2.THRESH_BINARY - 二值化處理适滓,低于閾值的像素點(diǎn)灰度值置為0敦迄;高于閾值的值置為參數(shù)3
#cv2.THRESH_BINARY_INV - 大于閾值的像素點(diǎn)灰度值置為0;小于閾值置為參數(shù)3
#cv2.THRESH_TRUNC - 小于閾值的像素點(diǎn)灰度值不變凭迹,大于閾值的像素點(diǎn)置為該閾值
#cv2.THRESH_TOZERO - 小于閾值的像素點(diǎn)灰度值不變罚屋,大于閾值的像素點(diǎn)置為0,其中參數(shù)3任取
#cv2.THRESH_TOZERO_INV - 大于閾值的像素點(diǎn)灰度值不變,小于閾值的像素點(diǎn)置為0,其中參數(shù)3任取
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
#將圖片進(jìn)行反向掩碼的位操作得到logo圖像
mask_inv = cv2.bitwise_not(mask)

# 保留除logo外的背景
img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)

# 去除除logo圖中l(wèi)ogo外的背景
img2_fg = cv2.bitwise_and(img2,img2,mask = mask)

# 進(jìn)行融合
dst = cv2.add(img1_bg,img2_fg)
# 融合后放在原圖上
img1[0:rows, 0:cols ] = dst

cv2.imshow('res',img1)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.blur(), cv2.GaussianBlur(), cv2.medianBlur(), cv2.bilateralFilter() —— 各種濾波進(jìn)行圖像平滑處理

首先要了解卷積是什么嗅绸?


二維卷積

卷積就是循環(huán)對(duì)圖像跟一個(gè)核逐個(gè)元素相乘再求和得到另外一副圖像的操作脾猛,比如結(jié)果圖中第一個(gè)元素5是怎么算的呢?原圖中3×3的區(qū)域與3×3的核逐個(gè)元素相乘再相加:1×1 + 2×0 + 1×0 + 0×0 + 1×0 + 1×0 + 3×0 + 0×0 + 2×2 = 5鱼鸠。算完之后猛拴,整個(gè)框再往右移一步繼續(xù)計(jì)算羹铅,橫向計(jì)算完后,再往下移一步繼續(xù)計(jì)算……網(wǎng)上有一副很經(jīng)典的動(dòng)態(tài)圖愉昆,方便我們理解卷積:


卷積動(dòng)畫
  • 濾波有均值濾波职员、方框?yàn)V波、高斯濾波跛溉、中值濾波焊切、雙邊濾波
  • 在不知道用什么濾波器好的時(shí)候,優(yōu)先高斯濾波cv2.GaussianBlur()芳室,然后均值濾波cv2.blur()
  • 斑點(diǎn)和椒鹽噪聲優(yōu)先使用中值濾波cv2.medianBlur()
  • 要去除噪點(diǎn)的同時(shí)盡可能保留更多的邊緣信息蛛蒙,使用雙邊濾波cv2.bilateralFilter()
  • 線性濾波方式:均值濾波、方框?yàn)V波渤愁、高斯濾波(速度相對(duì)快)
  • 非線性濾波方式:中值濾波牵祟、雙邊濾波(速度相對(duì)慢)


    從左到右,從上到下依次為均值濾波抖格、高斯濾波诺苹、中值濾波、雙邊濾波
cv2.threshold, cv2.adaptiveThreshold —— 圖像閾值化

簡單的閾值處理cv2.threshold在基礎(chǔ)操作已經(jīng)講過雹拄,接下來說高級(jí)處理cv2.adaptiveThreshold

有三個(gè)輸入變量和一個(gè)輸出量:

  • Adaptive Method - 決定閾值計(jì)算類型.
    • cv2.ADAPTIVE_THRESH_MEAN_C : 根據(jù)相鄰區(qū)域
    • cv2.ADAPTIVE_THRESH_GAUSSIAN_C : 通過高斯函數(shù)窗口
  • Block Size - 決定相鄰區(qū)域的范圍
  • C -計(jì)算中需要的一個(gè)常數(shù)
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('dave.jpg',0)
img = cv2.medianBlur(img,5)

ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
            cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,11,2)

titles = ['Original Image', 'Global Thresholding (v = 127)',
            'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]

for i in range(4):
    plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()
結(jié)果展示

孰優(yōu)孰劣顯而易見收奔!

幾何變換

縮放
import cv2
import numpy as np

img = cv2.imread('messi5.jpg')
# 縮放圖片,就一行代碼滓玖,很簡單
res = cv2.resize(img,None,fx=2, fy=2, interpolation = cv2.INTER_CUBIC)

#OR

height, width = img.shape[:2]
res = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC)
旋轉(zhuǎn)坪哄、平移

平移

import cv2
import numpy as np

img = cv2.imread('messi5.jpg',0)
rows,cols = img.shape

M = np.float32([[1,0,100],[0,1,50]])
# 用cv2.warpAffine平移一段距離M
dst = cv2.warpAffine(img,M,(cols,rows))

cv2.imshow('img',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
image

旋轉(zhuǎn)

img = cv2.imread('messi5.jpg',0)
rows,cols = img.shape

M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
# 用cv2.warpAffine旋轉(zhuǎn)
dst = cv2.warpAffine(img,M,(cols,rows))
image
仿射

對(duì)于仿射變換,我們只需要知道變換前的三個(gè)點(diǎn)與其對(duì)應(yīng)的變換后的點(diǎn)势篡,就可以通過cv2.getAffineTransform求得變換矩陣.

img = cv2.imread('sudokusmall.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 = cv2.getPerspectiveTransform(pts1,pts2)

dst = cv2.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()
image

形態(tài)學(xué)操作

形態(tài)學(xué)操作是指改變物體形狀翩肌,一般作用于二值化圖,來連接相鄰的元素或分離成獨(dú)立的元素禁悠。腐蝕和膨脹是針對(duì)圖片中的白色部分念祭!


原圖
腐蝕
import cv2
import numpy as np

img = cv2.imread('j.png',0)
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
腐蝕
膨脹
dilation = cv2.dilate(img,kernel,iterations = 1)
膨脹
開運(yùn)算

先腐蝕后膨脹叫開運(yùn)算(因?yàn)橄雀g會(huì)分開物體,這樣容易記装臁)粱坤,其作用是:分離物體,消除小區(qū)域瓷产。

opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
開運(yùn)算
閉運(yùn)算

先膨脹后腐蝕(先膨脹會(huì)使白色的部分?jǐn)U張站玄,以至于消除/“閉合”物體里面的小黑洞,所以叫閉運(yùn)算)

closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
閉運(yùn)算
形態(tài)學(xué)梯度運(yùn)算

膨脹圖減去腐蝕圖濒旦,這樣會(huì)得到物體的輪廓

gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
形態(tài)學(xué)梯度運(yùn)算
不常用株旷,不做解釋
##### 頂帽

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

##### 黑帽

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

圖像梯度

如果你還記得高數(shù)中用一階導(dǎo)數(shù)來求極值的話,就很容易理解了:把圖片想象成連續(xù)函數(shù)疤估,因?yàn)檫吘壊糠值南袼刂凳桥c旁邊像素明顯有區(qū)別的灾常,所以對(duì)圖片局部求極值,就可以得到整幅圖片的邊緣信息了铃拇。不過圖片是二維的離散函數(shù)钞瀑,導(dǎo)數(shù)就變成了差分,這個(gè)差分就稱為圖像的梯度慷荔。

濾波是應(yīng)用卷積來實(shí)現(xiàn)的雕什,卷積的關(guān)鍵就是卷積核,我們來考察下面這個(gè)卷積核:

這個(gè)核是用來提取圖片中的垂直邊緣的显晶,怎么做到的呢贷岸?看下圖:

當(dāng)前列左右兩側(cè)的元素進(jìn)行差分,由于邊緣的值明顯小于(或大于)周邊像素磷雇,所以邊緣的差分結(jié)果會(huì)明顯不同偿警,這樣就提取出了垂直邊緣。同理唯笙,把上面那個(gè)矩陣轉(zhuǎn)置一下螟蒸,就是提取水平邊緣。這種差分操作就叫圖像的梯度計(jì)算:

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('dave.jpg',0)

laplacian = cv2.Laplacian(img,cv2.CV_64F)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
sobely = cv2.Sobel(img,cv2.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()

邊緣檢測

邊緣檢測圖像處理計(jì)算機(jī)視覺中的基本問題崩掘,邊緣檢測的目的是標(biāo)識(shí)數(shù)字圖像中亮度變化明顯的點(diǎn)七嫌。圖像屬性中的顯著變化通常反映了屬性的重要事件和變化。

侃尼邊緣檢測原理

侃尼邊緣檢測是一個(gè)流行的邊緣檢測算法苞慢,1986年由 John F. Canny提出诵原。包括四個(gè)步驟:

  1. 減少噪聲

因?yàn)檫吘墮z測容易受到噪聲的影響,因此使用5×5高斯濾波消除噪聲挽放,前面已經(jīng)提到過绍赛。

  1. 計(jì)算圖像梯度

    首先用上面提到的Sobel方法提取水平垂直兩個(gè)方向的邊緣,然后根據(jù)以下公式計(jì)算出每條邊的梯度及其梯度方向:
    梯度方向總是垂直于邊緣的辑畦。梯度方向被歸為四類:水平惹资、垂直、及其對(duì)角線方向航闺。
  2. 非極大值抑制

    在找到梯度后褪测,應(yīng)該對(duì)整幅圖像做一個(gè)掃描,去除那些非邊界上的點(diǎn)潦刃。對(duì)每一個(gè)像素進(jìn)行檢查侮措,看這個(gè)點(diǎn)的梯度是不是周圍具有相同梯度方向的點(diǎn)中最大的。如下所示:
    非極大值抑制
    如果A的梯度大于B乖杠、C分扎,那么保留A的值,將B胧洒、C置為0畏吓。

    簡而言之,你得到的結(jié)果是一個(gè)二進(jìn)制圖像,“薄邊緣”墨状。

  3. 滯后閾值法

    這個(gè)階段決定誰是邊緣,誰不是邊緣
    滯后閾值法
  • 像素點(diǎn)的值大于最高閾值菲饼,那肯定是邊緣(上圖A)
  • 同理像素值小于最低閾值肾砂,那肯定不是邊緣
  • 像素值介于兩者之間,如果與高于最高閾值的點(diǎn)連接宏悦,也算邊緣镐确,所以上圖中C算,B不算
    進(jìn)過這一步就得到了清晰地邊界饼煞。

OpenCV中Canny邊緣檢測的使用

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('messi5.jpg',0)
# 第一個(gè)參數(shù)為圖片源葫,第二第三個(gè)參數(shù)為上述原理第四步的最大最小閾值
edges = cv2.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()

圖像匹配

SIFT算法由D.G.Lowe 1999年提出,2004年完善總結(jié)砖瞧,論文發(fā)表在2004年的IJCV上息堂,主要用于提取具有圖像旋轉(zhuǎn)不變性和伸縮不變性的特征點(diǎn)。這項(xiàng)技術(shù)可以推廣到圖像識(shí)別块促、圖像拼接以及圖像恢復(fù)等储矩。
David G. Lowe, "Distinctive image features from scale-invariant keypoints," International Journal of Computer Vision,60, 2 (2004), pp. 91-110
論文詳細(xì)地址
其中就用到了OpenCV的cv2.pyrDown()cv2.pyrUp()函數(shù)來創(chuàng)建圖像金字塔。
圖像金字塔主要有兩類:高斯金字塔和拉普拉斯金字塔褂乍。
高斯金字塔的頂部是通過將底部圖像的連續(xù)行與列去掉得到的持隧。每一層圖像中的像素值等于下一層圖像中對(duì)應(yīng)位置5個(gè)像素的高斯加權(quán)平均值。這樣操作一個(gè)MN的圖像就變成了(M/2)(N/2)的圖像逃片,圖像的面積就變?yōu)樵瓉淼?/4屡拨,連續(xù)進(jìn)行這樣的操作,就會(huì)得到一些列的金字塔的圖像褥实。

一個(gè)小應(yīng)用
import cv2
import numpy as np,sys

A = cv2.imread('apple.jpg')
B = cv2.imread('orange.jpg')

# 生成蘋果圖像金字塔
G = A.copy()
gpA = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpA.append(G)

# 生成橘子圖像金字塔
G = B.copy()
gpB = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpB.append(G)

# 生成蘋果圖像拉普拉斯金字塔
lpA = [gpA[5]]
for i in range(5,0,-1):
    GE = cv2.pyrUp(gpA[i])
    L = cv2.subtract(gpA[i-1],GE)
    lpA.append(L)

# 生成橘子圖像拉普拉斯金字塔
lpB = [gpB[5]]
for i in range(5,0,-1):
    GE = cv2.pyrUp(gpB[i])
    L = cv2.subtract(gpB[i-1],GE)
    lpB.append(L)

# 添加蘋果呀狼、橘子各一半的圖像
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)

# 重新組合
ls_ = LS[0]
for i in range(1,6):
    ls_ = cv2.pyrUp(ls_)
    ls_ = cv2.add(ls_, LS[i])

# 直接組合
real = np.hstack((A[:,:cols/2],B[:,cols/2:]))

cv2.imwrite('Pyramid_blending2.jpg',ls_)
cv2.imwrite('Direct_blending.jpg',real)

未完待續(xù)

關(guān)于OpenCV的學(xué)習(xí)就先告一段落,接下來我會(huì)更新關(guān)于機(jī)器學(xué)習(xí)的內(nèi)容损离,然后再用到關(guān)于OpenCV的內(nèi)容會(huì)再更新哥艇,大家有什么需要的也可以留言告訴我,我也會(huì)考慮更新的僻澎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末貌踏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子窟勃,更是在濱河造成了極大的恐慌祖乳,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秉氧,死亡現(xiàn)場離奇詭異眷昆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門亚斋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來作媚,“玉大人,你說我怎么就攤上這事帅刊≈脚荩” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵厚掷,是天一觀的道長弟灼。 經(jīng)常有香客問我级解,道長冒黑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任勤哗,我火速辦了婚禮抡爹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芒划。我一直安慰自己冬竟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布民逼。 她就那樣靜靜地躺著泵殴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拼苍。 梳的紋絲不亂的頭發(fā)上笑诅,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音疮鲫,去河邊找鬼吆你。 笑死,一個(gè)胖子當(dāng)著我的面吹牛俊犯,可吹牛的內(nèi)容都是我干的妇多。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼燕侠,長吁一口氣:“原來是場噩夢啊……” “哼者祖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起绢彤,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤咸包,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后杖虾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烂瘫,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坟比。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芦鳍。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖葛账,靈堂內(nèi)的尸體忽然破棺而出柠衅,到底是詐尸還是另有隱情,我是刑警寧澤籍琳,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布菲宴,位于F島的核電站,受9級(jí)特大地震影響趋急,放射性物質(zhì)發(fā)生泄漏喝峦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一呜达、第九天 我趴在偏房一處隱蔽的房頂上張望谣蠢。 院中可真熱鬧,春花似錦查近、人聲如沸眉踱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谈喳。三九已至,卻和暖如春戈泼,著一層夾襖步出監(jiān)牢的瞬間婿禽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工矮冬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谈宛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓胎署,卻偏偏與公主長得像吆录,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子琼牧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容