99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁大數(shù)據(jù)時代基于OpenCV的圖像卡通化
基于OpenCV的圖像卡通化
2020-08-11
收藏


文章來源: 小白學視覺

作者:努比

本期將創(chuàng)建一個類似于Adobe Lightroom的Web應(yīng)用程序,使用OpenCV和Streamlit實現(xiàn)圖像的卡通化

作為一個狂熱的街頭攝影愛好者,幾乎每個周末都要在城市中拍攝一些照片,因此Adobe Lightroom始終是我們的首選軟件,通過它可以編輯原始照片以使其更具“ Instagram風格”。

我們想能否創(chuàng)建一個自己的圖像編輯軟件?

開源計算機視覺庫(如OpenCV)和開源應(yīng)用程序框架(如Streamlit)的出現(xiàn)使這一想法得以實現(xiàn)。使用不到100行代碼,我們就可以構(gòu)建一個簡單的圖像卡通化Web應(yīng)用程序,模仿Adobe Lightroom的功能。

在本文中,我們將展示如何使用OpenCV和Streamlit,根據(jù)濾波器,構(gòu)建一個簡單的Web應(yīng)用程序,以將圖像轉(zhuǎn)換為卡通圖像。

如何使圖像成為卡通圖?

我們通常需要執(zhí)行兩個主要步驟將圖像轉(zhuǎn)換為卡通圖像:邊緣檢測和區(qū)域平滑。

邊緣檢測的主要目的顯然是為了強調(diào)圖像的邊緣,因為卡通圖像通常具有良好的邊緣。同時,區(qū)域平滑的主要目的是消除顏色邊界并減少圖像的噪點,使圖像像素化程度降低。

根據(jù)不同濾波器,我們可以獲得不同的圖像卡通化結(jié)果。在本文中,將有四個不同的過濾器:

1. 鉛筆素描

2. 細節(jié)增強

3. 雙邊過濾器

4. 鉛筆邊緣

接下來,我們將展示如何應(yīng)用每個過濾器,以及從每個過濾器中獲得什么樣的結(jié)果。

鉛筆素描濾波器

使用“鉛筆素描”濾波器,您的圖像將被轉(zhuǎn)換為素描,就像使用鉛筆繪制圖像一樣。下面是使用OpenCV將圖像轉(zhuǎn)換為鉛筆素描的完整代碼。

# Convert the image into grayscale image
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Blur the image using Gaussian Blur 
gray_blur = cv2.GaussianBlur(gray, (25, 25), 0)

# Convert the image into pencil sketch
cartoon = cv2.divide(gray, gray_blur, scale=250.0)

令人驚訝的是,使用OpenCV,我們只需三行代碼就可以將圖像轉(zhuǎn)換成鉛筆素描狀的圖片?,F(xiàn)在讓我逐行解釋一下該圖像發(fā)生了哪些變化。

在第一行中,我們使用OpenCV的cvtColor()功能將圖像從彩色通道轉(zhuǎn)換為灰度通道。這很簡單,處理的結(jié)果是我們將圖像變成了灰度圖。

接下來,我們使用高斯模糊對圖像進行模糊處理。模糊灰度圖像,實際上是在平滑圖像,減少圖像的噪點。另外,模糊也是我們檢測圖像邊緣的必要步驟。

模糊圖像,可以使用OpenCV中的GaussianBlur()功能。我在GaussianBlur()函數(shù)中輸入的(25,25)是內(nèi)核的大小。

由于我們使用高斯模糊,因此內(nèi)核中像素值的分布遵循正態(tài)分布。核數(shù)越大,標準偏差將越大,因此模糊效果越強。下面是內(nèi)核大小不同時的模糊結(jié)果示例。

基于不同內(nèi)核大小的模糊效果

最后一步是將原始灰度圖像除以模糊后的灰度圖像。這樣可以得出兩個圖像中每個像素之間的變化率。模糊效果越強,每個像素的值相對于其原點的變化就越大,因此,它使我們的鉛筆素描更加清晰。

