蒼老師的“碼”是怎麼打上的?

11-06

--OpenCV 初體驗,Swift 和 C++ 混編

提到OpenCV,相信大多數人都聽說過,應用領域非常廣泛,使用 C++ 開發,天生具有跨平臺的優勢,我們學習一次,就可以在各個平臺使用,這個還是很具有誘惑力的。

本文主要記錄我第一次使用 OpenCV,在 iOS 開發平臺上面搭建開發環境,並且實現一個簡單的馬賽克功能

開發環境:Swift4、XCode 9.0

1、什麼是 OpenCV?

由英特爾公司於 1999 年發起並參與開發,至今已有 18 年歷史

OpenCV 的全稱是 Open Source Computer Vision Library

是一個跨平臺的開源計算機視覺庫,可用於開發實時的圖像處理、計算機視覺以及模式識別程序。

支持 C/C++、Java、Python、OC、Swift、Ruby 等等語言

支持 Windows、 Android、 Maemo、 FreeBSD、 OpenBSD、 iOS、 Linux 和 Mac OS

2、難點,思路

由於我們使用的是 Swift,由於目前還不能在 Swift 中使用 C++ 的類,所以我們得想一個方法,在 Swift 中調用 C++ 的類

其實方法很簡單,Swift 天生具有跟 Objective-C++ 混編的能力,而 Objective-C++ 裡面是可以直接使用 C++ 的類的,上面的問題也就解決瞭

3、馬賽克原理

其實把圖片的像素密度調低,就可以出現馬賽克效果瞭

開始做馬賽克之前,需要定一個馬賽克的級別,表示原圖中每幾個像素變成新圖裡面的一個像素

取一小塊區域左上角的一個像素,並把這個像素填充到整個小區域內

如下圖,左邊是原圖,右邊是經過變換之後的圖,假設馬賽克級別為 3,每個數字表示的區域就是處理的一個小單元,取這個最小單元左上角的顏色,填充整個小單元就 OK 瞭

4、開動工程

4.1、搭建 c++ 和 swift 混編環境

我們首先要搭建一個 c++ 的環境,然後才能進行 c++ 的開發,而 c++ 環境可以通過 iostream 裡面的 cout 函數驗證

1. 首先,我們使用 xCode 新建一個 swift 的 iOS 項目

2. 在工程內,新建一個 Objective-C 類,繼承 NSObject,這裡會自動提示我們是否為項目添加橋接文件,選擇添加即可(橋接文件是用來向 Swift 暴露 Objective-C 方法的)

3. 因為我們要使用 Objective-C++,而把 Objective-C 轉成 Objective-C++ 的方法有兩種

把 .m 文件的後綴名改為 .mm,xCode 就會自動識別我們的代碼為 Objective-C++ 瞭(xCode 會通過後綴名自動識別源文件類型)

選中要修改的 .m 文件,在右邊的 Type 屬性修改成:Objective-C++ Source(也可以手動指定源文件類型)

4. 在剛才的 .mm 文件中,添加一個測試方法,在這裡測試一下 C++ 環境是否搭建成功

#import "MyUtil.h"#import // 記得導入 iostrem 頭文件 using namespace std;@implementation MyUtil+ ( void ) testCpp { cout

5. 在前面 xCode 自動創建的橋接文件中暴露我們的測試方法頭文件

6. 在 Swift 中調用測試方法,控制臺輸出 "Hello Swift and Cpp" 就正常瞭

