您現在的位置是:首頁 > 藝術

如何使用OpenCV的去除自動紅眼

由 影象演算法 發表于 藝術2021-05-29
簡介dilate(mask, None, anchor=(-1, -1), iterations=3, borderType=1, borderValue=1)第4步:修復紅眼現在我們有了一個只包含每隻眼睛紅色區域的蒙版

防紅眼功能怎麼開啟

如何使用OpenCV的去除自動紅眼

在本教程中,我們將學習如何完全自動消除照片中的紅眼。

僅僅考慮消除紅眼的問題,就會帶回我小時候的記憶。小時候擁有一臺傻瓜相機“ Hotshot”。它可能是我們家庭中唯一的行動式電子裝置,使用了數十年。我媽媽把相機和她的黃金首飾鎖在一個保險箱中。攝影是為非常特殊的場合而保留的,因為膠捲很貴。有時要過幾個月才能拍攝出我們拍攝的照片。自然,當我們晚上拍攝的照片產生紅眼效果時,它總是讓我心碎。滿臉鮮血的微笑的人使我想起了德古拉!

在本科期間的某個時候,我想出了一種使用照片編輯工具手動消除紅眼的方法。學習基本原理給我帶來了很多快樂,它的簡單性讓我感到驚訝!我要花幾年的時間才能弄清楚如何完全自動地做到這一點。

構建一個適用於各種影象的健壯的紅眼消除應用程式超出了本文的範圍。但是,我們將學習基本原理並構建概念證明應用程式。

是什麼導致閃光燈攝影中出現紅眼效應?

如何使用OpenCV的去除自動紅眼

當您在黑暗的房間裡時,您的瞳孔會變大(放大),以便讓更多的光線進入,以幫助您更好地看到。大多數相機上的閃光燈都非常靠近鏡頭。當您在閃光燈開啟的情況下拍照時,閃光燈發出的光線會透過擴大的瞳孔到達眼球后部,然後再透過瞳孔射入相機的鏡頭。眼球的背面稱為眼底。它是紅色的,因為眼底有充足的血液供應。

眼底影象顯示在左側。檢查眼底可以揭示一個人的健康狀況。您甚至可以獲取智慧手機應用程式,以幫助您檢視帶有附件的眼底。

這些天大多數相機閃光燈會閃爍幾秒鐘,這會使瞳孔收縮,從而減少了紅眼的可能性。

如何自動刪除紅眼?

在本節中,我們將逐步介紹用於自動消除紅眼的演算法。

步驟1:眼睛檢測

OpenCV眼睛檢測

如何使用OpenCV的去除自動紅眼

第一步是自動檢測眼睛。我們使用標準的OpenCV Haar檢測器(haarcascade_eye。xml)來尋找眼睛。有時先執行面部檢測器,然後再檢測面部區域內的眼睛是有意義的。為了簡單起見,我們直接在影象上執行眼睛檢測器。當輸入影象為人像拍攝或眼睛特寫時,可以跳過臉部檢測器。

您還可以說明訓練自己的HAAR物件檢測器。

我在下面共享用於眼睛檢測器的程式碼。

C++

// Read imageMat img = imread(“red_eyes。jpg”,CV_LOAD_IMAGE_COLOR); // Output imageMat imgOut = img。clone(); // Load HAAR cascade CascadeClassifier eyes_cascade(“haarcascade_eye。xml”); // A vector of Rect for storing bounding boxes for eyes。std::vector eyes; // Detect eyes。 eyesCascade。detectMultiScale( img, eyes, 1。3, 4, 0 | CASCADE_SCALE_IMAGE, Size(100, 100) );

Python

# Read imageimg = cv2。imread(“red_eyes。jpg”, cv2。IMREAD_COLOR) # Output imageimgOut = img。copy() # Load HAAR cascadeeyesCascade = cv2。CascadeClassifier(“haarcascade_eye。xml”) # Detect eyeseyes = eyesCascade。detectMultiScale(img,scaleFactor=1。3, minNeighbors=4, minSize=(100, 100))

步驟2:遮住紅眼

接下來,我們需要找到受紅眼影響的瞳孔部分。找到紅色的方法有很多。需要注意的一件事是我們的顏色不僅是紅色,還是鮮紅色!您可以根據色相和亮度將影象轉換為HSV顏色空間和閾值。在本文中,我們使用了一種更簡單的啟發式方法。我們說他的紅色通道應該大於閾值,也應該大於綠色和藍色通道的總和。出於概念驗證系統的目的,試探法就足夠了,但是如果您要為商業軟體包構建自動防紅眼功能,則需要收集數千張紅眼影象才能提出更好的解決方案。

在下面的程式碼中,我們遍歷在上一步中檢測到的所有眼睛矩形。然後,我們使用命令split將彩色影象分成三個通道。最後,對於紅色通道高於閾值(150)且紅色通道大於綠色通道和藍色通道之和的每個畫素,我們建立一個掩碼為1的蒙版。

C++

for( size_t i = 0; i < eyes。size(); i++ ){ // Extract eye from the image。 Mat eye = img(eyes[i]); // Split eye image into 3 channels。 vectorbgr(3); split(eye,bgr); // Simple red eye detector Mat mask = (bgr[2] > 150) & (bgr[2] > ( bgr[1] + bgr[0] ));}

Python

for (x, y, w, h) in eyes: # Extract eye from the image。 eye = img[y:y+h, x:x+w] # Split eye image into 3 channels b = eye[:, :, 0] g = eye[:, :, 1] r = eye[:, :, 2] # Add the green and blue channels。 bg = cv2。add(b, g) # Simple red eye detector mask = (r > 150) & (r > bg) # Convert the mask to uint8 format。 mask = mask。astype(np。uint8)*255

步驟3:清理瞳孔面罩

如何使用OpenCV的去除自動紅眼

左:基於顏色的瞳孔罩。中心:有孔的學生口罩。右:散瞳罩

在上一步中建立的蒙版很可能會帶有孔。上圖中的左圖顯示了使用顏色處理獲得的原始蒙版。

C++

void fillHoles(Mat &mask){ Mat mask_floodfill = mask。clone(); floodFill(mask_floodfill, cv::Point(0,0), Scalar(255)); Mat mask2; bitwise_not(mask_floodfill, mask2); mask = (mask2 | mask); }

Python

def fillHoles(mask): maskFloodfill = mask。copy() h, w = maskFloodfill。shape[:2] maskTemp = np。zeros((h+2, w+2), np。uint8) cv2。floodFill(maskFloodfill, maskTemp, (0, 0), 255) mask2 = cv2。bitwise_not(maskFloodfill) return mask2 | mask

另外,最好擴大遮罩,使其覆蓋比所需區域稍大的區域。這是因為在邊界處,顏色逐漸消失,並且在我們的原始蒙版中可能未捕獲到某些紅色。在上圖中,右圖是蒙版的放大圖。我們使用下面共享的程式碼生成擴充套件的蒙版。

C++

// Clean up mask by filling holes and dilatingfillHoles(mask);dilate(mask, mask, Mat(), Point(-1, -1), 3, 1, 1);

Python

# Clean up mask by filling holes and dilatingmask = fillHoles(mask)mask = cv2。dilate(mask, None, anchor=(-1, -1), iterations=3, borderType=1, borderValue=1)

第4步:修復紅眼

現在我們有了一個只包含每隻眼睛紅色區域的蒙版。接下來,我們展示如何處理此蒙版中的區域以修復紅眼。

我們知道,紅眼睛會使影象中的紅色通道飽和。換句話說,紅色通道中的所有資訊均被破壞。我們如何才能找回一些資訊?修復紅眼時,我們無需檢索紅色通道中的真實基礎紋理;我們只需要找到合理的紋理即可。

幸運的是,紅眼效果只會破壞紅色通道中的紋理;藍色和綠色通道仍然不錯。您可以在下圖中看到該位置,其中顯示了影象的紅色,綠色和藍色通道。

如何使用OpenCV的去除自動紅眼

左:紅色通道。中心:藍色通道。右:綠色通道。

綠色和藍色通道的組合可用於提出合理的紅色通道。例如,我們可以建立一個紅色通道,該通道是影象中綠色和藍色通道的平均值。但是,這樣做可能會使瞳孔略帶淡淡,看起來不錯,但效果不佳。注意中間影象中的紫色調。

如何使用OpenCV的去除自動紅眼

左:紅眼睛。中心:透過替換紅色通道進行固定。右:替換了所有通道後修復。

這給我們帶來了一個重要的問題。瞳孔應該是什麼顏色?瞳孔是眼睛的開口,眼睛的內部完全是黑暗的。因此,瞳孔應該是無色(灰度)和深色的。代替僅替換瞳孔區域中的紅色通道,我們將所有通道替換為綠色和藍色通道的均值。這消除了紫色調。

下面的程式碼首先透過平均綠色和藍色通道來建立平均通道。然後,它將所有通道的被遮罩區域內的所有畫素替換為該平均通道。

C++

// Calculate the mean channel by averaging// the green and blue channelsMat mean = (bgr[0]+bgr[1])/2; // Copy the mean image to blue channel with mask。mean。copyTo(bgr[0], mask); // Copy the mean image to green channel with mask。mean。copyTo(bgr[1], mask); // Copy the mean image to red channel with mask。mean。copyTo(bgr[2], mask);

Python

# Calculate the mean channel by averaging# the green and blue channels。 Recall, bg = cv2。add(b, g)mean = bg / 2mask = mask。astype(np。bool)[:, :, np。newaxis]mean = mean[:, :, np。newaxis] # Copy the eye from the original image。 eyeOut = eye。copy() # Copy the mean image to the output image。 np。copyto(eyeOut, mean, where=mask)

步驟5:更換固定眼部區域

在上一步中,我們修復了三個渠道。最後一步是合併三個通道以建立我們的RGB影象,然後將此固定眼圖區域放回原始影象中。

C++

// Merge the three channelsMat eyeOut;merge(bgr,eyeOut); // Copy the fixed eye to the output image。 eyeOut。copyTo(imgOut(eyes[i]));

Python

# Copy the fixed eye to the output image。 imgOut[y:y+h, x:x+w, :] = eyeOut

自動去除紅眼結果

我們首先在示例影象上顯示結果。

如何使用OpenCV的去除自動紅眼

請注意,從瞳孔區域刪除所有顏色會使影象看起來很漂亮,因為眼睛中心的點是完全白色的。還要注意,在瞳孔的邊界上,紅色逐漸減弱,但是由於進行了擴張操作,我們仍然捕獲了該區域。

接下來,我們在眼睛的特寫照片上顯示結果。如果我們使用了面部檢測器,它將不會檢測到面部,並且自動眼睛檢測器將無法工作。

如何使用OpenCV的去除自動紅眼

推薦文章