以下是使用鉛筆素描過濾器的結(jié)果。

鉛筆素描過濾器實現(xiàn)示例

細節(jié)增強濾波器

簡而言之,“細節(jié)增強”濾鏡通過銳化圖像,平滑顏色以及增強邊緣效果為我們提供了卡通效果。以下是使用此濾鏡將您的圖像轉(zhuǎn)換成卡通的完整代碼。

#convert the image into grayscale image
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#Blur the grayscale image with median blur
gray_blur = cv2.medianBlur(gray, 3) 

#Apply adaptive thresholding to detect edges
edges = cv2.adaptiveThreshold(gray_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9) 

#Sharpen the image
color = cv2.detailEnhance(img, sigma_s=5, sigma_r=0.5)

#Merge the colors of same images using "edges" as a mask
cartoon = cv2.bitwise_and(color, color, mask=edges)

第一步與之前相同,我們需要將圖像轉(zhuǎn)換為灰度圖像。

接下來,不使用高斯模糊,而是應(yīng)用中值模糊。為此,我們使用OpenCV中的medianBlur() 函數(shù)。中值模糊通過計算與內(nèi)核重疊的像素值的中值,然后將其中心像素替換為中值。但是,我們可以根據(jù)需要先使用高斯模糊。

接下來,我們需要檢測圖像的邊緣。為此,將自適應(yīng)閾值與OpenCV中的adaptiveThreshold() 函數(shù)一起應(yīng)用。自適應(yīng)閾值的主要目標是根據(jù)內(nèi)核重疊的像素的平均值,將圖像每個區(qū)域中的每個像素值轉(zhuǎn)換為黑色或白色。

以下是自適應(yīng)閾值對模糊圖像的影響的可視化結(jié)果。

左:自適應(yīng)閾值之前—右:自適應(yīng)閾值之后

為了使圖像看起來更清晰,我們可以使用OpenCV中的detailEnhance()函數(shù)。我們需要指定兩個參數(shù):

? sigma_s:控制著鄰域的大小,該鄰域的大小將被加權(quán)以替換圖像中的像素值。值越高,鄰域越大。這樣可以使圖像更平滑。

? sigma_r:如果要在平滑圖像時保留邊緣,這很重要。較小的值只會產(chǎn)生非常相似的顏色進行平均(即平滑),而相差很大的顏色將保持不變。

最后,我們使用自適應(yīng)閾值的結(jié)果作為掩碼。然后,根據(jù)蒙版的值合并細節(jié)增強的結(jié)果,以創(chuàng)建具有清晰邊緣的清晰效果。

以下是“細節(jié)增強”過濾器的示例結(jié)果。

細節(jié)增強過濾器實現(xiàn)示例

雙邊過濾器

使用雙邊濾鏡的一大優(yōu)勢是,我們可以在保留邊緣的同時使圖像和顏色平滑。以下是通過雙邊過濾將您的圖像轉(zhuǎn)換為卡通圖像的完整代碼。

#convert the image into grayscale image
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#Blur the grayscale image with median blur
gray_blur = cv2.medianBlur(gray, 3) 

#Apply adaptive thresholding to detect edges
edges = cv2.adaptiveThreshold(gray_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9) 

#Sharpen the image
color = cv2.detailEnhance(img, sigma_s=5, sigma_r=0.5)

#Merge the colors of same images using "edges" as a mask
cartoon = cv2.bitwise_and(color, color, mask=edges)

如果仔細看,所有步驟都與“細節(jié)增強”過濾器中的步驟相似,但是這次不是使用detailEnhance() 函數(shù),而是使用openCV中的bilateralFilter()函數(shù)。

調(diào)用此函數(shù)時需要傳遞的參數(shù)與detailEnhance()相同,只多一個附加參數(shù),即內(nèi)核大小d。首先,我們指定圖像源,然后是d,sigma_s和sigma_r值控制平滑效果,并保持邊緣。

以下是使用雙邊過濾器的結(jié)果示例。

雙邊過濾器實施示例

鉛筆邊緣濾波器

鉛筆邊緣濾鏡可創(chuàng)建僅包含重要邊緣和白色背景的新圖像。要應(yīng)用此濾波器,下面是完整的代碼。

#Convert the image into grayscale image
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#Blur the grayscale image using median blur
gray = cv2.medianBlur(gray, 25) 

#Detect edges with Laplacian
edges = cv2.Laplacian(gray, -1, ksize=3)

#Invert the edges
edges_inv = 255-edges

#Create a pencil edge sketch
dummy, cartoon = cv2.threshold(edges_inv, 150, 255, cv2.THRESH_BINARY)

前兩個步驟與其他過濾器相同。首先,我們將圖像轉(zhuǎn)換為灰度圖像。接下來,我們使用大小為25的內(nèi)核對圖像進行模糊處理。

接下來,我們應(yīng)用拉普拉斯濾波器來檢測邊緣。根據(jù)內(nèi)核的大小,拉普拉斯濾波器中的值可以不同。

Laplacian濾波器的工作是,將通過對象內(nèi)部的灰度級和圖像背景強度來突出對象的邊緣。以下是拉普拉斯濾波器應(yīng)用結(jié)果。

左:拉普拉斯濾波器應(yīng)用之前—右:拉普拉斯濾波器應(yīng)用之后

接下來,我們將Laplacian濾波器的結(jié)果求反。最后,通過應(yīng)用openCV中的threshold()函數(shù),根據(jù)指定的閾值將灰度圖像轉(zhuǎn)換為全黑或全白。

以下是“鉛筆邊緣”過濾器的結(jié)果示例。

Pencil Edges濾鏡實現(xiàn)示例

使用Streamlit構(gòu)建圖像卡通化Web應(yīng)用程序

在創(chuàng)建了圖像卡通化濾波器的代碼之后,現(xiàn)在就可以創(chuàng)建圖像卡通化Web應(yīng)用程序了。

第一步,需要將創(chuàng)建圖像卡通化濾波器的所有代碼放入一個函數(shù)中,以便于訪問。到目前為止,我們已經(jīng)對每個參數(shù)值進行了硬編碼,例如內(nèi)核的大小等等。

現(xiàn)在,我們可以讓用戶使用滑塊根據(jù)自己的喜好指定一個值,而不是對每個參數(shù)值進行硬編碼。為此,我們可以使用Streamlit中的streamlit.slider()函數(shù)。下面是其實現(xiàn)的示例。

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
scale_val = st.slider('Tune the brightness of your sketch (the higher the value, the brighter your sketch)', 0.0, 300.0, 250.0)
kernel = st.slider('Tune the boldness of the edges of your sketch (the higher the value, the bolder the edges)', 1, 99, 25, step=2)
gray_blur = cv2.GaussianBlur(gray, (kernel, kernel), 0)
cartoon = cv2.divide(gray, gray_blur, scale= scale_val)

使用此滑塊,可以創(chuàng)建一個交互式圖像卡通化Web應(yīng)用程序,就像Adobe Lightroom一樣。每次調(diào)整內(nèi)核的值和其他參數(shù)時,圖像卡通化的結(jié)果都會實時更改和更新。

我們可以將其應(yīng)用到streamlit.slider()上,創(chuàng)建的每個圖像卡通化濾波器,以替換硬編碼的參數(shù)值。

接下來,我們需要添加一個小插件,以便用戶可以上傳自己想要轉(zhuǎn)換為卡通的圖像。為此,我們可以使用Streamlit中的streamlit.file_uploader()函數(shù)。要添加某些文本到Web應(yīng)用程序中,我們可以使用Streamlit 中的streamlit.text()或streamlit.write()。

用戶上傳圖像后,現(xiàn)在我們需要顯示圖像,使用圖像卡通化濾波器之一編輯圖像,并顯示卡通化圖像,以便用戶知道他們是否要進一步調(diào)整滑塊。要顯示圖像,我們可以使用Streamlit中的streamlit.image()函數(shù)。

以下是在不到100行代碼的情況下如何構(gòu)建圖像卡通化Web應(yīng)用程序的實現(xiàn)。

import cv2
import streamlit as st
import numpy as np 
from PIL import Image


def cartoonization (img, cartoon):

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 

    if cartoon == "Pencil Sketch":
        
        value = st.sidebar.slider('Tune the brightness of your sketch (the higher the value, the brighter your sketch)', 0.0, 300.0, 250.0)
        kernel = st.sidebar.slider('Tune the boldness of the edges of your sketch (the higher the value, the bolder the edges)', 1, 99, 25, step=2)


        gray_blur = cv2.GaussianBlur(gray, (kernel, kernel), 0)

        cartoon = cv2.divide(gray, gray_blur, scale=value)

    if cartoon == "Detail Enhancement":
        
       
        smooth = st.sidebar.slider('Tune the smoothness level of the image (the higher the value, the smoother the image)', 3, 99, 5, step=2)
        kernel = st.sidebar.slider('Tune the sharpness of the image (the lower the value, the sharper it is)', 1, 21, 3, step =2)
        edge_preserve = st.sidebar.slider('Tune the color averaging effects (low: only similar colors will be smoothed, high: dissimilar color will be smoothed)', 0.0, 1.0, 0.5)
        
        gray = cv2.medianBlur(gray, kernel) 
        edges = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, 
                     cv2.THRESH_BINARY, 9, 9) 
    
        color = cv2.detailEnhance(img, sigma_s=smooth, sigma_r=edge_preserve)
        cartoon = cv2.bitwise_and(color, color, mask=edges) 

    if cartoon == "Pencil Edges":
    
        kernel = st.sidebar.slider('Tune the sharpness of the sketch (the lower the value, the sharper it is)', 1, 99, 25, step=2)
        laplacian_filter = st.sidebar.slider('Tune the edge detection power (the higher the value, the more powerful it is)', 3, 9, 3, step =2)
        noise_reduction = st.sidebar.slider('Tune the noise effects of your sketch (the higher the value, the noisier it is)', 10, 255, 150)
        
        gray = cv2.medianBlur(gray, kernel) 
        edges = cv2.Laplacian(gray, -1, ksize=laplacian_filter)

        
        edges_inv = 255-edges
    
        dummy, cartoon = cv2.threshold(edges_inv, noise_reduction, 255, cv2.THRESH_BINARY)
        

    if cartoon == "Bilateral Filter":
        
        
       
        smooth = st.sidebar.slider('Tune the smoothness level of the image (the higher the value, the smoother the image)', 3, 99, 5, step=2)
        kernel = st.sidebar.slider('Tune the sharpness of the image (the lower the value, the sharper it is)', 1, 21, 3, step =2)
        edge_preserve = st.sidebar.slider('Tune the color averaging effects (low: only similar colors will be smoothed, high: dissimilar color will be smoothed)', 1, 100, 50)
       
        gray = cv2.medianBlur(gray, kernel) 
        edges = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, 
                     cv2.THRESH_BINARY, 9, 9)
    
        color = cv2.bilateralFilter(img, smooth, edge_preserve, smooth) 
        cartoon = cv2.bitwise_and(color, color, mask=edges) 

    return cartoon

###############################################################################
    
st.write("""
          # Cartoonize Your Image!

          """
          )

st.write("This is an app to turn your photos into cartoon")

file = st.sidebar.file_uploader("Please upload an image file", type=["jpg", "png"])

if file is None:
    st.text("You haven't uploaded an image file")
else:
    image = Image.open(file)
    img = np.array(image)
    
    option = st.sidebar.selectbox(
    'Which cartoon filters would you like to apply?',
    ('Pencil Sketch', 'Detail Enhancement', 'Pencil Edges', 'Bilateral Filter'))
    
    st.text("Your original image")
    st.image(image, use_column_width=True)
    
    st.text("Your cartoonized image")
    cartoon = cartoonization(img, option)
    
    st.image(cartoon, use_column_width=True)

