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