import UIKitclass ViewController: UIViewController { override func viewDidLoad ( ) { super.viewDidLoad ( ) // 測試方法 MyUtil.testCpp ( ) }}

4.2、導入 OpenCV 動態庫

在 iOS 開發中導入 OpenCV 的庫其實非常簡單,直接拖拽到工程文件就行瞭

1. 首先去 OpenCV 的官網下載我們需要的 framework,下載地址:https://opencv.org/releases.html,選擇最新版本的 iOS pack 即可

2. 下載下來之後解壓,然後拖拽到我們的工程目錄,設置如下圖

3. 設置我們的工程鏈接 OpenCV 動態庫

4.build 一下,確認不會報錯

4.3、實現馬賽克函數

接下來就是幹代碼的時候瞭

1. 首先要在 .m 文件中,導入 OpenCV 的頭文件,導入頭文件之後代碼如下,這裡有幾個坑要註意:

不要在 .h 文件中去導入 OpenCV 的相關頭文件,否則會報錯,錯誤信息 : Core.hpp header must be compiled as C++,看到這個問題,趕緊把頭文件移動到 .m 文件中去

還有就是 OpenCV 的頭文件最好放在 #import 之前,否則也會報一個錯誤 : enum { NO, FEATHER, MULTI_BAND }; Expected identifier

// 導入 OpenCV 框架 最好放在 Foundation.h UIKit.h 之前 // 核心頭文件 #import // 對 iOS 支持 #import // 導入矩陣幫助類 #import #import #import "MyUtil.h"#import using namespace std;using namespace cv;

2. 實現馬賽克函數

+ ( UIImage* ) opencvImage: ( UIImage* ) image level: ( int ) level{ // 實現功能 // 第一步:將 iOS 圖片 ->OpenCV 圖片 ( Mat 矩陣 ) Mat mat_image_src; UIImageToMat ( image, mat_image_src ) ; // 第二步:確定寬高 int width = mat_image_src.cols; int height = mat_image_src.rows; // 在 OpenCV 裡面,必須要先把 ARGB 的顏色空間轉換成 RGB 的,否則處理會失敗(官方例程裡面,每次處理都會有這個操作) //ARGB->RGB Mat mat_image_dst; cvtColor ( mat_image_src, mat_image_dst, CV_RGBA2RGB, 3 ) ; // 為瞭不影響原始圖片,克隆一張保存 Mat mat_image_clone = mat_image_dst.clone ( ) ; // 第三步:馬賽克處理 int xMax = width - level; int yMax = height - level; for ( int y = 0; y 多個)->ARGB-> 數組 //mat_image_clone.at ( i, j ) [ 0 ] ->R 值 //mat_image_clone.at ( i, j ) [ 1 ] ->G 值 //mat_image_clone.at ( i, j ) [ 2 ] ->B 值 Scalar scalar = Scalar ( mat_image_clone.at ( y, x ) [ 0 ] , mat_image_clone.at ( y, x ) [ 1 ] , mat_image_clone.at ( y, x ) [ 2 ] ) ; // 取出要處理的矩形區域 Rect2i mosaicRect = Rect2i ( x, y, level, level ) ; Mat roi = mat_image_dst ( mosaicRect ) ; // 將前面處理的小區域拷貝到要處理的區域 //CV_8UC3 的含義 //CV_: 表示框架命名空間 //8 表示:32 位色 ->ARGB->8 位 = 1 字節 -> 4 個字節 //U: 無符號類型 //C 分析:char 類型 //3 表示:3 個通道 ->RGB Mat roiCopy = Mat ( mosaicRect.size ( ) , CV_8UC3, scalar ) ; roiCopy.copyTo ( roi ) ; } } // 第四步:將 OpenCV 圖片 ->iOS 圖片 return MatToUIImage ( mat_image_dst ) ;}

4.4、在 swift 中調用馬賽克函數

函數已經實現瞭,接下來就是在 Swift 中調用瞭

1. 為瞭便於測試,我們在 storyboard 中搭一個簡單的界面,在按鈕中切換馬賽克圖片和原圖,界面如下 :

2. 在按鈕點擊事件中調用上面的馬賽克函數即可

@IBOutlet weak var imageView: UIImageView! /// 顯示原圖按鈕 @IBAction func origImageBtnClick ( _ sender: Any ) { imageView.image = UIImage ( named: "pic.jpg" ) } /// 顯示馬賽克圖片 @IBAction func mosaicImageBtnClick ( _ sender: Any ) { guard let origImage = imageView.image else { return } let mosaicImage = MyUtil.opencvImage ( origImage, level: 20 ) imageView.image = mosaicImage }

3. 效果如下,左邊的是原圖,右邊的是馬賽克之後的圖片,就這樣,蒼老師的碼就打上去啦 ~

5、後記

對於 C++,很多人並不陌生,不過我想對於 iOS 開發者來說,用過 C++ 的童鞋並不多吧,我一直很崇拜那些 C++ 大神,因為通過 C++,我們可以很方便的實現跨平臺開發,就我們今天的馬賽克代碼來說,移植到安卓平臺,裡面的東西也隻需要做很小部分的修改,就可以非常完美的適配 ( 當然,安卓的開發環境麼有 iOS 這麼簡單 ) ,所以,掌握和使用 C++ 的性價比還是很高的。

完整代碼已經上傳到 github: https://github.com/fengqiangboy/FirstOpenCV,不過移除瞭 OpenCV.framework,因為太多傳不上去,歡迎大傢給 Star

精彩圖片
文章評論 相關閱讀
© 2016 看看新聞 http://www.kankannews.cc/