iOS-OpenCV之蔡徐坤教你玩轉邊框畫

期刊地址

  1. iOS實現字符串動畫
  2. iOS-OpenCV之蔡徐坤教你玩轉邊框畫

前言

這一系列的文章已經寫了第二篇了,因此這個系列將會轉變爲連載文章,每當我有什麼新的發現,都會更新。python

本文demo地址: github.com/chouheiwa/O…ios

正文

如今關於OpenCV的不少有趣的例子,都是python的。git

這篇文章的總體思路來源於 知乎Maker畢 的文章: 蔡徐坤教你用OpenCV實現素描效果github

上一篇文章中咱們已經講述過了,圖像的存儲,以及一些相關的信息。這篇文章就不會重複了,若是不是很清楚的讀者能夠看看第一篇文章。數組

這篇文章說是素描,其實與廣義素描差距很大,準確的說應該是叫邊框畫。ide

先上一下效果圖吧。函數

image

看起來是否是挺有意思的動畫

步驟及原理

這裏咱們仍是要先講述一下步驟,這裏先展現下原圖網站

cxk

1. 將給定圖片轉灰度圖

轉成灰度圖片的過程是爲了消除其餘影響因子(這一步也是不少圖片處理|文字識別等相關領域的第一步)。ui

將圖片從原來的三維層面,降到一維。

- (UIImage *)grayImage:(UIImage *)image {
    cv::Mat cvImage;

    UIImageToMat(image, cvImage);

    cv::Mat gray;
    // 將圖像轉換爲灰度顯示
    cv::cvtColor(cvImage, gray, CV_RGB2GRAY);

    cvImage.release();
    // 將灰度圖片轉成UIImage
    UIImage *nImage = MatToUIImage(gray);

    gray.release();

    return nImage;
}
複製代碼

處理完畢後,咱們能看到原來的蔡老師變灰了。

cxk01

2. 對灰度圖片進行高斯模糊

首先,先來說一下如何進行簡單的 模糊 處理

在上一篇文章中咱們已經講過了,圖片其實就是一個二維數組。

因此圖片上的每個像素,都有一個像素數值。

咱們能夠以當前像素點爲中心,取一個n * n的矩陣。

hui-du-tu-pian

這裏假定咱們選了一箇中心灰度值爲190的像素點,它的周邊像素的像素灰度值爲100(255爲純白色)的3*3的像素矩陣

模糊處理的簡單形式就是作平均,也就是將中間點的像素點和周圍8個像素點的灰度值取平均值。也就是(100 * 8 + 190) / 9 = 110

hui-du-tu-pian-_xiu-gai

簡單的模糊處理就是這麼作的,不過高斯模糊是經過高斯函數去進行相應的計算,這裏我找到了一篇至關好的文章: 高斯模糊

- (UIImage *)gaussianblurImage:(UIImage *)image {
    cv::Mat cvImage;

    UIImageToMat(image, cvImage);

    cv::Mat blur;
    // 選取一個5 * 5 的核用於模糊
    cv::GaussianBlur(cvImage, blur, cv::Size(5, 5), 0);
    cvImage.release();
    UIImage *blurImage = MatToUIImage(blur);
    blur.release();

    return blurImage;
}
複製代碼

有一個模糊的蔡老師出現了

cxk02

3. 對圖像進行自適應二值化處理

這一步其實要講的就是二值化,其實他的概念很簡單。咱們將灰度圖上的某一個像素點的灰度值與給定的一個值進行比較,小於這個給定值的咱們將其灰度值設置爲0(黑色),大於的設置爲255(白色)。咱們給定的比較值被稱之爲閾值

er-zhi-hua-tu-pian

固然,這種二值化太過固化、死板。由於真實的照片有可能有陰影之類的遮擋,會致使咱們的全局二值化,產生不少的偏差,以下圖右上角所示:

opencv_thresholding

所以咱們須要採用自適應二值化的方法,這裏咱們選擇採用自適應高斯二值化(效果如上圖右下角)

- (UIImage *)adaptiveThresholdImage:(UIImage *)image {
    cv::Mat cvImage;

    UIImageToMat(image, cvImage);

    cv::Mat outImage;

    cv::adaptiveThreshold(cvImage, outImage,
                          255,
                          cv::ADAPTIVE_THRESH_GAUSSIAN_C, // 這裏咱們採用的是高斯自適應模糊
                          cv::THRESH_BINARY, // 二值化
                          5,
                          2);

    cvImage.release();

    UIImage *adaImage = MatToUIImage(outImage);

    outImage.release();

    return adaImage;
}
複製代碼

蔡老師的線條出現啦

cxk03

4. 二值化圖片進行再次模糊

如今蔡老師的衣服都已經變成線條了,基礎的描邊效果已經達成。可是咱們能夠看到,圖片中好比說地面上,還有一些黑色的咱們並不想要的點(咱們稱這些點爲噪點)。以及蔡老師的線條仍是有點細,因此咱們須要將蔡老師的線條變粗些。

將上面的圖片再次進行高斯模糊。

cxk04

蔡老師變得模糊了

5. 對模糊圖片再次進行二值化

這裏咱們再次進行二值化操做,由於如今圖片已經相對乾淨,且並沒有陰影等干擾項。咱們能夠直接使用全局二值化來加深邊框了(計算速度快)。

- (UIImage *)thresholdImage:(UIImage *)image {
    cv::Mat cvImage;

    UIImageToMat(image, cvImage);

    cv::Mat outImage;
    // 由於這時的圖片已經比較乾淨且沒什麼陰影,因此選擇普通二值化,灰度值 > 200 (這個值能夠調,我以爲220效果更好) 的就賦值爲255(白色)
    cv::threshold(cvImage, outImage, 200, 255, cv::THRESH_BINARY);

    cvImage.release();

    UIImage *threImage = MatToUIImage(outImage);

    outImage.release();

    return threImage;
}
複製代碼

cxk05

6. 對圖片進行噪點去除

如今須要去除圖片中的小的噪點,咱們就須要進行一系列的操做了

關於這些操做,咱們在圖像處理方面有專門的名詞描述:

腐蝕膨脹

腐蝕:

腐蝕通俗的來講,就是將本來的圖像根據給定的核(爲咱們自定義的一種形狀,通常爲n*n的正方形,n爲奇數)縮小。

fu-shi-shuo-ming

只有當本來的圖像上對應核心周圍全部的點都有值時,咱們才保留當前核心的值。

fu-shi-liu-cheng

膨脹:

膨脹則正好相反,咱們將給定的圖片根據給定的核放大。

fu-shi-shuo-ming

當咱們掃描核的任意一點上有值時,當前核心點將會被賦值

peng-zhang-liu-cheng

腐蝕膨脹即是咱們這步處理的關鍵。

它們之間的組合被咱們稱之爲開運算閉運算

開運算

咱們先對圖片進行腐蝕運算,而後進行膨脹運算

最終效果將如上圖的左下角結果

咱們和原圖進行比較能夠發現。

開運算能夠去除毛刺,小橋和孤立的小點(在腐蝕運算中小點會直接消失)。最終總的位置和形狀不變(膨脹運算會恢復)

閉運算

閉運算這裏由於咱們不會用到,所以不會過多贅述。

它和開運算的過程相反,先對原圖像進行膨脹運算後進行腐蝕運算。

咱們的目的是處理圖片中的一些噪點,所以咱們採用開運算來處理。

- (UIImage *)morphologyImage:(UIImage *)image {
    cv::Mat cvImage;

    UIImageToMat(image, cvImage);
    // 將圖片取反,原黑變白,原白變黑
    cv::bitwise_not(cvImage, cvImage);

    cv::Mat outImage;
    /// 獲取一個3*3的核
    cv::Mat ken = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
    /// 進行圖像的開運算(開運算須要對有數值的地方進行縮小,因此咱們須要將圖片反色,即大部分有數值,而小部分沒有,才能達到效果)
    cv::morphologyEx(cvImage, outImage, cv::MORPH_OPEN, ken);

    ken.release();

    cvImage.release();

    cv::bitwise_not(outImage, outImage);

    UIImage *morphologyImage = MatToUIImage(outImage);

    outImage.release();

    return morphologyImage;
}
複製代碼

圖片乾淨了不少

cxk06

7. 最後進行一次高斯模糊

咱們最後在進行一次高斯模糊,使咱們的圖像效果更好。

cxk07

其餘

視頻的轉換,這裏就很少寫了(正在研究過程當中...)

這篇文章的對應demo請點擊網址,若是你們以爲還不錯,請盡情的用你麼的star來砸我。

結尾

圖像處理很是有趣,同時很高端。

若是你們有什麼問題或疑問,能夠關注個人公衆號並提問。只要看到了會第一時間回覆,也能夠直接在github中提issue。

個人博客網站

公衆號
相關文章
相關標籤/搜索