相機自動對焦功能在數字智慧型手機中的工作原理及機器學習擴展代碼

相機自動對焦功能在數字智能手機中的工作原理及機器學習擴展代碼

介紹

雖然相機作為捕捉圖像的工具已有150多年的歷史,但智能手機的出現極大地改變了相機的使用,並將其與軟件編程集成在一起。如今,相機不再完成“簡單”任務,例如拍攝靜止照片或拍攝視頻,它們實際上覆制了人眼執行的大部分複雜任務。

事實上,計算機視覺中使用的大多數算法和公式都是基於對人眼的感知。例如,通過對R,B和G像素值求平均來對RGB圖像進行灰度級處理,將圖像的通道減少到1通道的方法,使用以下公式:灰色←0.299⋅R+0.587⋅G+ 0.114 ⋅B。注意:顯然與平均R,G和B像素值不同(如公式所示:Gray←0.33⋅R+0.33⋅G+0.33⋅B)。

但為什麼?這是因為與色度相比,我們的眼睛對亮度/亮度更敏感。灰度級圖像時使用的實際公式與計算給定像素的亮度/亮度值相同。注意:亮度值是YUV和YCrCb顏色空間中的Y值。

相機自動對焦功能在數字智能手機中的工作原理及機器學習擴展代碼

圖1

自動對焦是相機的一個有趣功能。它實際上可以複製我們眼睛的聚焦能力。為了更好地可視化,請在不同平面上拍攝兩個物體(水瓶和插座),如圖1所示。現在把注意力集中在水瓶上。不知不覺中,你的眼睛模糊了後面的牆壁插座。對牆壁插座重複相同的操作,我們的眼睛會自動模糊水瓶。現在在家中複製類似的設置並打開手機的相機應用程序。通過點擊您想要關注的區域,相機會像我們的眼睛一樣自動模糊其他物體。這是相機自動對焦的神奇之處。今天,相機使用許多算法來聚焦圖像。我將重點介紹一種基本的自動對焦算法:基於對比度的自動對焦。

基於對比度的自動對焦如何在高水平上工作?

基於對比度的自動對焦基本上測量不同相機鏡頭位置的對比度。相機鏡頭將一直移動,直到達到其定義為具有最大對比度的點。我們可以將對比度定義為圖像中的銳度。為了更好地可視化,這裡是各種相機鏡頭位置的虛擬圖像(比較黑色方塊的邊緣):

相機自動對焦功能在數字智能手機中的工作原理及機器學習擴展代碼

圖2

為了概括對比度,我們可以為每個圖像分配0到1之間的任意對比度值,其中0表示未聚焦/低對比度圖像,1表示聚焦/高對比度圖像。

相機自動對焦功能在數字智能手機中的工作原理及機器學習擴展代碼

圖3

現在,相機循環通過變化的相機鏡頭位置,計算圖像內的對比度,然後比較並選擇具有最高對比度值的相機鏡頭位置。

我們如何定義對比度?

有許多不同的方法來定義對比度。實際上,算法的複雜性是基於用於定義對比度的方法確定的。今天我將介紹一種非常基本的方法,它不需要額外的硬件,如傳感器。請注意,公司通常利用手機內置的其他硬件組件來提高算法的複雜性。

為圖像指定對比度值的一種基本方法是Canny邊緣檢測。實際上,這就是OpenCV如何計算自動對焦的最佳相機鏡頭位置。對於每個鏡頭位置,我們繪製圖像的邊緣並根據邊緣的清晰度分配對比度值。例如,下面的圖像序列顯示執行Canny邊緣檢測算法後的輸出:

相機自動對焦功能在數字智能手機中的工作原理及機器學習擴展代碼

圖4

如您所見,圖像聚焦越少,邊緣越不清晰。事實上,在設置Canny邊緣檢測算法的默認設置後,您會注意到它無法檢測左側兩個日益未聚焦的圖像的邊緣。顯然,通過降低算法的最小閾值,我們將能夠看到邊緣。但是為了自動對焦,我們可以丟棄不檢測邊緣的相機鏡頭位置。

如果您想進一步探索OpenCV的自動聚焦算法,請查看以下代碼:https://github.com/opencv/opencv/blob/master/samples/cpp/autofocus.cpp。

結論

