App下載

使用 Python 和 OpenCV 進(jìn)行圖像混合

搜索樹(shù)下你我他 2021-08-24 10:08:25 瀏覽數(shù) (2377)
反饋

Python 和 OpenCV 庫(kù)使處理圖像或視頻等視覺(jué)輸入變得非常容易。在本篇文章中,我將討論有關(guān)圖像混合的內(nèi)容并提出一種合并兩個(gè)圖像的像素信息的方法。為了實(shí)現(xiàn)這一點(diǎn),我使用了第三張圖像(所謂的蒙版),作為混合過(guò)程的模板。因?yàn)檫@個(gè)模板是一個(gè)加權(quán)因子矩陣,所以有可能產(chǎn)生結(jié)果,這是通常在網(wǎng)上找到的混合方法無(wú)法獲得的(或者至少我沒(méi)有找到)。

簡(jiǎn)介

Photoshop 和其他圖像處理程序(例如,GIMP 或 Paint.net 等免費(fèi)軟件替代品)提供了廣泛的可能性來(lái)編輯和處理圖像和照片。然而,有時(shí),人們希望執(zhí)行標(biāo)準(zhǔn)軟件中沒(méi)有的操作,或者只是想了解一下具體的照片編輯程序是如何工作的。這兩個(gè)目標(biāo)都可以通過(guò)嘗試將照片編輯程序轉(zhuǎn)換為編程代碼來(lái)實(shí)現(xiàn)。在這里,在這段文字中,我將這樣做并提供用于將圖像的部分(或整個(gè)圖像)與另一個(gè)圖像合并的代碼。

要理解本教程的內(nèi)容,您應(yīng)該具備 Python (Python 3) 的基本知識(shí)以及圖像在計(jì)算機(jī)上的表示方式(即 RGB 或 BGR 模型)。但是,由于代碼并不過(guò)分復(fù)雜,因此具有其他編程語(yǔ)言背景的人也應(yīng)該可以訪問(wèn)它。如果您打算執(zhí)行或使用我加載的代碼,則需要在您的機(jī)器上安裝 OpenCv 和 NumPy(使用?pip?命令或?Anaconda Navigator?這樣做)當(dāng)然還有 Python。OpenCV 是一個(gè)免費(fèi)提供的圖像處理庫(kù)(接口可用于 C++、Python 等),包含許多有助于處理視頻和圖像等視覺(jué)輸入的功能。這里,在這段代碼中,我只使用了一些基本的方法。我使用命令在屏幕上加載和顯示圖像,并設(shè)置一個(gè) while 循環(huán)來(lái)啟用與程序的一些交互(但這也非常實(shí)際)。如前所述,還需要 NumPy。NumPy 是 Python 處理數(shù)字、數(shù)組和矩陣的第一大庫(kù),它非常方便,可以使用 NumPy 方法操作和修改 OpenCv 圖像數(shù)據(jù)。

背景

混合圖像

關(guān)于如何使用 OpenCV 將存儲(chǔ)在一個(gè)圖像中的信息與第二個(gè)圖像的信息合并的示例代碼在網(wǎng)絡(luò)上廣泛可用。例如,?cv2.addWeighted(image1, weighting_factor1, image2, weighting_factor2)?OpenCV 函數(shù)是一種單線函數(shù),能夠以簡(jiǎn)單的方式執(zhí)行圖像混合。如果兩個(gè)加權(quán)因子都選擇 0.5,則該函數(shù)返回兩個(gè)圖像的等權(quán)重(或均值)混合。選擇 0.7 和 0.3 作為輸入權(quán)重,將導(dǎo)致圖像由第一幅圖像的 70% 像素顏色和第二幅圖像的 30% 像素顏色組成。再舉一個(gè)例子,選擇 1 和 0 將返回圖像一的未更改版本,而 0 和 1 將返回圖像二的未更改版本。我提到這一點(diǎn),因?yàn)樗谙旅孀兊煤苤匾?,?dāng)我進(jìn)入我編寫(xiě)的代碼的細(xì)節(jié)時(shí)。

使用掩碼插入圖像

