0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

使用Python+OpenCV處理圖片

安費諾傳感器學堂 ? 來源:安費諾傳感器學堂 ? 2024-12-23 15:54 ? 次閱讀

如果給你一張圖片作為背景,另外一張圖片中的物體作為前景圖,要把前景圖中的物體疊加布置到背景圖的中間位置,并且前景圖中的物體需要在背景圖中有旋轉(zhuǎn)和投影,怎么處理?

如果是一兩張圖,PS應(yīng)該是首選,但是如果是批量的呢?這就是小編要準備處理的一個小問題。挑戰(zhàn)一下,用Python+OpenCV來實現(xiàn)這個小目標。

提出問題和解決思路

作為前景的圖片的背景是白色不透明的,不過這就有條件實現(xiàn)摳圖了

前景圖的尺寸甚至比背景圖大,要縮小并且要算出位置

如果圖片沒有透明層來控制,則需要轉(zhuǎn)換并添加透明層

疊加的前景圖需要可以控制旋轉(zhuǎn)角度,但旋轉(zhuǎn)同時也影響前景圖的尺寸

摳圖進行疊加效果不好怎么辦?要進行羽化模糊化處理

為了讓圖片的疊加更加自然,還要考慮讓前景物體在背景上投個影

代碼驗證

1. 摳圖,取出前景物體的兩種處理方式比較

為了看到中間過程,代碼中添加了加輪廓線和掩碼圖兩個中間圖的輸出。

1.1 通過cv2.bitwise_and()函數(shù)處理輪廓掩碼

下面首先使用cv2.bitwise_and()函數(shù)處理。掩碼圖是有透明度控制層的,每個像素,在輪廓線外的的像素值是(B, G, R, A)=(0,0,0,0),輪廓線內(nèi)的像素值是(B, G, R, A)=(255,255,255,255)。這種情況下,前景圖中任何在輪廓線外的像素和掩碼圖對應(yīng)位置的掩碼像素進行按位“與”操作時,都會變成透明‘人’,而輪廓線內(nèi)部的原圖像素則會保留原值。

這里OpenCV中的一個函數(shù)是個關(guān)鍵。注意閾值thresh。


contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

import cv2
import numpy as np
import tkinter as tk


def get_display_size():
    root = tk.Tk()
    width = root.winfo_screenwidth()
    height = root.winfo_screenheight()
    root.quit()
    return width, height


def extract_contour_from_jpg(image_path, output_path):
    # 讀取JPEG圖像
    image = cv2.imread(image_path)
    # 如果是 JPG 圖像,轉(zhuǎn)換為 BGRA 格式以支持透明度
    if image.shape[2] == 3:  # Assuming BGR without alpha
        image = cv2.cvtColor(image, cv2.COLOR_BGR2BGRA)
    # 轉(zhuǎn)換為灰度圖像
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)


    # 應(yīng)用閾值操作以找到物體
_,thresh=cv2.threshold(gray,240,255,cv2.THRESH_BINARY_INV)
    
    # 找到輪廓
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)


#創(chuàng)建一個全透明的背景
    result = np.zeros_like(image)


    # 在原圖區(qū)域上填充在掩碼中不透明的區(qū)域
    for contour in contours:
        cv2.drawContours(result, [contour], -1, (255, 255, 255, 255), thickness=cv2.FILLED)


    # 在原圖上畫出輪廓線
    # 獲取圖像的尺寸
    original_height, original_width = image.shape[:2]
    
#為輸出中間圖計算縮放比例
    display_size = get_display_size()
    scale_width = display_size[0] / original_width
    scale_height = display_size[1] / original_height
    scale = min(scale_width, scale_height)
    
    # 計算新的尺寸
    new_width = int(original_width * scale)
    new_height = int(original_height * scale)
    
    # 為輸出中間圖而調(diào)整圖像大小
    image_contours = image.copy()
    cv2.drawContours(image_contours, contours, -1, (0, 255, 0, 255), thickness=2) # 綠色的輪廓線
    resized_image = cv2.resize(image_contours, (new_width, new_height), interpolation=cv2.INTER_AREA)


    cv2.imshow('contours', resized_image)
    cv2.waitKey(0)
    
    # 僅保留原圖在不透明區(qū)域(內(nèi)部)的像素
    resized_resultimage = cv2.resize(result, (new_width, new_height), interpolation=cv2.INTER_AREA)
    cv2.imshow('resized_resultimage', resized_resultimage)
    cv2.waitKey(0)
    
    result = cv2.bitwise_and(image, result)
    
    # 將結(jié)果圖像保存為支持透明度的文件格式(如PNG)
    cv2.imwrite(output_path, result)
    


# 使用示例
if __name__=='__main__':
    input_file = "Your_ForGround_Image_Path.png"


    output_file = "You_Output_transparent_Img_Path.png"


    extract_contour_from_jpg(input_file, output_file)

通過上面的代碼,我們可以得到前景圖中的物體,并且使得物體周邊的像素成為透明。下面的示意圖是在PPT中操作的,僅僅是為了顯示這個產(chǎn)品圖已經(jīng)成功取出,在圖的背后添加了藍色。

我們看看細節(jié)。是不是無法忍受這些毛刺?

所以,通過“cv2.bitwise_and()”處理后得到的物體還是有點問題,我們需要對物體的周邊進行平滑處理。于是有了下面優(yōu)化后的代碼,通過“cv2.GaussianBlur()”這個函數(shù)對得到的填充后的輪廓灰度圖的邊沿進行羽化處理,就可以對于輪廓的周邊進行平滑處理。

1.2 通過cv2.GaussianBlur()函數(shù)處理輪廓后的改善

我們直接上代碼。

import cv2
import numpy as np
import tkinter as tk


def get_display_size():
    root = tk.Tk()
    width = root.winfo_screenwidth()
    height = root.winfo_screenheight()
    root.quit()
    return width, height


def feather_object_contour(image_path, feather_size=10):
    # 讀取圖像
    image = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)
    # 如果是 JPG 圖像,轉(zhuǎn)換為 BGRA 格式以支持透明度 / Convert JPG image to BGRA format to support transparency
    if image.shape[2] == 3:  # Assuming BGR without alpha
        image = cv2.cvtColor(image, cv2.COLOR_BGR2BGRA)
    # 獲取圖像的尺寸 / Get the dimensions of the image
    original_height, original_width = image.shape[:2]
    
    # 計算縮放比例 / Calculate scale ratio
    display_size = get_display_size()
    scale_width = display_size[0] / original_width
    scale_height = display_size[1] / original_height
    scale = min(scale_width, scale_height)
    
    # 計算新的尺寸 / Calculate new dimensions
    new_width = int(original_width * scale)
    new_height = int(original_height * scale)
    
    # 轉(zhuǎn)換為灰度圖像 / Convert to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
    # 二值化以識別物體 / Binarize to identify objects
    # 應(yīng)用閾值,選擇較高的閾值來分離掉白色背景 / Apply threshold to separate white background
    _, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)


    # 查找物體的輪廓 / Find contours of the object
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)


    # 創(chuàng)建一個新圖像用于繪制輪廓 / Create a new image for drawing contours
    contour_mask = np.zeros_like(gray)


    # 在輪廓區(qū)域上填充 / Fill in the contour area
    for contour in contours:
        cv2.drawContours(contour_mask, [contour], -1, (255, 255, 255, 255), thickness=cv2.FILLED)
    
    # 對輪廓進行高斯模糊處理 / Apply Gaussian blur to the contour
    smoothed_mask = cv2.GaussianBlur(contour_mask, (feather_size, feather_size), 0)
    resized_image = cv2.resize(smoothed_mask, (new_width, new_height), interpolation=cv2.INTER_AREA)


    cv2.imshow('feathered_mask', resized_image)
    cv2.waitKey(0)
    
    # 確保圖像具有透明通道 / Ensure the image has an alpha channel
    if image.shape[2] == 3:
        image = cv2.cvtColor(image, cv2.COLOR_BGR2BGRA)
    
    # 應(yīng)用羽化到透明通道 / Apply feathering to the alpha channel
    # 基于羽化輪廓掩模設(shè)置透明度 / Set alpha based on feathered contour mask
    smoothed_alpha = (smoothed_mask.astype(np.float32) / 255.0)
    alpha_channel = (255 * smoothed_alpha).astype(np.uint8)
    image[..., 3] = alpha_channel
    
    return image


# 使用示例
feathered_image=feather_object_contour('Your_ForGround_Image_Path.png',feather_size=5)
cv2.imshow('Blurred Img', feathered_image)
cv2.waitKey(0)
cv2.imwrite('You_Output_transparent_Img_Path.png', feathered_image)

下面是效果圖,可以和上面的圖進行比較。



2. 圖片疊加:前景圖和背景圖的疊加處理

既然有了上面PPT的效果,為什么還要用程序?qū)崿F(xiàn)?

不如多問一句:如果類似的圖處理有很多呢?

把這個取出的前景圖按照比例進行縮放,移動,旋轉(zhuǎn),得到新的前景圖,再通過前景圖中的像素的透明度來控制兩個圖的疊加效果。但是要增加投影的話,實際上需要第三個圖,也即投影圖,并且投影的圖中也需要一個柔和的過渡。

代碼中設(shè)置了前景圖和背景圖的比例關(guān)系,避免了合成之后前景圖尺寸的不一致。

合成圖片的代碼如下,效果圖后隨。

import cv2
import numpy as np


"""
要在圖像合成中使用羽化(或模糊)處理前景圖的透明邊緣附近,以便在背景圖上生成一個朝指定方向的陰影效果,可以通過以下步驟實現(xiàn)。
這個過程通常涉及到對前景圖的透明度(alpha 通道)進行處理,然后將其偏移并疊加到背景圖上。
"""
def create_shadow_effect(image, feather_size=10, shadow_offset=(10,10), shadow_color=(0, 0, 0, 128)):
    # 創(chuàng)建透明度通道的副本
    alpha = image[:, :, 3]


    # 使用高斯模糊處理 alpha 通道,以實現(xiàn)邊緣羽化
    feathered_alpha = cv2.GaussianBlur(alpha, (0, 0), sigmaX=feather_size, sigmaY=feather_size)
    
#創(chuàng)建一個純色圖層用于陰影效果
    shadow_layer = np.zeros_like(image)
    shadow_layer[:, :, :3] = shadow_color[:3]
    shadow_layer[:, :, 3] = feathered_alpha * (shadow_color[3] / 255.0)


    # 創(chuàng)建空白圖像作為陰影圖層
    shadow = np.zeros_like(image)
    x_offset, y_offset = shadow_offset


    # 調(diào)整大小以適應(yīng)原圖像的邊界
    y_bound = min(shadow_layer.shape[0], shadow.shape[0] - y_offset)
    x_bound = min(shadow_layer.shape[1], shadow.shape[1] - x_offset)


    # 復(fù)制陰影到陰影圖層中
    shadow[y_offset:y_offset + y_bound, x_offset:x_offset + x_bound] = shadow_layer[:y_bound, :x_bound]


    return shadow


# 融合三個圖
def blend_images(background, foreground, shadow):
    for y in range(shadow.shape[0]):
        for x in range(shadow.shape[1]):
            # Blend shadow into the background
            alpha_shadow = shadow[y, x, 3] / 255.0
            background[y, x, :3] = (shadow[y, x, :3] * alpha_shadow +
                                    background[y, x, :3] * (1 - alpha_shadow))


    for y in range(foreground.shape[0]):
        for x in range(foreground.shape[1]):
            # Blend foreground into the background
            alpha_fg = foreground[y, x, 3] / 255.0
            background[y, x, :3] = (foreground[y, x, :3] * alpha_fg +
                                    background[y, x, :3] * (1 - alpha_fg))