現(xiàn)在,可以打開提示符,然后轉(zhuǎn)到包含上面代碼的Python文件的工作目錄。接下來,您需要使用以下命令運行代碼。

streamlit run your_app_name.py

最后,您可以在本地計算機上使用圖像卡通化Web應(yīng)用程序!以下是該網(wǎng)絡(luò)應(yīng)用程序的示例。

該網(wǎng)絡(luò)應(yīng)用程序示例

部署Web應(yīng)用

本節(jié)是可選的,但是如果小伙伴需要部署Web應(yīng)用程序以便其他人也可以訪問您的Web應(yīng)用程序,則可以使用Heroku部署Web應(yīng)用程序。

要將Web應(yīng)用程序部署到Heroku,首先要免費創(chuàng)建一個Heroku帳戶,然后下載Heroku CLI。

接下來需要在與Python文件相同的目錄中創(chuàng)建四個其他文件,它們是:

requirements.txt:這是文本文件,用于告訴Heroku構(gòu)建Web應(yīng)用程序需要哪些依賴項。因為在我們的web應(yīng)用程序,我們使用四種不同的庫:opencv,numpy,Pillow,和streamlit,那么我們就可以寫所有這些庫及其版本為requirements.txt的

opencv-python==4.3.0.36
streamlit==0.63.0
Pillow==7.0.0
numpy==1.18.1

setup.sh:這是用于在Heroku上設(shè)置配置的文件。為此setup.sh文件編寫以下內(nèi)容。

mkdir -p ~/.streamlit/                       
echo "\                       
[server]\n\                       
headless = true\n\                       
port = $PORT\n\                       
enableCORS = false\n\                       
\n\                       
" > ~/.streamlit/config.toml

Procfile:這是告訴Heroku哪些文件以及應(yīng)如何執(zhí)行文件的文件。為Procfile編寫以下內(nèi)容。

web: sh setup.sh && streamlit run cartoon_app.py

Aptfile:這是Heroku 構(gòu)建包的文件,以使OpenCV能夠在Heroku中運行。為Aptfile編寫以下內(nèi)容。

libsm6                       
libxrender1                       
libfontconfig1                       
libice6

接下來,打開命令提示符,然后轉(zhuǎn)到Python文件和這四個其他文件的工作目錄。在其中鍵入heroku login命令,以便您登錄到Heroku帳戶。

現(xiàn)在,您可以通過鍵入來創(chuàng)建新應(yīng)用heroku create your-app-name。為確保您位于新創(chuàng)建的應(yīng)用程序內(nèi)部,請鍵入以下內(nèi)容:

heroku git:remote -a your-app-name

接下來,我們需要在新創(chuàng)建的應(yīng)用程序中添加一個buildpack,以使OpenCV能夠在Heroku上運行。要添加必要的buildpack,請在Heroku CLI上鍵入以下內(nèi)容。

heroku create --buildpack https://github.com/heroku/heroku-buildpack-apt.git

現(xiàn)在設(shè)置好了。接下來,您需要通過打字來初始化一個空的git git init其次是git add .,git commit和git push heroku master命令。

git init
git add .
git commit -m "Add your messages"
git push heroku master

之后,部署過程就開始了,并且可能需要一些時間來等待此部署過程。最后,Heroku將生成新部署的Web應(yīng)用程序的URL。

就是這樣!現(xiàn)在,我們已經(jīng)構(gòu)建了自己的圖像卡通化Web應(yīng)用程序,該應(yīng)用程序模仿了Adobe Lightroom的功能。


數(shù)據(jù)分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個參數(shù)驗證碼對象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺檢測極驗服務(wù)器是否宕機 new_captcha: data.new_captcha, // 用于宕機時表示是新驗證碼的宕機 product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說明請參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計時完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }