原文:Hands-On Image Processing with Python
協(xié)議:CC BY-NC-SA 4.0
譯者:飛龍
本文來自【ApacheCN 計(jì)算機(jī)視覺 譯文集】,采用譯后編輯(MTPE)流程來盡可能提升效率。
當(dāng)別人說你沒有底線的時(shí)候,你最好真的沒有;當(dāng)別人說你做過某些事的時(shí)候,你也最好真的做過。
十一、深入學(xué)習(xí)圖像處理——目標(biāo)檢測等
在本章中,我們將繼續(xù)討論圖像處理與深度學(xué)習(xí)的最新進(jìn)展。我們將特別處理一些問題,并將嘗試使用深度 CNN 的深度學(xué)習(xí)來解決這些問題
我們將研究目標(biāo)檢測問題,了解涉及的基本概念,然后研究如何編寫代碼來解決目標(biāo)建議和問題,您只需查看 Keras 中的(YOLO)v2 預(yù)訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)。您將獲得有助于培訓(xùn) YOLO net 的資源。
準(zhǔn)備好學(xué)習(xí)遷移學(xué)習(xí),并使用DeepLab
庫解決深度分段問題。您將學(xué)習(xí)指定哪個(gè)。。。
介紹 YOLO v2
YOLO 是一種非常流行且完全傳統(tǒng)的用于檢測圖像的算法。與其他算法相比,該算法具有非常高的準(zhǔn)確率,并且能夠?qū)崟r(shí)運(yùn)行。顧名思義,這種算法只會在圖像上查看一次。這意味著該算法只需要一個(gè)正向傳播過程就可以做出準(zhǔn)確的預(yù)測
在本節(jié)中,我們將使用完全卷積網(wǎng)絡(luò)(FCN)深度學(xué)習(xí)模型檢測圖像中的對象。給定包含一些對象(例如動物、汽車等)的圖像,目標(biāo)是使用預(yù)先訓(xùn)練的 YOLO模型和邊界框檢測這些圖像中的對象。
*許多想法來自于兩份原始的 YOLO 論文,可在上找到 https://arxiv.org/abs/1506.02640 和https://arxiv.org/abs/1612.08242 。但在深入研究 YOLO 模型之前,讓我們先了解一些先決條件的基本概念。
圖像分類定位與目標(biāo)檢測
讓我們首先了解有關(guān)分類、定位、檢測*、*和目標(biāo)檢測問題的概念,如何將它們轉(zhuǎn)化為有監(jiān)督的機(jī)器學(xué)習(xí)問題,然后,如何使用深度卷積神經(jīng)網(wǎng)絡(luò)解決它們。
請參閱下圖:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-vCIrOJnc-1681961504726)(img/fd0ebf8c-2f06-475a-b6ef-daa014cd83ca.png)]
我們可以推斷如下:
- 在圖像分類問題中,通常圖像中有一個(gè)(大的)中心對象,我們必須通過為圖像指定正確的標(biāo)簽來識別該對象
- 圖像分類與定位的目的是找到一個(gè)物體在圖像中的位置。。。
利用 CNNs 提出和檢測目標(biāo)
從定位到檢測,我們可以分兩步進(jìn)行,如下面的屏幕截圖所示:首先使用緊密裁剪的小圖像訓(xùn)練卷積神經(jīng)網(wǎng)絡(luò)進(jìn)行圖像分類,然后使用不同窗口大小(從小到大)的滑動窗口使用 convnet 對該窗口內(nèi)的測試圖像進(jìn)行分類,并在整個(gè)圖像中按順序運(yùn)行窗口,但計(jì)算速度太慢。
然而,如下圖所示,通過使用 1×1 濾波器替換完全連接的層,滑動窗口的卷積實(shí)現(xiàn)使得能夠在所有可能的滑動窗口內(nèi)并行地同時(shí)對圖像子集進(jìn)行分類,從而使其在計(jì)算上更加高效。
使用 YOLO v2
卷積滑動窗口雖然計(jì)算效率更高,但仍然存在精確檢測邊界框的問題,因?yàn)榭蚺c滑動窗口不對齊,并且對象形狀也往往不同。YOLO 算法通過將訓(xùn)練圖像劃分為網(wǎng)格并將對象指定給網(wǎng)格(當(dāng)且僅當(dāng)對象的中心位于網(wǎng)格內(nèi)時(shí)),克服了這一限制。這樣,可以將訓(xùn)練圖像中的每個(gè)對象精確地指定給一個(gè)柵格,然后通過相對于柵格的坐標(biāo)表示相應(yīng)的邊界框
在測試圖像中,多個(gè)相鄰柵格可能認(rèn)為某個(gè)對象實(shí)際上屬于它們。為了解決這個(gè)問題,交叉口。。。
使用預(yù)先訓(xùn)練的 YOLO 模型進(jìn)行目標(biāo)檢測
以下是您必須遵循的步驟,以便能夠使用經(jīng)過預(yù)培訓(xùn)的模型:
-
克隆此存儲庫:轉(zhuǎn)到https://github.com/allanzelener/YAD2K/ ,右鍵點(diǎn)擊克隆或下載,選擇下載
ZIP
的路徑。然后將壓縮文件解壓縮到*YAD2K-master*
文件夾。 -
從下載重量和 cfg 文件 https://pjreddie.com/darknet/yolo/ 點(diǎn)擊頁面上紅色框標(biāo)記的黃色鏈接:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-HaryVHGy-1681961504728)(img/155b4477-5e1b-44b2-930e-3daa474b9d7d.png)]
-
將下載的
yolov2.cfg
和yolov2.weights
文件保存在YAD2K-master
文件夾中。 -
進(jìn)入
YAD2K-master
文件夾,打開命令提示符(需要安裝 Python3 并在 path 中),然后運(yùn)行以下命令:
python yad2k.py yolov2.cfg yolov2.weights yolo/yolo.h5
如果執(zhí)行成功,將在YAD2K-master/model_data
文件夾*、中創(chuàng)建兩個(gè)文件,即yolo.h5
和yolo.anchors
。*
-
現(xiàn)在轉(zhuǎn)到要從中運(yùn)行代碼的文件夾。在此處創(chuàng)建一個(gè)名為
yolo
的文件夾,并將YAD2K-master/model_data
文件夾中的四個(gè)文件(coco_classes
、pascal_classes
、yolo.h5
、yolo.anchors
復(fù)制到您創(chuàng)建的yolo
文件夾中。 -
將
yad2k
文件夾從YAD2K-master
文件夾復(fù)制到當(dāng)前路徑?,F(xiàn)在,您當(dāng)前的路徑應(yīng)該有兩個(gè)文件夾yad2k
和yolo
-
在當(dāng)前路徑中創(chuàng)建一個(gè)名為
images
的新文件夾,并將輸入圖像放在此處。 -
在當(dāng)前路徑中創(chuàng)建另一個(gè)名為
output
的新空文件夾。YOLO 模型將在此處保存輸出圖像(檢測到對象)。 -
在當(dāng)前路徑中創(chuàng)建一個(gè)
.py
腳本,復(fù)制粘貼以下代碼并運(yùn)行(或從當(dāng)前路徑的 Jupyter 筆記本單元運(yùn)行) -
在運(yùn)行代碼之前,請仔細(xì)檢查文件夾結(jié)構(gòu)是否完全如以下屏幕截圖所示,以及是否存在所需的文件:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-kkAgpk0v-1681961504728)(img/8f5fbc5f-463e-4bd5-8be3-22d5e5a450c7.png)]
讓我們首先加載所有必需的庫,如此代碼塊所示:
# for jupyter notebook uncomment the following line of code
#% matplotlib inline
import os
import matplotlib.pylab as pylab
import scipy.io
import scipy.misc
import numpy as np
from PIL import Image
from keras import backend as K
from keras.models import load_model
# The following functions from the yad2k library will be used
# Note: it assumed that you have the yad2k folder in your current path, otherwise it will not work!
from yad2k.models.keras_yolo import yolo_head, yolo_eval
import colorsys
import imghdr
import random
from PIL import Image, ImageDraw, ImageFont
現(xiàn)在實(shí)現(xiàn)幾個(gè)函數(shù)來讀取classes
和anchor
文件,生成方框的顏色,并縮放 YOLO 預(yù)測的方框:
def read_classes(classes_path):
with open(classes_path) as f:
class_names = f.readlines()
class_names = [c.strip() for c in class_names]
return class_names
def read_anchors(anchors_path):
with open(anchors_path) as f:
anchors = f.readline()
anchors = [float(x) for x in anchors.split(',')]
anchors = np.array(anchors).reshape(-1, 2)
return anchors
def generate_colors(class_names):
hsv_tuples = [(x / len(class_names), 1., 1.) for x in range(len(class_names))]
colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples))
colors = list(map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)), colors))
random.seed(10101) # Fixed seed for consistent colors across runs.
random.shuffle(colors) # Shuffle colors to decorrelate adjacent classes.
random.seed(None) # Reset seed to default.
return colors
def scale_boxes(boxes, image_shape):
""" scales the predicted boxes in order to be drawable on the image"""
height = image_shape[0]
width = image_shape[1]
image_dims = K.stack([height, width, height, width])
image_dims = K.reshape(image_dims, [1, 4])
boxes = boxes * image_dims
return boxes
在下面的代碼片段中,我們將實(shí)現(xiàn)兩個(gè)函數(shù)來預(yù)處理圖像,并繪制從 YOLO 獲得的框來檢測圖像中存在的對象:
def preprocess_image(img_path, model_image_size):
image_type = imghdr.what(img_path)
image = Image.open(img_path)
resized_image = image.resize(tuple(reversed(model_image_size)), Image.BICUBIC)
image_data = np.array(resized_image, dtype='float32')
image_data /= 255.
image_data = np.expand_dims(image_data, 0) # Add batch dimension.
return image, image_data
def draw_boxes(image, out_scores, out_boxes, out_classes, class_names, colors):
font = ImageFont.truetype(font='font/FiraMono-Medium.otf',size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32'))
thickness = (image.size[0] + image.size[1]) // 300
for i, c in reversed(list(enumerate(out_classes))):
predicted_class = class_names[c]
box = out_boxes[i]
score = out_scores[i]
label = '{} {:.2f}'.format(predicted_class, score)
draw = ImageDraw.Draw(image)
label_size = draw.textsize(label, font)
top, left, bottom, right = box
top = max(0, np.floor(top + 0.5).astype('int32'))
left = max(0, np.floor(left + 0.5).astype('int32'))
bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32'))
right = min(image.size[0], np.floor(right + 0.5).astype('int32'))
print(label, (left, top), (right, bottom))
if top - label_size[1] >= 0:
text_origin = np.array([left, top - label_size[1]])
else:
text_origin = np.array([left, top + 1])
# My kingdom for a good redistributable image drawing library.
for i in range(thickness):
draw.rectangle([left + i, top + i, right - i, bottom - i], outline=colors[c])
draw.rectangle([tuple(text_origin), tuple(text_origin + label_size)], fill=colors[c])
draw.text(text_origin, label, fill=(0, 0, 0), font=font)
del draw
現(xiàn)在,讓我們使用函數(shù)加載輸入圖像、類文件和錨點(diǎn),然后加載 YOLO 預(yù)訓(xùn)練模型,并使用下一個(gè)代碼塊打印模型摘要:
# provide the name of the image that you saved in the images folder to be fed through the network
input_image_name = "giraffe_zebra.jpg"
input_image = Image.open("images/" + input_image_name)
width, height = input_image.size
width = np.array(width, dtype=float)
height = np.array(height, dtype=float)
image_shape = (height, width)
#Loading the classes and the anchor boxes that are copied to the yolo folder
class_names = read_classes("yolo/coco_classes.txt")
anchors = read_anchors("yolo/yolo_anchors.txt")
#Load the pretrained model
yolo_model = load_model("yolo/yolo.h5")
#Print the summery of the model
yolo_model.summary()
#__________________________________________________________________________________________________
#Layer (type) Output Shape Param # Connected to
#==================================================================================================
#input_1 (InputLayer) (None, 608, 608, 3) 0
#__________________________________________________________________________________________________
#conv2d_1 (Conv2D) (None, 608, 608, 32) 864 input_1[0][0]
#__________________________________________________________________________________________________
#batch_normalization_1 (BatchNor (None, 608, 608, 32) 128 conv2d_1[0][0]
#__________________________________________________________________________________________________
#leaky_re_lu_1 (LeakyReLU) (None, 608, 608, 32) 0 batch_normalization_1[0][0]
#__________________________________________________________________________________________________
#max_pooling2d_1 (MaxPooling2D) (None, 304, 304, 32) 0 leaky_re_lu_1[0][0]
#__________________________________________________________________________________________________
#conv2d_2 (Conv2D) (None, 304, 304, 64) 18432 max_pooling2d_1[0][0]
#__________________________________________________________________________________________________
#batch_normalization_2 (BatchNor (None, 304, 304, 64) 256 conv2d_2[0][0]
#__________________________________________________________________________________________________
#leaky_re_lu_2 (LeakyReLU) (None, 304, 304, 64) 0 batch_normalization_2[0][0]
#__________________________________________________________________________________________________
#max_pooling2d_2 (MaxPooling2D) (None, 152, 152, 64) 0 leaky_re_lu_2[0][0]
#__________________________________________________________________________________________________
#... ... ...
#__________________________________________________________________________________________________
#concatenate_1 (Concatenate) (None, 19, 19, 1280) 0 space_to_depth_x2[0][0]
# leaky_re_lu_20[0][0]
#________________________________________________________________________________________________
#batch_normalization_22 (BatchNo (None, 19, 19, 1024) 4096 conv2d_22[0][0]
#__________________________________________________________________________________________________
#leaky_re_lu_22 (LeakyReLU) (None, 19, 19, 1024) 0 batch_normalization_22[0][0]
#__________________________________________________________________________________________________
#conv2d_23 (Conv2D) (None, 19, 19, 425) 435625 leaky_re_lu_22[0][0]
#==================================================================================================
#Total params: 50,983,561
#Trainable params: 50,962,889
#Non-trainable params: 20,672
__________________________________________________________________________________________________
最后,下一個(gè)代碼塊從 YOLO 預(yù)測輸出中提取邊界框,并在找到的具有正確標(biāo)簽、分?jǐn)?shù)和顏色的對象周圍繪制邊界框:
# convert final layer features to bounding box parameters
yolo_outputs = yolo_head(yolo_model.output, anchors, len(class_names))
#Now yolo_eval function selects the best boxes using filtering and non-max suppression techniques.
# If you want to dive in more to see how this works, refer keras_yolo.py file in yad2k/models
boxes, scores, classes = yolo_eval(yolo_outputs, image_shape)
# Initiate a session
sess = K.get_session()
#Preprocess the input image before feeding into the convolutional network
image, image_data = preprocess_image("images/" + input_image_name, model_image_size = (608, 608))
#Run the session
out_scores, out_boxes, out_classes = sess.run([scores, boxes, classes],feed_dict={yolo_model.input:image_data,K.learning_phase(): 0})
#Print the results
print('Found {} boxes for {}'.format(len(out_boxes), input_image_name))
#Found 5 boxes for giraffe_zebra.jpg
#zebra 0.83 (16, 325) (126, 477)
#giraffe 0.89 (56, 175) (272, 457)
#zebra 0.91 (370, 326) (583, 472)
#giraffe 0.94 (388, 119) (554, 415)
#giraffe 0.95 (205, 111) (388, 463)
#Produce the colors for the bounding boxes
colors = generate_colors(class_names)
#Draw the bounding boxes
draw_boxes(image, out_scores, out_boxes, out_classes, class_names, colors)
#Apply the predicted bounding boxes to the image and save it
image.save(os.path.join("output", input_image_name), quality=90)
output_image = scipy.misc.imread(os.path.join("output", input_image_name))
pylab.imshow(output_image)
pylab.axis('off')
pylab.show()
下圖顯示了通過運(yùn)行上述代碼獲得的輸出。用 YOLO 模型預(yù)測了標(biāo)有邊框的對象,長頸鹿和斑馬。每個(gè)邊界框上方的數(shù)字是來自 YOLO 模型的概率分?jǐn)?shù)*:*
*[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-vt41prR8-1681961504729)(img/ca086560-bc06-490e-aa9f-73e717374685.png)]
同樣,讓我們嘗試使用以下照片作為輸入:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-nol2iVi8-1681961504729)(img/39a78848-1924-4201-9043-7a97c2f09937.png)]
我們將檢測以下對象(汽車、公共汽車、人、傘):
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-VPrHC1sb-1681961504729)(img/fa4d063f-6d25-4548-9627-3d0677382d95.png)]
基于 deeplabv3 的深度語義切分+
在本節(jié)中,我們將討論如何使用深度學(xué)習(xí) FCN 對圖像執(zhí)行語義分割。在深入了解更多細(xì)節(jié)之前,讓我們先了解一下基本概念。
語義分割
語義分割是指在像素級理解圖像;也就是說,當(dāng)我們想要為圖像中的每個(gè)像素分配一個(gè)對象類*(一個(gè)語義標(biāo)簽)*時(shí)。這是從粗略推理到精細(xì)推理過程中的一個(gè)自然步驟。它通過密集的預(yù)測來實(shí)現(xiàn)細(xì)粒度的推斷,為每個(gè)像素推斷標(biāo)簽,以便每個(gè)像素都用其封閉對象或區(qū)域的類別來標(biāo)記。
深海實(shí)驗(yàn)室 V3+
DeepLab 提出了一種用于控制信號抽取和學(xué)習(xí)多尺度上下文特征的體系結(jié)構(gòu)。DeepLab 使用在 ImageNet 數(shù)據(jù)集上預(yù)先訓(xùn)練的 ResNet-50 模型作為其主要特征提取器網(wǎng)絡(luò)。然而,它為多尺度特征學(xué)習(xí)提出了一個(gè)新的殘差塊,如下圖所示。最后一個(gè) ResNet 塊使用 atrus 卷積代替常規(guī)卷積。此外,每個(gè)卷積(在這個(gè)新塊中)使用不同的膨脹率來捕獲多尺度上下文。此外,在這個(gè)新塊的頂部,它使用萎縮的空間金字塔池*(ASPP。ASPP 使用不同速率的擴(kuò)張卷積來嘗試對任意尺度的區(qū)域進(jìn)行分類。。。*
*# DeepLab v3 體系結(jié)構(gòu)
圖中顯示了具有阿托斯卷積的并行模塊:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-yBCfhMsM-1681961504730)(img/1aa5b349-5a66-456a-8afa-080a7b07a525.png)]
使用 DeepLab-v3+,DeepLab-v3 模型通過添加一個(gè)簡單但有效的解碼器模塊來擴(kuò)展,以細(xì)化分割結(jié)果,特別是沿著對象邊界。將深度可分離卷積應(yīng)用于 Atrus 空間金字塔池和解碼器模塊,從而形成更快、更強(qiáng)的用于語義分割的編解碼網(wǎng)絡(luò)。架構(gòu)如下圖所示:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-oX6vskx5-1681961504730)(img/d929fc98-db73-4c77-9d60-4b4582fa03e2.png)]
使用 DeepLab V3+模型進(jìn)行語義分段必須遵循的步驟
以下是使用模型分割圖像必須遵循的步驟:
- 首先,從克隆或下載存儲庫 https://github.com/bonlime/keras-deeplab-v3-plus 。
- 解壓縮下載到
keras-deeplab-v3-plus-master
文件夾的ZIP
文件。 - 導(dǎo)航到
keras-deeplab-v3-plus-master
文件夾*;*以下代碼需要從目錄內(nèi)部運(yùn)行。
在運(yùn)行以下代碼塊之前,請創(chuàng)建一個(gè)輸入文件夾和一個(gè)空輸出文件夾。將要分割的圖像保存在輸入文件夾中。以下代碼塊顯示如何使用 Python 中的 Deeplabv3+進(jìn)行語義分割:
#os.chdir('keras-deeplab-v3-plus-master') # go ...
遷移學(xué)習(xí)——它是什么,何時(shí)使用
遷移學(xué)習(xí)是一種深度學(xué)習(xí)策略,通過將從解決一個(gè)問題中獲得的知識應(yīng)用于一個(gè)不同但相關(guān)的問題,從而重用這些知識。例如,假設(shè)我們有三種類型的花,即玫瑰、向日葵和郁金香。我們可以使用標(biāo)準(zhǔn)的預(yù)訓(xùn)練模型,如 VGG16/19、ResNet50 或 InceptionV3 模型(在 ImageNet 上預(yù)訓(xùn)練,有 1000 個(gè)輸出類,可在中找到)https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a 對花卉圖像進(jìn)行分類,但是我們的模型無法正確識別它們,因?yàn)檫@些花的類別不是由模型學(xué)習(xí)的。換句話說,它們是模型不知道的類。
下圖顯示了預(yù)先訓(xùn)練過的 VGG16 模型如何錯(cuò)誤地對花卉圖像進(jìn)行分類(代碼留給讀者作為練習(xí)):
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-10uCL0I3-1681961504731)(img/c5c28219-be6f-483c-8085-79940f9d3376.png)]
基于 Keras 的遷移學(xué)習(xí)
對許多綜合圖像分類問題進(jìn)行預(yù)訓(xùn)練模型的訓(xùn)練。卷積層充當(dāng)特征提取器,完全連接的*(FC層充當(dāng)分類器*、,如下圖所示,在使用 conv 網(wǎng)絡(luò)進(jìn)行貓狗圖像分類的情況下:
*[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-0Sa3IQbo-1681961504731)(img/34041fa9-e175-44cf-b818-e5c96473bd39.png)]
由于標(biāo)準(zhǔn)模型(如 VGG-16/19)相當(dāng)大,并且在許多圖像上進(jìn)行了訓(xùn)練,因此它們能夠?yàn)椴煌念悓W(xué)習(xí)許多不同的特征。我們可以簡單地將卷積層重用為特征提取器,以學(xué)習(xí)低級和高級圖像特征,并只訓(xùn)練 FC 層權(quán)重。。。
使用預(yù)先訓(xùn)練的 torch 模型進(jìn)行 cv2 神經(jīng)風(fēng)格轉(zhuǎn)換
在本節(jié)中,我們將討論如何使用深度學(xué)習(xí)來實(shí)現(xiàn)神經(jīng)風(fēng)格轉(zhuǎn)移*(NST。你會驚訝于我們可以用它生成的藝術(shù)圖像。在深入研究深度學(xué)習(xí)模型的更多細(xì)節(jié)之前,讓我們先討論一些基本概念。*
*# 理解 NST 算法
2015 年,Gatys等人在一篇關(guān)于該主題的論文中首次揭示了 NST 算法。這個(gè)技巧包含了很多樂趣!我相信您會喜歡實(shí)現(xiàn)這一點(diǎn),并會對您將創(chuàng)建的輸出感到驚訝。
它嘗試根據(jù)以下參數(shù)合并兩個(gè)圖像:
- 內(nèi)容圖像(C)
- 樣式圖像
NST 算法使用這些參數(shù)創(chuàng)建第三個(gè)生成的圖像(G)。生成的圖像 G 將圖像 C 的內(nèi)容與圖像 S 的樣式相結(jié)合。
**下面是我們實(shí)際將要做的一個(gè)例子:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-fckcmKcI-1681961504732)(img/2f698b69-5259-4f48-9266-aa3ad9cfb284.png)]
驚訝我希望你喜歡蒙娜麗莎的濾鏡。。。
利用遷移學(xué)習(xí)實(shí)現(xiàn) NST
與深度學(xué)習(xí)中的大多數(shù)算法不同,NST 優(yōu)化了代價(jià)函數(shù)以獲得像素值。NST 實(shí)現(xiàn)通常使用預(yù)先訓(xùn)練的卷積網(wǎng)絡(luò)。
這只是一個(gè)簡單的想法,即使用一個(gè)在一項(xiàng)任務(wù)上訓(xùn)練過的網(wǎng)絡(luò),并將其用于一項(xiàng)全新的任務(wù)。
以下是三個(gè)分量損耗函數(shù):
- 內(nèi)容丟失
- 樣式丟失
- 總變化損失
每個(gè)分量單獨(dú)計(jì)算,然后組合成一個(gè)元損失函數(shù)。通過最小化元損失函數(shù),我們將依次聯(lián)合優(yōu)化內(nèi)容、樣式和總變化損失。
確保 NST 內(nèi)容丟失
我們現(xiàn)在完全知道,卷積網(wǎng)絡(luò)的頂層檢測圖像的低級特征,而深層檢測圖像的高級特征。但是中間層呢?他們持有內(nèi)容。由于我們希望生成的圖像 G 具有與輸入類似的內(nèi)容,即我們的內(nèi)容圖像 C,因此我們將在它們之間使用一些激活層來表示圖像的內(nèi)容
如果我們自己選擇網(wǎng)絡(luò)的中間層,我們將獲得更視覺愉悅的輸出,這意味著它既不太淺,也不太深。
內(nèi)容丟失或特征重構(gòu)丟失(我們希望最小化)可以表示為:
這里,nW、nH和 nC是……的寬度、高度和數(shù)量。。。
計(jì)算樣式成本
我們首先需要通過從展開的過濾器矩陣計(jì)算點(diǎn)積矩陣來計(jì)算樣式,或 Gram 矩陣。
隱藏層a的樣式丟失可以表示為:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-bnqzl6J5-1681961504732)(img/a8d7ca44-e30c-4b97-9d8d-408c90141777.png)]
我們希望最小化圖像 S 和 G 的 Gram 矩陣之間的距離。整體加權(quán)樣式損失(我們希望最小化)表示為:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-r1KovAjb-1681961504732)(img/1d757fd8-f7d7-40c2-9c6f-364d6f07aff7.png)]
這里,λ表示不同層的權(quán)重。記住以下幾點(diǎn):
- 圖像的樣式可以使用隱藏的層激活的 Gram 矩陣來表示。然而,我們從多個(gè)不同的層中結(jié)合這種表示,得到了更好的結(jié)果。這與內(nèi)容表示不同,內(nèi)容表示通常只使用一個(gè)隱藏層就足夠了。
*** 最小化樣式成本將導(dǎo)致圖像 G 遵循圖像 S 的樣式。**
**# 計(jì)算總損失
最小化樣式和內(nèi)容成本的成本函數(shù)如下所示:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-Pp9VlN0i-1681961504732)(img/74b2407d-2c6e-4b65-892f-75dacfc55ec5.png)]
有時(shí),為了鼓勵(lì)輸出圖像G中的空間平滑度,還向 RHS 凸組合添加了總變化正則化器 TV(G)。
然而,在本節(jié)中,我們將不使用遷移學(xué)習(xí)。如果您感興趣,您可以按照進(jìn)一步閱讀和參考資料部分提供的鏈接進(jìn)行操作。取而代之的是,我們將使用一個(gè)預(yù)先訓(xùn)練好的火炬模型(火炬是另一個(gè)深度學(xué)習(xí)圖書館),具有特定的圖像風(fēng)格,即梵高的星夜畫。
使用 Python 和 OpenCV 進(jìn)行神經(jīng)風(fēng)格轉(zhuǎn)換
我們先從下載經(jīng)過預(yù)培訓(xùn)的火炬模型 https://github.com/DmitryUlyanov/online-neural-doodle/blob/master/pretrained/starry_night.t7 并將其保存在當(dāng)前文件夾中(我們計(jì)劃從中運(yùn)行以下代碼)。在當(dāng)前路徑上創(chuàng)建一個(gè)名為output
的文件夾,保存模型生成的圖像。
下一個(gè)代碼塊演示如何對輸入的內(nèi)容圖像執(zhí)行 NST(帶星夜樣式)。首先,使用cv2.dnn.readNetFromTorch()
功能加載預(yù)先訓(xùn)練好的模型。
接下來,通過從 RGB 通道中減去平均值,使用cv2.dnn.blobFromImage()
函數(shù)從圖像中創(chuàng)建一個(gè) 4 維水滴。最后,執(zhí)行前向傳遞以獲得輸出圖像(即 NST 算法的結(jié)果):
import cv2
import matplotlib.pyplot as pylab
import imutils
import time
model = 'neural-style-transfer/models/eccv16/starry_night.t7' # assumes
the pre-trained torch file is in the current path
print("loading style transfer model...")
net = cv2.dnn.readNetFromTorch(model)
image = cv2.imread('../images/monalisa.jpg') # the content image path
image = imutils.resize(image, width=600)
(h, w) = image.shape[:2]
b, g, r = np.mean(image[...,0]), np.mean(image[...,1]),
np.mean(image[...,2])
# construct a blob from the image, set the input, and then perform a
# forward pass of the network
blob = cv2.dnn.blobFromImage(image, 1.0, (w, h), (b, g, r), swapRB=False, crop=False)
net.setInput(blob)
start = time.time()
output = net.forward()
end = time.time()
# reshape the output tensor, add back in the mean subtraction, and
# then swap the channel ordering
output = output.reshape((3, output.shape[2], output.shape[3]))
output[0] += b
output[1] += g
output[2] += r
#output /= 255.0
output = output.transpose(1, 2, 0)
# show information on how long inference took
print("neural style transfer took {:.4f} seconds".format(end - start))
#pylab.imshow(output / 255.0)
#pylab.show()
# show the images
cv2.imwrite('output/styled.jpg', output)
以下是蒙娜麗莎的輸入內(nèi)容圖像:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-y0cARheC-1681961504733)(img/327d9ad7-2745-4c0a-bee5-28acf98bb034.png)]
以下是輸入式圖像,梵高的《星夜》:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-NXrXp4xF-1681961504733)(img/203ddd5b-1497-474b-9757-770a1c9931ed.png)]
以下是由深度學(xué)習(xí)模型生成的輸出圖像,其中星夜圖像的樣式被傳輸?shù)矫赡塞惿膬?nèi)容輸入圖像上:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-Sg2KckEI-1681961504733)(img/4eb02fb7-d9c9-451f-b840-e0c78e3eae0b.png)]
總結(jié)
在本章中,我們討論了一些高級深度學(xué)習(xí)應(yīng)用程序,以解決一些復(fù)雜的圖像處理問題。我們從圖像分類的基本概念開始,包括定位和目標(biāo)檢測。然后,我們演示了如何使用流行的 YOLO v2 FCN 預(yù)訓(xùn)練模型檢測圖像中的對象并在其周圍繪制框。接下來,我們討論了語義分割的基本概念,然后演示了如何使用 DeepLab v3+(及其體系結(jié)構(gòu)摘要)對圖像執(zhí)行語義分割。然后,我們定義了遷移學(xué)習(xí),并解釋了它在深度學(xué)習(xí)中的作用,以及在 Keras 中使用預(yù)先訓(xùn)練的 VGG16 對花卉進(jìn)行分類的遷移學(xué)習(xí)演示。。。
問題
- 使用預(yù)先訓(xùn)練的快速 RCNN 和 MobileNet 模型進(jìn)行實(shí)時(shí)目標(biāo)檢測。
- 我們使用一個(gè) YOLO v2 預(yù)訓(xùn)練模型來實(shí)現(xiàn)目標(biāo)檢測。嘗試使用 YOLO v3 預(yù)先訓(xùn)練的模型來實(shí)現(xiàn)對象檢測。
- 什么是微調(diào),它與遷移學(xué)習(xí)有何不同?舉例說明。
- 我們只針對遷移學(xué)習(xí)對 VGG16 的 FC 層進(jìn)行了培訓(xùn)。使用 VGG19、Resnet50 和 Inception V3 模型代替 Keras。準(zhǔn)確度提高了嗎?
- 對于使用 Keras 的遷移學(xué)習(xí),我們使用 500 張圖像進(jìn)行訓(xùn)練,50 張圖像用于驗(yàn)證每個(gè)花卉類,非標(biāo)準(zhǔn)的 91:9 訓(xùn)練與驗(yàn)證數(shù)據(jù)集比率。將其更改為標(biāo)準(zhǔn) 80:20 驗(yàn)證它對驗(yàn)證數(shù)據(jù)集中的準(zhǔn)確性有多大影響?
- 請點(diǎn)擊此鏈接https://cs.stanford.edu/people/jcjohns/papers/eccv16/JohnsonECCV16.pdf ,并實(shí)現(xiàn) NST 算法,使用轉(zhuǎn)移學(xué)習(xí)將圖像樣式(星夜除外)轉(zhuǎn)移到輸入內(nèi)容圖像。
進(jìn)一步閱讀
- http://www.deeplearning.ai
- http://www.learnopencv.com
- http://pyimagesearch.com
- https://arxiv.org/abs/1506.02640
- https://arxiv.org/abs/1612.08242
- https://pjreddie.com/darknet/yolo/
- https://arxiv.org/pdf/1506.02640.pdf
- https://sandipanweb.wordpress.com/2018/03/11/autonomous-driving-car-detection-with-yolo-in-python/
- https://arxiv.org/abs/1706.05587
- https://arxiv.org/pdf/1802.02611.pdf
- https://arxiv.org/pdf/1508.06576.pdf
- https://cs.stanford.edu/people/jcjohns/papers/eccv16/JohnsonECCV16.pdf
- https://sandipanweb.wordpress.com/2018/01/02/deep-learning-art-neural-style-transfer-an-implementation-with-tensorflow-in-python/*********
十二、圖像處理中的附加問題
在本章中,我們將討論圖像處理中的幾個(gè)更高級的問題。我們將從接縫雕刻問題開始,并演示兩個(gè)應(yīng)用程序,第一個(gè)是內(nèi)容感知圖像大小調(diào)整,第二個(gè)是從圖像中刪除對象。接下來,我們將討論無縫克隆,可用于將一個(gè)對象從一個(gè)圖像無縫復(fù)制到另一個(gè)圖像。然后,我們將討論一種修復(fù)算法,該算法可用于恢復(fù)圖像中受損的像素。之后,我們將研究圖像處理中的變分方法及其在圖像去噪中的應(yīng)用。接下來,我們將討論圖像絎縫算法及其在紋理合成和圖像傳輸中的應(yīng)用。我們將以一個(gè)復(fù)雜的人臉變形算法結(jié)束我們的討論。
本章涉及的主題如下:
- 縫雕
- 無縫克隆和泊松圖像編輯
- 圖像修復(fù)
- 變分圖像處理
- 圖像絎縫
- 面變形
縫雕
接縫雕刻是一種內(nèi)容感知圖像大小調(diào)整技術(shù),其中圖像的大小在高度(或?qū)挾龋┥蠝p少一個(gè)像素一次。圖像中的垂直接縫是一條從上到下連接的像素路徑,每行一個(gè)像素。水平接縫是一條從左到右連接的像素路徑,每列一個(gè)像素。盡管底層算法簡單而優(yōu)雅,但直到 2007 年才被發(fā)現(xiàn)。
現(xiàn)在它是 Adobe Photoshop 和其他計(jì)算機(jī)圖形應(yīng)用程序的核心功能。與標(biāo)準(zhǔn)的內(nèi)容無關(guān)的大小調(diào)整技術(shù)(如裁剪和縮放)不同,接縫雕刻保留了圖像最有趣的功能,如縱橫比、顯示的對象集等。。。
使用接縫雕刻調(diào)整內(nèi)容感知圖像大小
下面的代碼演示了如何使用scikit-image
庫的transform
模塊的seam_curve()
函數(shù)來調(diào)整內(nèi)容感知圖像的大小。讓我們首先導(dǎo)入所需的包,加載原始輸入飛機(jī)圖像,并使用以下代碼塊顯示圖像:
# for jupyter notebook uncomment the next line of code
# % matplotlib inline
from skimage import data, draw
from skimage import transform, util
import numpy as np
from skimage import filters, color
from matplotlib import pyplot as pylab
image = imread('../images/aero.jpg')
print(image.shape)
# (821, 616, 3)
image = util.img_as_float(image)
energy_image = filters.sobel(color.rgb2gray(image))
pylab.figure(figsize=(20,16)), pylab.title('Original Image'), pylab.imshow(image), pylab.show()
下面顯示前面代碼塊的輸出:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-0eAT0Q9t-1681961504734)(img/47c6706a-2919-4c89-8d54-86498835b449.png)]
讓我們使用resize()
函數(shù)縮小此圖像,使用通常的下采樣縮小圖像的寬度,如以下代碼片段所示:
resized = transform.resize(image, (image.shape[0], image.shape[1] - 200), mode='reflect')
print(resized.shape)
# (821, 416, 3)
pylab.figure(figsize=(20,11)), pylab.title('Resized Image'), pylab.imshow(resized), pylab.show()
下面顯示前面代碼塊的輸出。從以下輸出中可以看出,飛機(jī)的尺寸大幅減小,但它們也被扭曲了,因?yàn)楹唵蔚貙⒊叽缯{(diào)整為新的縱橫比會扭曲圖像內(nèi)容:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-ayCPLUDu-1681961504734)(img/4b44f42b-182e-4f41-988b-087ba6416675.png)]
現(xiàn)在讓我們用seam_carve()
函數(shù)調(diào)整圖像的大小。這里,sobel
過濾器用作energy
函數(shù),表示每個(gè)像素的重要性:
image = util.img_as_float(image)
energy_image = filters.sobel(color.rgb2gray(image))
out = transform.seam_carve(image, energy_image, 'vertical', 200)
pylab.figure(figsize=(20,11)), pylab.title('Resized using Seam Carving'), pylab.imshow(out)
下面顯示了前面代碼塊的輸出??梢钥闯觯瑂eam carving 試圖通過刪除其認(rèn)為不太重要的圖像區(qū)域(即能量較低的區(qū)域),在不失真的情況下調(diào)整大小。因此,飛機(jī)沒有任何可見的變形:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-JYbq73uP-1681961504734)(img/b97efd46-1add-46d4-8a00-3bf2eeaf9567.png)]
用縫線雕刻去除物體
您也可以使用接縫雕刻從圖像中刪除對象或瑕疵。這需要使用較低的值對對象區(qū)域進(jìn)行加權(quán),因?yàn)樵诮涌p雕刻中優(yōu)先移除較低的權(quán)重。以下代碼塊使用與原始輸入照片形狀相同的遮罩圖像,遮罩包含體重較輕的狗的照片區(qū)域,表示應(yīng)將其移除:
image = imread('man.jpg')mask_img = rgb2gray(imread('man_mask.jpg'))print(image.shape)pylab.figure(figsize=(15,10))pylab.subplot(121), pylab.imshow(image), pylab.title('Original Image')pylab.subplot(122), pylab.imshow(mask_img), pylab.title('Mask for the object to be removed (the dog)') pylab.show()
以下是。。。
無縫克隆和泊松圖像編輯
泊松圖像編輯的目標(biāo)是從源圖像(由遮罩圖像捕獲)到目標(biāo)圖像執(zhí)行對象或紋理的無縫混合(克?。?。我們希望通過使用泊松圖像編輯將圖像區(qū)域粘貼到新背景上來創(chuàng)建一個(gè) photomontage。這一想法來源于佩雷斯等人發(fā)表的 SIGGRAPH2003 論文泊松圖像編輯。該問題首先在連續(xù)域中表示為約束變分優(yōu)化問題(使用 Euler-Lagrange 方程求解),然后可以使用離散 Poisson 解算器求解。離散泊松解算器的主要任務(wù)是求解一個(gè)龐大的線性系統(tǒng)。本文的中心觀點(diǎn)是,使用圖像梯度,而不是圖像強(qiáng)度,可以產(chǎn)生更真實(shí)的結(jié)果。無縫克隆后,遮罩區(qū)域中輸出圖像的梯度與遮罩區(qū)域中源區(qū)域的梯度相同。另外,在遮罩區(qū)域的邊界處的輸出圖像的強(qiáng)度與目的地圖像的強(qiáng)度相同。
在本節(jié)中,我們將演示 Python 和 OpenCV 的無縫克?。∣penCV 3.0 中引入了seamlessClone()
函數(shù))。讓我們使用此函數(shù)將源圖像中的天空中的鳥復(fù)制到目標(biāo)sea-bird
圖像中的天空中。以下是我們將使用的照片:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-aIWSQfJF-1681961504735)(img/3858be25-9bbf-46ba-8c1f-fcc2b877b473.png)]
目的地圖像:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-9BWhT4AH-1681961504735)(img/1095e20a-8bb2-4c8a-b43f-bbe8b4e57c2e.png)]
下一個(gè)代碼塊顯示了如何通過調(diào)用具有正確參數(shù)的函數(shù)來實(shí)現(xiàn)無縫克隆。在本例中,使用的克隆類型標(biāo)志為NORMAL_CLONE
,其中源圖像的紋理(漸變)保留在克隆區(qū)域中:
import cv2
print(cv2.__version__) # make sure the major version of OpenCV is 3
# 3.4.3
import numpy as np
# read source and destination images
src = cv2.imread("bird.jpg")
dst = cv2.imread("sea.jpg")
# read the mask image
src_mask = cv2.imread("birds_mask.jpg")
print(src.shape, dst.shape, src_mask.shape)
# (480, 698, 3) (576, 768, 3) (480, 698, 3)
# this is where the CENTER of the airplane will be placed
center = (450,150)
# clone seamlessly.
output = cv2.seamlessClone(src, dst, src_mask, center, cv2.NORMAL_CLONE)
# save result
cv2.imwrite("sea_bird.jpg", output)
下面顯示了前面代碼塊的輸出,源映像中的 bird 已無縫克隆到目標(biāo)映像:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-pDb3IQHD-1681961504735)(img/6434d984-7854-4ea1-8a45-6d4fec69b112.png)]
圖像修復(fù)
修復(fù)是修復(fù)圖像受損或缺失部分的過程。假設(shè)我們有一個(gè)二元掩碼D,它指定了輸入圖像f中受損像素的位置,如下所示:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-jeoptsex-1681961504735)(img/1ab99695-f02c-4ab5-978a-130c3658712f.png)]
一旦用掩模定位圖像中的受損區(qū)域,丟失/受損像素必須用某種算法重建(例如,全變修復(fù)。通過利用非損傷區(qū)域的信息,可以完全自動地進(jìn)行重建
在本例中,我們將演示使用scikit-image``restoration
模塊inpaint_biharmonic() ...
的圖像修復(fù)實(shí)現(xiàn)
變分圖像處理
在本節(jié)中,我們將非常簡要地討論圖像處理中的變分方法,并舉例說明在去噪中的應(yīng)用。圖像處理任務(wù)可以看作是函數(shù)估計(jì)(例如,分割可以看作是在對象和背景之間找到一條平滑的閉合曲線)。對于特定的圖像處理任務(wù),可以使用變分法最小化適當(dāng)定義的能量泛函(使用 Euler-Langrange 方法),并使用梯度下降法向解決方案方向發(fā)展。
下圖描述了圖像處理任務(wù)的基本步驟,表示為變分優(yōu)化問題。首先,我們需要?jiǎng)?chuàng)建一個(gè)能量泛函E,用于描述輸入圖像u的質(zhì)量。然后,使用 Euler-Lagrange 方程,我們需要計(jì)算第一個(gè)變量。接下來,我們需要建立一個(gè)用于最速下降最小化的偏微分方程(PDE),并將其離散化并向最小值演化:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-xvRQ9FyQ-1681961504735)(img/e48a9f83-2a3b-49ae-acf4-c4d617ee0a66.png)]
全變差去噪
下面展示了線性和非線性全變差去噪算法。從下面可以看出,能量泛函是唯一的區(qū)別:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-qJhe10St-1681961504736)(img/0cbe5d02-be44-44fc-a7d9-3835c22cce45.png)]
讓我們演示一個(gè)使用scikit-image
庫的restoration
模塊實(shí)現(xiàn)的全變差去噪。全變差去噪的原理是最小化圖像的總變差,它可以粗略地描述為圖像梯度范數(shù)的積分。首先,讓我們通過將隨機(jī)高斯噪聲與原始輸入圖像相加來創(chuàng)建帶噪的輸入圖像。接下來,讓我們使用denoise_tv_chambolle()
函數(shù)來執(zhí)行。。。
使用全變差去噪創(chuàng)建平面紋理卡通圖像
全變差去噪可用于產(chǎn)生卡通圖像;也就是說,分段恒定圖像,如所示。我們增加的權(quán)重越多,紋理就越平坦(以犧牲對輸入圖像的逼真度為代價(jià)):
image = io.imread('../images/me18.jpg')
pylab.figure(figsize=(10,14))
pylab.subplot(221), pylab.imshow(image), pylab.axis('off'), pylab.title('original', size=20)
denoised_img = denoise_tv_chambolle(image, weight=0.1, multichannel=True)
pylab.subplot(222), pylab.imshow(denoised_img), pylab.axis('off'), pylab.title('TVD (wt=0.1)', size=20)
denoised_img = denoise_tv_chambolle(image, weight=0.2, multichannel=True)
pylab.subplot(223), pylab.imshow(denoised_img), pylab.axis('off'), pylab.title('TVD (wt=0.2)', size=20)
denoised_img = denoise_tv_chambolle(image, weight=0.3, multichannel=True)
pylab.subplot(224), pylab.imshow(denoised_img), pylab.axis('off'), pylab.title('TVD (wt=0.3)', size=20)
pylab.show()
下圖顯示了前一個(gè)代碼塊的輸出,使用不同的權(quán)重,通過全變差去噪獲得平坦紋理圖像。權(quán)重越大,紋理越平坦:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-1mFQs1UH-1681961504736)(img/913846f8-e9af-403f-9d3b-6baffe262a54.png)]
圖像絎縫
圖像絎縫算法是一種用于圖像紋理合成和傳輸?shù)乃惴ǎ珽fros 和 Freeman 在SIGGRAPH 2001論文中對此進(jìn)行了描述。在本節(jié)中,我們將討論用于實(shí)現(xiàn)紋理合成和傳輸?shù)慕W縫算法背后的主要思想,并展示通過實(shí)現(xiàn)該算法獲得的兩個(gè)結(jié)果。代碼留給讀者執(zhí)行(參見https://sandipanweb.wordpress.com/2017/10/24/some-computational-photography-image-quilting-texture-synthesis-with-dynamic-programming-and-texture-transfer-in-python/ 了解更多信息)。
紋理合成
紋理合成是指從小樣本中創(chuàng)建較大的紋理圖像。對于紋理合成,主要思想是采樣面片并將其以重疊模式放置,以便重疊區(qū)域相似。重疊區(qū)域可能不完全匹配,這將導(dǎo)致邊緣周圍出現(xiàn)明顯的瑕疵。為了解決這個(gè)問題,我們需要計(jì)算一條路徑,沿著重疊區(qū)域中具有類似強(qiáng)度的像素,并使用該路徑選擇在哪個(gè)重疊面片上繪制每個(gè)像素。下面顯示了紋理合成算法生成的輸出:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-gSuIm9Ga-1681961504736)(img/9453c652-594c-469c-ab09-789bd71e78fd.png)]
紋理轉(zhuǎn)移
紋理轉(zhuǎn)移是指在保持物體基本形狀的同時(shí),賦予物體與樣本具有相同紋理的外觀。紋理轉(zhuǎn)移是通過鼓勵(lì)采樣的面片與給定的目標(biāo)圖像具有相似的外觀來實(shí)現(xiàn)的,以及匹配已采樣面片的重疊區(qū)域。以下屏幕截圖顯示了紋理傳輸算法生成的輸出:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-V8Il4kP2-1681961504737)(img/69daa7cd-5957-4dd9-bbdd-99e786ae50e3.png)]
面變形
在第一章圖像處理入門中,我們討論了一種基于簡單α-混合的天真人臉變形技術(shù),如果要變形的人臉沒有對齊,這看起來很糟糕。
最后一章,我們將討論一種復(fù)雜的人臉變形技術(shù),即Beier-Neely 變形,它在視覺上比未對齊人臉的α-混合更平滑、更好。以下是算法:
- 讀入兩個(gè)圖像文件,A 和 B。
- 使用一組線段對以交互方式指定源圖像和目標(biāo)圖像之間的對應(yīng)關(guān)系(通過使用 PyStasm 計(jì)算面部關(guān)鍵點(diǎn))。將線段對保存到“線”文件中。
- 讀取行文件。線條文件包含線段對 SiA、SiB
- 通過在 SiA和 SiB之間通過翹曲分?jǐn)?shù)線性插值計(jì)算目的線段。這些線段定義了目標(biāo)形狀。
- 將圖像 A 扭曲到其目標(biāo)形狀,計(jì)算新圖像 A’
- 將圖片 B 扭曲到其目標(biāo)形狀,計(jì)算新的圖像 B’。
- 通過溶解分?jǐn)?shù)α在 A’和 B’之間交叉溶解。
- 將生成的圖像保存到文件中。
這個(gè)算法的實(shí)現(xiàn)留給讀者。下圖顯示了使用 PyStasm 庫的面變形實(shí)現(xiàn)。第一行中的圖像是源圖像和目標(biāo)圖像,最后一行顯示兩個(gè)中間平均人臉圖像??梢钥闯?,使用此實(shí)現(xiàn),變形非常平滑且視覺上令人愉悅:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-iB1diPyA-1681961504737)(img/aee43830-7b47-47fa-a924-18830f44e714.png)]
總結(jié)
在本章中,我們討論了一些高級圖像處理問題。我們從接縫雕刻算法開始,并通過scikit-image
庫演示了該算法在上下文感知圖像大小調(diào)整和從圖像中去除對象或偽影方面的應(yīng)用。文章來源:http://www.zghlxwxcb.cn/news/detail-439985.html
接下來,我們討論了使用 Python 和 OpenCV 將一個(gè)對象從一個(gè)圖像復(fù)制到另一個(gè)圖像的應(yīng)用程序的無縫克隆。然后,我們討論了雙諧波修復(fù)算法,并利用scikit-image
庫將其應(yīng)用于圖像中受損像素的恢復(fù)。然后,我們討論了變分方法在圖像處理中的應(yīng)用,并用scikit-image
對圖像進(jìn)行去噪。接下來,我們討論了圖像絎縫算法及其應(yīng)用。。。文章來源地址http://www.zghlxwxcb.cn/news/detail-439985.html
問題
- 使用
MIXED_CLONE
作為與python-opencv
無縫克隆的克隆類型參數(shù)。輸出與使用NORMAL_CLONE
獲得的輸出有何區(qū)別 - 使用梯度下降的變分優(yōu)化實(shí)現(xiàn)全變分修復(fù)(提示:參考https://sandipanweb.wordpress.com/2017/10/08/some-more-variational-image-processing-diffusiontv-denoising-image-inpainting/ )。
- 對 RGB 圖像應(yīng)用全變差去噪。
進(jìn)一步閱讀
- Shai Avidan 和 Ariel Shamir:用于內(nèi)容感知圖像大小調(diào)整的接縫雕刻-http://www.cs.jhu.edu/~misha/ReadingSeminar/Papers/Avidan07.pdf
- 帕特里克·佩雷斯、米歇爾·甘內(nèi)特和安德魯·布萊克:泊松圖像編輯-http://www.irisa.fr/vista/Papers/2003_siggraph_perez.pdf
- 用于紋理合成和轉(zhuǎn)移的絎縫:http://www.merl.com/publications/docs/TR2001-17.pdf
- 雙調(diào)和函數(shù)圖像修復(fù):https://arxiv.org/pdf/1707.06567.pdf
- 基于特征的圖像變形:https://www.cs.toronto.edu/~mangas/teaching/320/assignments/a4/Beier-SIG92.pdf
- https://sandipanweb.wordpress.com/2017/10/14/seam-carving-using-dynamic-programming-to-implement-context-aware-image-resizing-in-python/
- https://sandipanweb.wordpress.com/2017/10/03/some-variational-image-processing-possion-image-editing-and-its-applications/ …
到了這里,關(guān)于Python 圖像處理實(shí)用指南:11~12的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!