App下載

使用 Python 和 OpenCV 進行圖像混合

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

Python 和 OpenCV 庫使處理圖像或視頻等視覺輸入變得非常容易。在本篇文章中,我將討論有關圖像混合的內容并提出一種合并兩個圖像的像素信息的方法。為了實現這一點,我使用了第三張圖像(所謂的蒙版),作為混合過程的模板。因為這個模板是一個加權因子矩陣,所以有可能產生結果,這是通常在網上找到的混合方法無法獲得的(或者至少我沒有找到)。

簡介

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

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

背景

混合圖像

關于如何使用 OpenCV 將存儲在一個圖像中的信息與第二個圖像的信息合并的示例代碼在網絡上廣泛可用。例如,?cv2.addWeighted(image1, weighting_factor1, image2, weighting_factor2)?OpenCV 函數是一種單線函數,能夠以簡單的方式執(zhí)行圖像混合。如果兩個加權因子都選擇 0.5,則該函數返回兩個圖像的等權重(或均值)混合。選擇 0.7 和 0.3 作為輸入權重,將導致圖像由第一幅圖像的 70% 像素顏色和第二幅圖像的 30% 像素顏色組成。再舉一個例子,選擇 1 和 0 將返回圖像一的未更改版本,而 0 和 1 將返回圖像二的未更改版本。我提到這一點,因為它在下面變得很重要,當我進入我編寫的代碼的細節(jié)時。

使用掩碼插入圖像

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

使用加權因子矩陣進行圖像疊加

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


使用代碼

我將您可以在存儲庫中找到的代碼示例分為四個部分。下面,我只展示了兩個內部部分的代碼,因為它們涵蓋了本教程的主要主題。為完整起見,我在下面簡要評論第 1 節(jié)和第 4 節(jié),然后以要點的形式提供第 2 節(jié)和第 3 節(jié)的基本信息。

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

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

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

  • 該函數 ?mix_pixel(pix_1, pix_2, perc)?以類似的方式處理輸入?cv2.addWeighted()?。它根據在第三個參數(即,給定的權重需要從兩個圖像和共混物像素信息?perc?的功能的)(例如,當?perc?在0和255的中間,它給出了一個50-50混合像素1和像素 2;另請參見混合圖像部分)。當參數為?NumPy?數組時(注意:所有數組需要具有相同的維度),操作將應用于圖像的所有對應像素。第三個參數是一個數組(掩碼),其中包含每個像素的單獨加權因子。
  • 該?blend_images_using_mask(img_orig, img_for_overlay,img_mask)?功能是相當簡單的。它獲取三張圖像,檢查掩碼是否為 3 通道灰度圖像(否則,它不會與其他圖像具有相同的維度),調用該mix_pixel()函數,然后將結果作為 3 通道 8 位無符號整數返回(否則用于顯示圖像的 OpenCV 命令將失敗)。
  • 您在下面的示例中找到的最終命令用于顯示不同類型的圖像,以使過程的結果可見并可用于評估。還有一些代碼行用于使圖像變小,因為照片的原始尺寸對于標準屏幕來說通常太大。
# 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

如果您想要了解更多關于Python OpenCV的內容,推薦大家可以系統(tǒng)地學習一下OpenCV相關教程


0 人點贊