該? cv2.addWeighted()?當(dāng)兩個(gè)相同大小的圖像的信息(或更準(zhǔn)確地說(shuō),感興趣的區(qū)域)的信息被組合并且相同的加權(quán)因子應(yīng)用于所有像素時(shí),該函數(shù)特別有用。然而,有時(shí)人們計(jì)劃將特定區(qū)域從一張圖像轉(zhuǎn)移到另一張圖像。這可以通過(guò)不同的方式完成,但一種常見(jiàn)的方法是使用面具。掩碼通常是一個(gè)二進(jìn)制圖像(僅包含黑色和白色像素),用作包圍插入或混合區(qū)域的模板。為了澄清這一點(diǎn),我舉了一個(gè)例子。如果希望將圖像的天空替換為第二張圖像的背景,則蒙版(或二值圖像)需要有一個(gè)黑色區(qū)域代表圖像一的天空,以便程序“知道”該放在哪里圖二的背景。換句話說(shuō),其中像素顏色為黑色(8 位圖像中的 0;[0,0,

使用加權(quán)因子矩陣進(jìn)行圖像疊加

在我在這里展示的示例代碼中,我將圖像混合方法與基于掩碼的圖像插入方法結(jié)合起來(lái)。與“標(biāo)準(zhǔn)”方法相比,我使用非二進(jìn)制掩碼(可以保存 0 到 255 之間的所有值),其中每個(gè)像素都用作單獨(dú)的權(quán)重。因此,我沒(méi)有定義圖像一的整體加權(quán)因子(例如,0.7)和圖像二的整體加權(quán)因子(例如,0.3),而是使用掩碼的每個(gè)像素作為加權(quán)因子(參見(jiàn)下圖)。例如,如果掩碼中位于 [X, Y] 位置的像素的值為 0(即黑色),則圖像 1 的像素將放置在該位置。如果掩碼的一個(gè)像素保持值 255(白色),則圖像 2 的相應(yīng)像素將占據(jù)該位置。如果它介于兩者之間(例如,170),則會(huì)混合圖像一和圖像二。使用掩碼作為由權(quán)重因子組成的地圖在疊加兩個(gè)圖像時(shí)提供了更大的靈活性。它可以產(chǎn)生過(guò)渡或“軟”邊界(甚至更多)。


使用代碼

我將您可以在存儲(chǔ)庫(kù)中找到的代碼示例分為四個(gè)部分。下面,我只展示了兩個(gè)內(nèi)部部分的代碼,因?yàn)樗鼈兒w了本教程的主要主題。為完整起見(jiàn),我在下面簡(jiǎn)要評(píng)論第 1 節(jié)和第 4 節(jié),然后以要點(diǎn)的形式提供第 2 節(jié)和第 3 節(jié)的基本信息。

在第 1 節(jié)中,您可以找到用于加載所需圖像(即?cv2.imread(“X.jpg”,cv2.IMREAD_UNCHANGED)?)的OpenCV 代碼。有三個(gè)圖像:image 1 是在其上的內(nèi)容的表面image 2 粘貼,并且image 3 是限定用于混合操作條件的掩模或模板。還有一些附加功能,但我留給您去了解它們的用途(我上傳的示例代碼中有信息豐富的注釋?zhuān)?/p>

在第 4 節(jié)中,您會(huì)發(fā)現(xiàn)一個(gè)“?while?循環(huán)”,它允許與程序進(jìn)行一種基本的交互。循環(huán)正在等待關(guān)鍵事件。按“ ?q?”退出程序,按“ ?s?”保存混合操作結(jié)果后退出程序。

第 2 節(jié)和第 3 節(jié)包含用于根據(jù)掩碼提供的加權(quán)因子混合兩個(gè)圖像信息的代碼。

  • 該函數(shù) ?mix_pixel(pix_1, pix_2, perc)?以類(lèi)似的方式處理輸入?cv2.addWeighted()?。它根據(jù)在第三個(gè)參數(shù)(即,給定的權(quán)重需要從兩個(gè)圖像和共混物像素信息?perc?的功能的)(例如,當(dāng)?perc?在0和255的中間,它給出了一個(gè)50-50混合像素1和像素 2;另請(qǐng)參見(jiàn)混合圖像部分)。當(dāng)參數(shù)為?NumPy?數(shù)組時(shí)(注意:所有數(shù)組需要具有相同的維度),操作將應(yīng)用于圖像的所有對(duì)應(yīng)像素。第三個(gè)參數(shù)是一個(gè)數(shù)組(掩碼),其中包含每個(gè)像素的單獨(dú)加權(quán)因子。
  • 該?blend_images_using_mask(img_orig, img_for_overlay,img_mask)?功能是相當(dāng)簡(jiǎn)單的。它獲取三張圖像,檢查掩碼是否為 3 通道灰度圖像(否則,它不會(huì)與其他圖像具有相同的維度),調(diào)用該mix_pixel()函數(shù),然后將結(jié)果作為 3 通道 8 位無(wú)符號(hào)整數(shù)返回(否則用于顯示圖像的 OpenCV 命令將失?。?。
  • 您在下面的示例中找到的最終命令用于顯示不同類(lèi)型的圖像,以使過(guò)程的結(jié)果可見(jiàn)并可用于評(píng)估。還有一些代碼行用于使圖像變小,因?yàn)檎掌脑汲叽鐚?duì)于標(biāo)準(zhǔn)屏幕來(lái)說(shuō)通常太大。
# code skeleton

import numpy as np
import cv2

# .......omitted code

# functions for blending operations

# takes a pixel from image 1 (pix_1) and blends it with a pixel from image 2 (pix_2)

# depending on the value given in perc (percentage);

# if perc = 0 or 255 (or 0,0,0 or 255,255,255) it will perform no blending at all 

# and return the value of image 1 or image 2;

# by contrast, all values in between (e.g., 140) will give a weighted blend of the two images

# function can be used with scalars or numpy arrays (perc will be greyscale numpy array then)

def mix_pixel(pix_1, pix_2, perc):

    return (perc/255 * pix_1) + ((255 - perc)/255 * pix_2)

# function for blending images depending on values given in mask

def blend_images_using_mask(img_orig, img_for_overlay, img_mask):

    # turn mask into 24 bit greyscale image if necessary

    # because mix_pixel() requires numpy arrays having the same dimension

    # if image is 24-bit BGR, the image has 3 dimensions, if 8 bit greyscale 2 dimensions

    if len(img_mask.shape) != 3:

        img_mask = cv2.cvtColor(img_mask, cv2.COLOR_GRAY2BGR)

    # interpolate between two images (img_orig and img_to_insert)

    # using the values in img_mask (each pixel serves as individual weight)
    
    # as weighting factors (ranging from [0,0,0] to [255,255,255] or 0 to 100 percent);

    # because all three images are numpy arrays standard operators

    # for multiplication etc. will be applied to all values in arrays

    img_res = mix_pixel(img_orig, img_for_overlay, img_mask)

    return img_res.astype(np.uint8)

# blend images and display results

# call function above to perform blending with mask (containing weights for interpolation)

img_blended = blend_images_using_mask(img, img_insert, img_insert_mask)

#print(img_blended.shape)

# rf -> resizing factor; used to make images smaller, so they can be displayed on screen;

# blending operations, however, will be performed on original sized images

rf = 0.4

wi = img.shape[1] # width and

hi = img.shape[0] # height of images

 # call OpenCV resize 
img_sm = cv2.resize(img, (int(wi * rf), int(hi * rf)),

                    interpolation=cv2.INTER_CUBIC)

img_insert_sm = cv2.resize(

    img_insert, (int(wi * rf), int(hi * rf)), interpolation=cv2.INTER_CUBIC)

img_blended_sm = cv2.resize(

    img_blended, (int(wi * rf), int(hi * rf)), interpolation=cv2.INTER_CUBIC)

# display images

cv2.imshow("Original Image", img_sm)

cv2.imshow("Insert This Image", img_insert_sm)

cv2.imshow("Blended Images", img_blended_sm) 

# .......omitted code

如果您想要了解更多關(guān)于Python OpenCV的內(nèi)容,推薦大家可以系統(tǒng)地學(xué)習(xí)一下OpenCV相關(guān)教程。


0 人點(diǎn)贊