基於對比度的自動對焦算法需要許多計算 - > L * O(對比度),其中L是可能的相機鏡頭位置的數量,O(對比度)是用於確定圖像內對比度的算法的複雜度。在上面的例子中,確定邊緣是否清晰的複雜性需要大於O(m * n),其中m和n是幀的尺寸。由於這種高複雜性,許多創建相機驅動程序(Qualcomm,Apple等)的公司研究新的和更有效的方法來確定圖像是否聚焦。一些其他常見的算法包括PDAF,激光等。事實上,作為一個側面實驗,

利用機器學習進行擴展

作為擴展,我決定使用基於機器學習的方法來定義對比度。因為每幀的計算邊緣計算量很大,所以我決定設計一個神經網絡,這應該會降低基於對比度的自動對焦算法的複雜性。

我決定嘗試前饋和卷積神經網絡。

我開始嘗試使用前饋神經網絡,因為這更容易實現。我創建了一個4層的小型神經網絡。在這個神經網絡中,我為一個大小為224乘224像素的3通道圖像添加了一個輸入層。然後我繼續將尺寸flatten 為單個維度,並添加了1024個神經元的隱藏層。我沒有直接跳到最後一層,而是決定追加128個神經元的另一個隱藏層。最後,我用2個神經元的輸出層完成了神經網絡,以指示聚焦或未聚焦。

主要Python代碼如下:

from keras import layers

my_model = keras.models.Sequential()

my_model.add(layers.Dense(3, input_shape=(224,224, 3), activation='relu'))

my_model.add(layers.Flatten())

my_model.add(layers.Dense(1024, activation='relu'))

my_model.add(layers.Dropout(0.5))

my_model.add(layers.Dense(128, activation='relu'))

my_model.add(layers.Dropout(0.5))

my_model.add(layers.Dense(2, activation='softmax'))

my_model.summary()

'''

SET UP TRAINING AND VALIDATION DATA

'''

from keras.preprocessing.image import ImageDataGenerator, load_img

train_datagen = ImageDataGenerator(

rescale=1./255,

rotation_range=20,

width_shift_range=0.2,

height_shift_range=0.2,

horizontal_flip=True,

vertical_flip=True,

fill_mode='nearest')

validation_datagen = ImageDataGenerator(rescale=1./255)

train_batchsize = 20

val_batchsize = 5

train_generator = train_datagen.flow_from_directory(

'train_data',

target_size=(224, 224),

batch_size=train_batchsize,

class_mode='categorical')

validation_generator = validation_datagen.flow_from_directory(

'validation_data',

target_size=(224, 224),

batch_size=val_batchsize,

class_mode='categorical',

shuffle=False)

# Compile

try:

my_model = keras.models.load_model('autofocus_ff.h5') # trains from last epoch if model exists

except:

print "Training new model..."

my_model.compile(loss='categorical_crossentropy',

optimizer='adam',

metrics=['acc'])

# Train

checkpoint = keras.callbacks.ModelCheckpoint('autofocus_ff.h5', monitor='val_loss', verbose=1, period=1)

my_model_hist = my_model.fit_generator(

train_generator,

steps_per_epoch=2*train_generator.samples/train_generator.batch_size ,

epochs=25,

validation_data=validation_generator,

validation_steps=validation_generator.samples/validation_generator.batch_size,

verbose=1,

callbacks=[checkpoint])

# Save the Model

my_model.save('autofocus_ff.h5')

在我開始訓練這個前饋神經網絡後,我發現模型的驗證準確性和損失在每個時期都不再提高。

這促使我嘗試使用卷積神經網絡(CNN),因為它們似乎可以為物體檢測提供更好的結果。Keras有許多預先訓練過的CNN模型,我選擇根據給定的問題微調vgg16模型。我採用了vgg16模型的5個卷積塊,然後添加了一個全局平均池圖層,將尺寸減小到1,同時還有效地減少了可訓練參數的數量。最後,我添加了一個2個神經元的輸出層來表示聚焦或未聚焦的置信度。

Python實現的過程如下:

from keras.applications import VGG16

#Load the VGG model

vgg16 = VGG16(include_top=False, input_shape=(224, 224, 3)) # load vgg16 with all defaults except top

'''

MARK ALL LAYERS AS NON-TRAINABLE SO TRAINING DOESN'T ALTER WEIGHTS

'''

for layer in vgg16.layers:

layer.trainable = False

'''

TUNE MODEL TO AUTOFOCUS NEEDS

'''

from keras import layers

# my_model_output = vgg16.layers[10].output # Only use the first three blocks of convolution

my_model_output = vgg16.output # use all 5 conv layers of vgg

