python opencv 图像切割_【OpenCV+Python】图像的基本操作与算术运算
圖像的基本操作
在上個教程中,我們介紹了使用鼠標畫筆的功能。本次教程,我們將要談及OpenCV圖像處理的基本操作。
本次教程的所有操作基本上都和Numpy相關,而不是與OpenCV相關。要使用OpenCV編寫更好的優化代碼,需要Numpy的豐富知識。
1.查看和修改像素值
我們要想查看一幅圖像中某一個像素點的像素值,首先需要進行定位,將其坐標標定,我們先來看一個彩色圖像(仍然是我們的貓咪,本次教程它是我們的主角):
現在我想查看某一個坐標的像素值,我們在pycharm中輸入代碼:
import?cv2import?numpy?as?npimg?=?cv2.imread("cat.jpg")#獲取像素值px?=?img[200,200]print(px)代碼為查看圖像坐標(200,200)處的像素值,我們來看結果:
在之前的教程中我們談到,OpenCV對于圖像的讀取并非是RGB通道,而是BGR通道,那么程序輸出的[178,189,186]則分別對應于BGR的像素,我們可以進行驗證:
import?cv2import?numpy?as?npimg?=?cv2.imread("cat.jpg")#獲取像素值px?=?img[200,200]B?=?img[200,200,0]G = img[200,200,1]R?=?img[200,200,2]print(px,B,G,R)現在我們假設,如果圖像并非彩色,而是黑白的灰度圖像,那么將會怎么輸出?先進行實驗:
我們仍然用剛剛的代碼進行實驗(前提是圖像已經灰度化處理,這在后面會講到),效果:
可以看到,BGR的像素一致,我們得出一個結論:對于灰度圖像,其輸出的像素值本質上為它的亮度強度值,值的范圍為0-255之間,當為0時,則全部為黑色,相反則為白色。
接下來我們來修改像素值,將指定坐標的像素值用一個數組進行賦值:
import?cv2import?numpy?as?npimg?=?cv2.imread("cat1.jpg")#獲取像素值px?=?img[200,200]print(px)img[200,200]?=?[225,225,225]print(img[200,200])查看輸出:
可以看到,初始像素值跟修改之后的像素值。
一般來說,數組通常選擇的是某一片區域,比如頭幾行或者最后幾列。而對于某個像素點的訪問,Numpy數組方法,array.item() 和array.itemset()有著更好的作用。但是它返回的是一個標量。所以如果我們想訪問所有的B,G,R值,就需要分開調用array.item(),我們來看代碼(仍然以坐標200,200為例):
import?cv2import?numpy?as?npimg?=?cv2.imread("cat.jpg")#獲取像素值px?=?img[200,200]print(px)print(img.item(200,200,0))我們用item輸出像素的B值,也就是藍色像素的數值:
實驗可以看到,跟之前的效果是一樣的。
對于指定坐標的賦值,我們使用itemset函數可以精確到某個像素,比如現在我只對藍色像素的數值進行改變:
import?cv2import?numpy?as?npimg?=?cv2.imread("cat.jpg")#獲取像素值px?=?img[200,200]print(px)print(img.item(200,200,0))img.itemset((200,200,0),100)print(img.item(200,200,0))可以看到,對于指定的顏色通道的賦值時完全可以的。
2.查看圖像屬性
現在將要對圖像的各個屬性進行研究,圖像屬性包括行數、列數和通道數,圖像數據類型,像素數等。
對于一個圖像,我們使用shape可以返回行數、列數以及顏色通道的元數:
import?cv2import?numpy?as?npimg?=?cv2.imread("cat.jpg")print(img.shape)輸出的第三個數值代表的是圖像的BGR三個通道的元數,也就是3。現在我們使用灰度圖像做實驗:
import?cv2import?numpy?as?npimg?=?cv2.imread("cat.jpg")img?=?cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)print(img.shape)灰度圖像在之后的教程中會進行講解,這里先用做實驗:
可以看到,如果圖像是灰度的,則返回的元組僅包含行數和列數,因此這是檢查加載的圖像是灰度還是彩色的好方法。
通過size可以返回當前圖像的所有的像素點的總數:
import?cv2import?numpy?as?npimg?=?cv2.imread("cat.jpg")print(img.size)圖像的數據類型可以通過dtype獲得:
import?cv2import?numpy?as?npimg?=?cv2.imread("cat.jpg")print(img.dtype)imread函數默認讀取圖像的格式就是uint8,所以返回的全部都是這個格式。在以后我們學習深度學習框架時會發現,uint8的圖像數據格式用來進行模型訓練時,做數據歸一化(預處理階段)會導致精度缺失,最后導致分割精度下降。當然這是后話,我們現在不提。
如果我們想修改圖像的格式,我們需要用到astype函數,現在將圖像修改為float32格式的(這種格式的圖像被廣泛的應用于深度學習的模型訓練):
import?cv2import?numpy?as?npimg?=?cv2.imread("cat.jpg").astype(np.float32)print(img.dtype)dtype在調試時非常重要,因為OpenCV-Python代碼中的大量錯誤是由無效的數據類型引起的,我們在以后的學習中會經常遇到這些問題。
3.圖像ROI
對于圖像中的特定區域的選取我們稱之為ROI,其實際上就是對圖像的xy坐標進行操作,我們來看示例:
import?cv2import?numpy?as?npimg?=?cv2.imread("cat.jpg")husky?=?img[1:240,60:270]cv2.imshow("img",husky)cv2.waitKey(0)cv2.destroyAllWindows()本質相當于截取某一部分圖片,現在我們來做一些有意思的操作,將截取部分覆蓋到圖像的其他地方,本質相當于前面講過的像素修改:
import?cv2import?numpy?as?npimg?=?cv2.imread("cat.jpg")husky = img[1:240,60:270]img[61:300,270:480]?=?huskycv2.imshow("img",img)cv2.waitKey(0)cv2.destroyAllWindows()4.分割和合并圖像通道
有時我們需要在B,G,R通道圖像上單獨進行操作。在這種情況下,需要將BGR圖像分割為單個通道。需要使用split函數與merge函數,它們的作用分別為分離和合并:
b,g,r = cv2.split(img) #拆分圖像通道img = cv2.merge((b,g,r))此操作可以將BGR三通道分離出來,從而可以對某一通道進行操作,比如現在我們將R像素全部設置為0:
import?cv2import?numpy?as?npimg = cv2.imread("cat.jpg")b,g,r = cv2.split(img) #拆分圖像通道img[:,:,2] = 0r = img[:,:,2]img = cv2.merge((b,g,r))cv2.imshow("img",img)cv2.waitKey(0)cv2.destroyAllWindows()r則為R通道,看效果:
將紅色通道去除后,我們的貓咪變的有點綠了。當然,大家還可以進行其他的通道的實驗。
5.圖像邊框填充
如果要在圖像周圍創建邊框(如相框),則可以使用函數cv2.copyMakeBorder()。它在卷積運算(很重要),零填充等方面有更多應用。
此函數采用以下參數:
cv2.copyMakeBorder(src, top, bottom, left, right, borderType[, dst[, value]])
? src—輸入圖像
? top,bottom,left,right—相應方向上像素數的邊框寬度
? value—cv2.BORDER_CONSTANT,cv2.BORDER_REFLECT,cv2.BORDER_REFLECT_101 or cv2.BORDER_DEFAULT ,cv2.BORDER_REPLICATE,cv2.BORDER_WRAP
cv2.BORDER_REFLECT_101或cv2.BORDER_DEFAULT
? 與上面相同,但略有改動,如下所示:gfedcb | abcdefgh | gfedcba
cv.BORDER_REPLICATE
? 最后一個像素在整個過程中被復制,像:aaaaaa |abcdefgh|hhhhhhh這樣
cv.BORDER_WRAP
? 對稱方向 像素互換 就像:cdefgh|abcdefgh|abcdefg 這樣。
我們來看代碼:
import?cv2from?matplotlib?import?pyplot?as?pltBLUE?=?[255,0,0]img1?=?cv2.imread('cat.jpg')replicate?=?cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REPLICATE)reflect?=?cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT)reflect101?=?cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT_101)wrap?=?cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_WRAP)constant=?cv2.copyMakeBorder(img1,10,10,10,10,cv2.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()
實驗效果:
對于五個參數都進行了實驗,可以看到明顯的不同,當然,在這里為了方便圖片對比顯示,我們使用了matplotlib庫,不過這屬于python的知識,在這里就不一一介紹講解了,大家也可以修改代碼用OpenCV進行其他參數輸出。
圖像的算術運算
本次教程我們將概述圖像的算數運算,眾所周知,數學中有著加減乘除運算,同樣的,圖像也是如此,它的本質實際上就是一個矩陣,所以圖像也存在著加法、減法、位運算等等算數運算。
1.加法
使用cv2.add()將兩個圖像相加,可以使用numpy中的矩陣加法來實現。但是在opencv中加法是飽和操作,也就是有上限值,numpy會對結果取模,綜上,使用opencv的效果更好,我們來看函數實例:
cv2.add(img1, img2) # 進行圖片的加和
參數說明:cv2.add將兩個圖片進行加和,大于255的使用255計數。
我們將使用以下兩個圖片作為實例:
來看代碼:
import cv2img1 = cv2.imread("01.jpg")img2 = cv2.imread("02.jpg")res = cv2.add(img1,img2)cv2.imshow("res",res)cv2.waitKey(0)cv2.destroyAllWindows()不難理解,第一幅圖像白色部分像素部分為255,黑色部分像素為0,所以和第二幅圖像加起來之后白色部分仍然是白色部分,因為加起來的值大于255時,默認取值255。
2.減法
減法運算就是兩幅圖像見對象像素的灰度值或彩色分量進行相減,它可以用于目標檢測,需要用到函數cv2.subtract(),程序實現:
import?cv2img1?=?cv2.imread("01.jpg")img2?=?cv2.imread("02.jpg")res?=?cv2.subtract(img1,img2)cv2.imshow("res",res)cv2.waitKey(0)cv2.destroyAllWindows()3.乘法
圖像的乘法運算就是將兩幅圖像對應的灰度值或彩色分量進行相乘。
乘運算的主要作用是抑制圖像的某些區域,掩膜值置為1,否則置為0。乘運算有時也被用來實現卷積或相關的運算,其相關函數為cv2.multiply()。
以下為相關程序代碼:
import?cv2img1?=?cv2.imread("01.jpg")img2?=?cv2.imread("02.jpg")res?=?cv2.multiply(img1,img2)cv2.imshow("res",res)cv2.waitKey(0)cv2.destroyAllWindows()4.除法
圖像除運算就是兩幅圖像對應像素的灰度值或彩色分量進行相除。簡單的出運算可以用于改變圖像的灰度級。其相關函數為cv2.divide。
以下為代碼部分:
5.圖像融合
它實際上本質也是一個加法運算,但是這個加法運算跟普通的并不一樣,我們可以理解為是一種加權的運算。
我們用函數來表示一個圖像,前提是所有的圖像尺寸是一樣的,即圖像矩陣的行列一樣,通道數一樣。
我們用 f0(x) 和 f1(x) 來表示輸入的圖像,用 g(x) 來表示輸出圖像,α表示比例( 0≤α≤1 ,一般來說,α取0和1沒有太大意義),那我們能得到如下圖所示的一個公式:
所以圖像混合就是將兩個圖像按照一定的比例轉存到另一個圖像中。
首先需要看一下函數原型:
cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]]) → dst
? src1—第一個輸入數組。
? alpha—第一個數組元素的權重。
? src2—第二個輸入數組,其大小和通道號與src1相同。
? beta—第二個數組元素的權重。
? gamma—標量加到每個和。
? dst—輸出數組,其大小和通道數與輸入數組相同。
? dtype—輸出數組的可選深度;當兩個輸入數組的深度相同時,可以將dtype設置為-1,這等效于src1.depth()。
此函數可以用以下矩陣表達式進行代替:
dst = src1 * alpha + src2 * beta + gamma;
注意:由參數說明可以看出,被疊加的兩幅圖像必須是尺寸相同、類型相同的;并且,當輸出圖像array的深度為CV_32S時,這個函數就不適用了,這時候就會內存溢出或者算出的結果壓根不對。
我們來看一下代碼:
import?cv2img1?=?cv2.imread("01.jpg")img?=?cv2.imread("02.jpg")h,?w,?_?=?img1.shapeimg2?=?cv2.resize(img,?(w,h),?interpolation=cv2.INTER_AREA)alpha?=?0.7beta?=?1-alphagamma = 0img_add?=?cv2.addWeighted(img1,?alpha,?img2,?beta,?gamma)cv2.imshow('img_add',img_add)cv2.waitKey()cv2.destroyAllWindows()效果:
此函數最大的缺陷就是需要兩張圖片尺寸必須完全一樣,所以在實驗時必須要注意。
6.按位運算
我們在學習數電時想必都學過邏輯運算,OpenCV中也有相關的運算。與或非這些想必就不必再多講了,我們可以通過代碼實驗來熟悉:
1)與運算:
import?cv2img1?=?cv2.imread("01.jpg")img2?=?cv2.imread("02.jpg")res?=?cv2.bitwise_and(img1,img2)cv2.imshow("res",res)cv2.waitKey()cv2.destroyAllWindows()2)或運算:
import?cv2img1?=?cv2.imread("01.jpg")img2?=?cv2.imread("02.jpg")res?=?cv2.bitwise_or(img1,img2)cv2.imshow("res",res)cv2.waitKey()cv2.destroyAllWindows()可以看到,跟加法運算基本上類似。
3)非運算:
import?cv2img1?=?cv2.imread("01.jpg")img2?=?cv2.imread("02.jpg")res?=?cv2.bitwise_not(img1,img2)cv2.imshow("res",res)cv2.waitKey()cv2.destroyAllWindows()非運算在之后的學習中是非常有幫助的,它的以用來對二值化圖像進行取反,然后方便進行形態學操作。
4)異或運算:
import cv2img1?=?cv2.imread("01.jpg")img2?=?cv2.imread("02.jpg")res?=?cv2.bitwise_xor(img1,img2)cv2.imshow("res",res)cv2.waitKey()cv2.destroyAllWindows()關于圖像的所有的基本運算就介紹到這里。
7.練習實例
現在帶大家做一個好玩的小項目,題目是:用OpenCV完成一個幻燈片演示一幅圖轉成另一幅圖,并在圖像之間進行平滑過渡。
實際上,我們使用剛剛的線性加權函數就可以完成,我們只需要定義一個變量a,然后讓其值小于一,變量的值依次遞增。這樣總體進行分析的話,第一幅圖圖像的加權值為a,第二幅圖像的加權值為1-a,那么在一個循環里面它們會進行動態過渡,我們來看一下代碼:
import?cv2?as?cvimg1?=?cv.imread('01.jpg')img2 = cv.imread('02.jpg')l, h = img1.shape[0:2]img2_R = cv.resize(img2, (h, l))a=0cv.namedWindow('ppt',True)dst = cv.addWeighted(img1, a, img2_R, 1-a, -1)cv.imshow('ppt', dst)cv.waitKey(0)while a<1.0:dst = cv.addWeighted(img1, a, img2_R, 1-a, -1)cv.imshow('ppt', dst)cv.waitKey(100)a+=0.02cv.waitKey(0)cv.destroyAllWindows()按下esc鍵開始幻燈片放映,由于效果為動態,此處不便展示,大家請自己實驗,還是很有意思的。
掃碼入群掃碼添加管理員微信加入“電子產品世界”粉絲交流群
↓↓↓↓點擊,查看更多新聞
總結
以上是生活随笔為你收集整理的python opencv 图像切割_【OpenCV+Python】图像的基本操作与算术运算的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue 获取url地址的参数_2020年
- 下一篇: python3.6字典有序_为什么从Py