# 旋轉(zhuǎn),縮放以及融合            
def rotate_and_overlay(background_path, overlay_path, output_path, angle=30, feather_size=10):
    # 檢查前景圖有無透明層通道:創(chuàng)建一個帶有Alpha通道的
    bg_image = cv2.imread(background_path, cv2.IMREAD_UNCHANGED)
    if bg_image.shape[2] == 3:
        bg_image = cv2.cvtColor(bg_image, cv2.COLOR_BGR2BGRA)
    # 檢查背景圖有無透明層通道:創(chuàng)建一個帶有Alpha通道的
    fg_image = cv2.imread(overlay_path, cv2.IMREAD_UNCHANGED)
    if fg_image.shape[2] == 3:
        fg_image = cv2.cvtColor(fg_image, cv2.COLOR_BGR2BGRA)
        
    # 前景圖尺寸需要縮放
    original_height, original_width = fg_image.shape[:2]
    scale = 650.0/870.0
    
    # 計算新的尺寸
    fg_new_width = int(original_width * scale)
    fg_new_height = int(original_height * scale)
    
    # 新尺寸的前景圖
    fg_image = cv2.resize(fg_image, (fg_new_width, fg_new_height), interpolation=cv2.INTER_AREA)
    
    # 獲取前景圖像的中心
    fg_center = (fg_image.shape[1] // 2, fg_image.shape[0] // 2)


    # 創(chuàng)建旋轉(zhuǎn)矩陣(順時針旋轉(zhuǎn)30度)
    rot_matrix = cv2.getRotationMatrix2D(fg_center, angle, 1.0)


    # 計算旋轉(zhuǎn)后的圖像維度
    cos = np.abs(rot_matrix[0, 0])
    sin = np.abs(rot_matrix[0, 1])
    new_width = int((fg_image.shape[0] * sin) + (fg_image.shape[1] * cos))
    new_height = int((fg_image.shape[0] * cos) + (fg_image.shape[1] * sin))


    # 調(diào)整旋轉(zhuǎn)矩陣的移動量
    rot_matrix[0, 2] += (new_width / 2) - fg_center[0]
    rot_matrix[1, 2] += (new_height / 2) - fg_center[1]


    # 旋轉(zhuǎn)前景圖像
    rotated_fg = cv2.warpAffine(fg_image, rot_matrix, (new_width, new_height), 
                                borderMode=cv2.BORDER_CONSTANT, borderValue=(0, 0, 0, 0))


    # 創(chuàng)建陰影效果圖像
    shadow = create_shadow_effect(rotated_fg, feather_size=feather_size)
    
    # 將陰影和前景圖疊加到背景圖上
    x_offset = (bg_image.shape[1] - shadow.shape[1]) // 2
    y_offset = (bg_image.shape[0] - shadow.shape[0]) // 2
    
    blend_images(bg_image[y_offset:y_offset + shadow.shape[0], x_offset:x_offset + shadow.shape[1]], rotated_fg, shadow)


    # 保存結(jié)果圖像
    cv2.imwrite(output_path, bg_image)


# 調(diào)用示例
backGround_ImgPath='Your_backGround_ImgPath.png'
forGround_ImgPath = 'Your_forGround_ImgPath.png'
output_ImgPath = 'Your_output_ImgPath.png'
rotate_and_overlay(backGround_ImgPath, forGround_ImgPath, output_ImgPath, feather_size=5)

測試代碼的圖片疊加效果如下。

局部看起來還可以。甚至可以看到這個傳感器芯片的角度和前一個有一個轉(zhuǎn)角。是的,這里把前景圖整體轉(zhuǎn)動了一個指定的角度。

投影的效果看起來也比較自然。

上面就是小編要批量處理圖片的工具了,圖片量大的話,把代碼調(diào)整修改之后,就可以對文件夾中的所有圖片進行處理了,效率超過PhotoShop是沒有問題的。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4331

    瀏覽量

    62605
  • OpenCV
    +關(guān)注

    關(guān)注

    31

    文章

    635

    瀏覽量

    41347
  • python
    +關(guān)注

    關(guān)注

    56

    文章

    4797

    瀏覽量

    84682

原文標題:用Python處理圖片:摳物體輪廓圖、透明化、圖片疊加以及圖中前景物體陰影的生成

文章出處:【微信號:安費諾傳感器學堂,微信公眾號:安費諾傳感器學堂】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    【Raspberry Pi 3試用體驗】+Opencv+python的人臉識別

    ;)看一下效果:光線不好還是能認出來,說明opencv自帶的分類器算開源里面不錯的了~參考:Tigerboard開發(fā)板試用體驗 python+opencv的人臉識別 NanoPi2試用體驗 簡單人臉識別-結(jié)項
    發(fā)表于 05-13 21:38

    基于機器學習庫opencv和平臺Jupyter Notebook的車牌識別案例

    python+opencv實現(xiàn)車牌識別
    發(fā)表于 02-28 11:08

    【Toybrick RK3399Pro AI開發(fā)板試用體驗】ACT Ⅵ:Linux下靜態(tài)人臉識別 python+opencv

    程序,只要點擊run即可,也不會報錯。看了網(wǎng)上很多教程,python+opencv,在有深度訓練源的情況下,7行代碼就能實現(xiàn),那我們現(xiàn)在就來試一試。首先,我們要找一個訓練過的人臉的源,看了下大神的代碼,我
    發(fā)表于 08-10 10:50

    LabVIEW+Python+openCV

    的,動態(tài)鏈接庫也需要配置,還需要知道各個參數(shù)含義和類型,這里提供另外一種方法,那就是PythonopenCV工具包,絕對開源和免費,LabVIEW可以利用Python節(jié)點調(diào)用Python
    發(fā)表于 12-07 20:59

    OpenCV-Python-Toturial-中文版

    python編寫opencv的入門資料,介紹了python的各個函數(shù)的應(yīng)用
    發(fā)表于 03-23 14:55 ?0次下載

    Python下使用OpenCV的技巧教程與典型應(yīng)用案例

    Python下使用OpenCV教程,本篇將介紹和深度學習數(shù)據(jù)處理階段最相關(guān)的基礎(chǔ)使用,并完成4個有趣實用的小例子: - 延時攝影小程序 - 視頻中截屏采樣的小程序 - 圖片數(shù)據(jù)增加(
    發(fā)表于 11-15 18:43 ?1.2w次閱讀

    python圖像處理opencv步驟是怎么樣的

    越來越覺得python是一強大的工具,處理樣本確實不錯。最近因項目需要涉及到圖片處理,所以開始用python調(diào)用
    發(fā)表于 12-04 15:29 ?4412次閱讀

    OpenCV中的Python實現(xiàn)

    類構(gòu)成,同時提供了Python、Ruby、MATLAB等語言的接口,實現(xiàn)了圖像處理和計算機視覺方面的很多通用算法。 OpenCV用C++語言編寫,它的主要接口也是C++語言,但是依然保留了大量的C語言
    的頭像 發(fā)表于 08-25 15:55 ?2077次閱讀

    使用opencvpython進行智能火災(zāi)檢測

    電子發(fā)燒友網(wǎng)站提供《使用opencvpython進行智能火災(zāi)檢測.zip》資料免費下載
    發(fā)表于 11-02 15:08 ?0次下載
    使用<b class='flag-5'>opencv</b>和<b class='flag-5'>python</b>進行智能火災(zāi)檢測

    opencv讀入圖片注意事項詳解1

    深度學習數(shù)據(jù)預(yù)處理中常用opencv讀入圖片,一般在`__getitem__`函數(shù)中調(diào)用。本文主要介紹opencv讀取圖片的一些細節(jié)以及注意
    的頭像 發(fā)表于 02-07 16:06 ?624次閱讀

    opencv讀入圖片注意事項詳解 2

    深度學習數(shù)據(jù)預(yù)處理中常用opencv讀入圖片,一般在`__getitem__`函數(shù)中調(diào)用。本文主要介紹opencv讀取圖片的一些細節(jié)以及注意
    的頭像 發(fā)表于 02-07 16:06 ?671次閱讀

    如何使用Python+opencv進行圖像處理

    圖像是 Web 應(yīng)用中除文字外最普遍的媒體格式。流行的 Web 靜態(tài)圖片有 JPEG、PNG、ICO、BMP 等。動態(tài)圖片主要是 GIF 格式。 為了節(jié)省圖片傳輸流量,大型互聯(lián)網(wǎng)公司還會定制特殊格式的
    的頭像 發(fā)表于 02-08 10:57 ?925次閱讀
    如何使用<b class='flag-5'>Python+opencv</b>進行圖像<b class='flag-5'>處理</b>

    OpenCV 如何加載圖片

    實現(xiàn)一遍。 OpenCV 的內(nèi)容挺多的,而且不使用的話,容易忘記,所以通過制造工具的方式來給自己加深印象,平常要處理圖片的時候,就可以用自己的工具直接處理,不需要每次都去重復(fù)的寫代碼。
    的頭像 發(fā)表于 10-09 15:01 ?724次閱讀

    opencv-pythonopencv一樣嗎

    不一樣。OpenCV(Open Source Computer Vision Library)是一個開源的計算機視覺和機器學習軟件庫,它提供了大量的圖像和視頻處理功能。OpenCV-Python
    的頭像 發(fā)表于 07-16 10:38 ?1195次閱讀

    一個月速成python+OpenCV圖像處理

    OpenCV是一個廣受歡迎且極為流行的計算機視覺庫,它因其強大的功能、靈活性和開源特性而在開發(fā)者和研究者中備受青睞。學習OpenCV主要就是學習里面的計算機視覺算法。要學習這些算法的原理,知道它們
    的頭像 發(fā)表于 11-29 18:27 ?140次閱讀
    一個月速成<b class='flag-5'>python+OpenCV</b>圖像<b class='flag-5'>處理</b>