my_model_output = layers.GlobalAveragePooling2D()(my_model_output) # Then add a GlobalAveragePooling layer to get 1d representation

# my_model_output = layers.Dense(128, activation='relu')(my_model_output) # add a Dense layer just to increase trainable params

# my_model_output = layers.Dropout(0.5)(my_model_output) # Add regularization to help decrease overfitting data

my_model_output = layers.Dense(2, activation='softmax')(my_model_output) # binary classification prediction layer

my_model = keras.models.Model(inputs=vgg16.input, outputs=my_model_output) #created my neural network

my_model.summary()

'''

SET UP TRAINING AND VALIDATION DATA

'''

from keras.preprocessing.image import ImageDataGenerator, load_img

train_datagen = ImageDataGenerator(

rescale=1./255,

rotation_range=20,

width_shift_range=0.2,

height_shift_range=0.2,

horizontal_flip=True,

vertical_flip=True,

fill_mode='nearest')

validation_datagen = ImageDataGenerator(rescale=1./255)

train_batchsize = 20

val_batchsize = 5

train_generator = train_datagen.flow_from_directory(

'train_data',

target_size=(224, 224),

batch_size=train_batchsize,

class_mode='categorical')

validation_generator = validation_datagen.flow_from_directory(

'validation_data',

target_size=(224, 224),

batch_size=val_batchsize,

class_mode='categorical',

shuffle=False)

'''

COMPILE AND TRAIN MODEL

'''

# Compile

try:

my_model = keras.models.load_model('autofocus_vgg16.h5') # trains from last epoch if model exists

except:

print "Training new model..."

my_model.compile(loss='categorical_crossentropy',

optimizer='adam',

metrics=['acc'])

# Train

checkpoint = keras.callbacks.ModelCheckpoint('autofocus_vgg16.h5', monitor='val_loss', verbose=1, period=1)

my_model_hist = my_model.fit_generator(

train_generator,

steps_per_epoch=2*train_generator.samples/train_generator.batch_size ,

epochs=25,

validation_data=validation_generator,

validation_steps=validation_generator.samples/validation_generator.batch_size,

verbose=1,

callbacks=[checkpoint])

# Save the Model

my_model.save('autofocus_vgg16.h5')

# Compile

try:

my_model = keras.models.load_model('autofocus_vgg16.h5') # trains from last epoch if model exists

except:

print "Training new model..."

my_model.compile(loss='categorical_crossentropy',

optimizer='adam',

metrics=['acc'])

# Train

checkpoint = keras.callbacks.ModelCheckpoint('autofocus_vgg16.h5', monitor='val_loss', verbose=1, period=1)

my_model_hist = my_model.fit_generator(

train_generator,

steps_per_epoch=2*train_generator.samples/train_generator.batch_size ,

epochs=25,

validation_data=validation_generator,

validation_steps=validation_generator.samples/validation_generator.batch_size,

verbose=1,

callbacks=[checkpoint])

# Save the Model

my_model.save('autofocus_vgg16.h5')

'''

PREDICT

'''

import numpy as np

import keras

from keras.models import load_model

from keras.preprocessing import image

model = keras.models.load_model('autofocus_vgg16.h5')

def load_image_as_tensor(img_path):

img = image.load_img(img_path, target_size=(224, 224))

img = image.img_to_array(img)

img = np.expand_dims(img, axis=0)

img /= 255.

return img

def predict(img_path):

img = load_image_as_tensor(img_path)

prob = model.predict(img)

classes = np.argmax(prob, axis=1)

label_map = (validation_generator.class_indices)

print img_path

print prob, classes, label_map

predict('test_blur/black_square.jpg')

predict('test_blur/black_square9.jpg')

predict('test_blur/black_square17.jpg')

predict('test_blur/black_square25.jpg')

predict('test_blur/black_square33.jpg')

predict('test_blur/black_square41.jpg')

# 100% Accurate for these 6 test images

與前饋神經網絡相比,該模型的準確性要好得多,我完成了25個時期,驗證準確率為0.76,驗證損失為0.49。雖然這些數字不是很好,但我覺得這些數字反映了缺乏訓練數據。我只使用了1400張訓練圖像,如果我將其增加到大約6000-7000張圖像,我覺得我的準確度會有顯著提高。我在圖2所示的6個圖像上測試了我的模型。模型正確地將每個圖像標記為聚焦或未聚焦。


分享到:


相關文章: