OpenCVを使ってリアルタイムに顔認識
やはりリアルタイムに認識するのは重いですね。そりゃそうですよね、iPhoneだもの。
1.いつものようにプロジェクトファイルを作って、いったんXCodeを終了する
2.ターミナルを開き、以下を行う
[sudo] gem install cocoapodsと入力してリターンキーを押す
pod setupと入力してリターンキーを押す
3.いったんターミナルを終了する
4.ターミナルを開き、cdと入力した後にスペースを押す。そして1.のプロジェクトファイル(ファイル名.xcodeprojが入っているフォルダ)を
ドラッグ&ドロップする。そうするとパスが表示されます。そのままリターンキーを押す
5.pod initと入力
6.ターミナルを終了する。プロジェクトファイルが入ったフォルダの中にPodfileというファイルが出来ているので、それを
miなどのテキストエディタで開き、以下のように編集して保存する。
注:どうも2.4.10ではバグがあるようです。あとpod 'OpenCV'だけではダメで、バージョンも入れる必要があります
# Uncomment this line to define a global platform for your project # platform :ios, '8.0' target 'opencvTest4' do pod 'OpenCV', '2.4.9' end target 'opencvTest4Tests' do end
7.4.と同じ
8.pod installと入力し、リターンキーを押す
9.ファイル名.xcworkspaceをダブルクリックして開く
10.こちらを参照してファイルを作ったりコードを入力していく(ありがとうございます)
11.CameraUtil.swiftを以下のように書き換えたほうが良いっぽい
import Foundation import UIKit import AVFoundation class CameraUtil { // sampleBufferからUIImageへ変換 class func imageFromSampleBuffer(sampleBuffer: CMSampleBufferRef) -> UIImage { let imageBuffer: CVImageBufferRef = CMSampleBufferGetImageBuffer(sampleBuffer) // ベースアドレスをロック CVPixelBufferLockBaseAddress(imageBuffer, 0) // 画像データの情報を取得 let baseAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0) let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer) let width = CVPixelBufferGetWidth(imageBuffer) let height = CVPixelBufferGetHeight(imageBuffer) // RGB色空間を作成 let colorSpace = CGColorSpaceCreateDeviceRGB() // Bitmap graphic contextを作成 let bitsPerCompornent: UInt = 8 var bitmapInfo = CGBitmapInfo((CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue) as UInt32) let context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, bitmapInfo) // Quartz imageを作成 let imageRef = CGBitmapContextCreateImage(context) // ベースアドレスをアンロック CVPixelBufferUnlockBaseAddress(imageBuffer, 0) // UIImageを作成 let resultImage: UIImage = UIImage(CGImage: imageRef)! return resultImage } }
OpenCVを使う
Swift+iOSでOpenCVを使ってみます。
最初はcocoapodsをインストールしていたのですが、どうにもリンクエラーになってしまって
opencv2.frameworkを追加する以下のような方法でやることにしました。
1.こちらにアクセスし、
新しいバージョン(2015年6月の時点では3.0.0)をクリック、さらにopencv2.framework.zipをクリックし
ダウンロードする
2.プロジェクトファイルを作成し、プロジェクトファイルのLinked Fremeworks and Librariesに先ほど
ダウンロードし解凍したopencv2.frameworkをドラック&ドロップする
3.Fileメニュー→New→Fileを選択し、iOS-Source-Objective-C Fileを選ぶ。File typeはEmpty Fileにし、ファイル名を入力。
ここではTestOpenCVとします
4.ファイル名.mとプロジェクトファイル名-Bridging-Header.hができるので、ファイル名.mをファイル名.mmに書き換える
5.ファイル名.mmとプロジェクトファイル名-Bridging-Header.hにOpenCVのコードを書いていく
今回はこちらを参考にさせて頂いて、輪郭線を抽出するコードを書きます。
・プロジェクトファイル名-Bridging-Header.h
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface TestOpenCV : NSObject +(UIImage *)DetectEdgeWithImage:(UIImage *)image; @end
・ファイル名.mm
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> #import "openCVTest2-Bridging-Header.h" #import <opencv2/opencv.hpp> #import <opencv2/imgcodecs/ios.h> @implementation TestOpenCV : NSObject +(UIImage *)DetectEdgeWithImage:(UIImage *)image{ //UIImageをcv::Matに変換 cv::Mat mat; UIImageToMat(image, mat); //白黒濃淡画像に変換 cv::Mat gray; cv::cvtColor(mat, gray, CV_BGR2GRAY); //エッジ検出 cv::Mat edge; cv::Canny(gray, edge, 200, 180); //cv::MatをUIImageに変換 UIImage *edgeImg = MatToUIImage(edge); return edgeImg; } @end
6.StoryboardにImageViewを設置し、画像を追加する
7.ViewControllerとImageeViewを結びつけ、以下のように入力する
import UIKit class ViewController: UIViewController { @IBOutlet weak var cvTestPic: UIImageView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. //ここから追加 var image = cvTestPic.image var edge = TestOpenCV.DetectEdgeWithImage(image) cvTestPic.image = edge as UIImage; } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
追記あり;Bluetoothでデータ送受信
★
func peripheral(peripheral: CBPeripheral!, didWriteValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) ...と
@IBAction func writeBtnTapped(sender: UIButton)...の項目を追加して、セントラル側からペリフェラル側へ
データを送れるようにしました。
これでペリフェラルとセントラルの双方でデータのやりとりができます。
Bluetoothでデータ送受信というと、画像などのメディアも送受信できるMultipeer Connectivityを使うのがスムーズなのかもですが、
どうやらCore Bluetoothのほうが電池をくわないそうなので、大変でしたがこっちで書いてみました。
こちらの本「iOS×BLE Core Bluetoothプログラミング」をベースにSwiftで書いています。
この本はとても素晴らしい本なのですが、Swiftでない部分もあるので、そこは補完しました。
まず最初にプロジェクトの設定画面でCoreBluetoothのFrameworkを読み込んでおきます。
Linked Frameworks and Librariesの+をクリックして、CoreBluetooth.Frameworkを選ぶだけ。
以下はペリフェラル(データ送る)側でボタンを押すとその値がセントラル(データ受信側)に送られて、
セントラル側でその値に応じたテキストとUIImageが表示されます。
ペリフェラル側でトリガーを送ってあげて、セントラル側でそのトリガーに合ったアクションが起きるという感じですね。
・ペリフェラル(データ送る)側
import UIKit import CoreBluetooth class ViewController: UIViewController, CBPeripheralManagerDelegate { @IBOutlet var advertiseBtn: UIButton! @IBOutlet var valueLabel: UILabel! @IBOutlet var strLabel: UILabel! var peripheralManager: CBPeripheralManager! var serviceUUID: CBUUID! var characteristic: CBMutableCharacteristic! var data:NSData! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. self.peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: nil) self.valueLabel.text = nil; } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func publishservice () { // サービスを作成 self.serviceUUID = CBUUID(string: "0000") let service = CBMutableService(type: serviceUUID, primary: true) // キャラクタリスティックを作成 let characteristicUUID = CBUUID(string: "0001") let properties = ( CBCharacteristicProperties.Notify | CBCharacteristicProperties.Read | CBCharacteristicProperties.Write) let permissions = ( CBAttributePermissions.Readable | CBAttributePermissions.Writeable) self.characteristic = CBMutableCharacteristic( type: characteristicUUID, properties: properties, value: nil, permissions: permissions) // キャラクタリスティックをサービスにセット service.characteristics = [self.characteristic] // サービスを Peripheral Manager にセット self.peripheralManager.addService(service) var msg: String = "0" let data: NSData! = msg.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion:true) println("data: \(data)") self.characteristic.value = data; } func startAdvertise() { // アドバタイズメントデータを作成する let advertisementData: Dictionary = [ CBAdvertisementDataLocalNameKey: "Test Device", CBAdvertisementDataServiceUUIDsKey: [self.serviceUUID] ] // アドバタイズ開始 self.peripheralManager.startAdvertising(advertisementData) self.advertiseBtn.setTitle("STOP ADVERTISING", forState: UIControlState.Normal) } func stopAdvertise () { // アドバタイズ停止 self.peripheralManager.stopAdvertising() self.advertiseBtn.setTitle("START ADVERTISING", forState: UIControlState.Normal) } //データ送信 func updateValueLabel () { let reportData = UnsafePointer<UInt8>(data.bytes) var bpm : UInt16 bpm = UInt16(reportData[0]) bpm = CFSwapInt16LittleToHost(bpm) let outputString = String(bpm) self.valueLabel.text = "分類用文字: \(outputString)" switch outputString { case "1": self.strLabel.text = "いちです" case "2": self.strLabel.text = "にです" case "3": self.strLabel.text = "さんです" default: self.strLabel.text = "その他" //ランダムな数値を出力する場合 //self.valueLabel.text = NSString(format: "Characteristic value: %@", self.characteristic.value) as String } } // ペリフェラルマネージャの状態が変化すると呼ばれる func peripheralManagerDidUpdateState(peripheral: CBPeripheralManager!) { println("state: \(peripheral.state)") switch peripheral.state { case CBPeripheralManagerState.PoweredOn: // サービス登録開始 self.publishservice() break default: break } } // サービス追加処理が完了すると呼ばれる func peripheralManager(peripheral: CBPeripheralManager!, didAddService service: CBService!, error: NSError!) { if (error != nil) { println("サービス追加失敗! error: \(error)") return } println("サービス追加成功!") // アドバタイズ開始 self.startAdvertise() } // アドバタイズ開始処理が完了すると呼ばれる func peripheralManagerDidStartAdvertising(peripheral: CBPeripheralManager!, error: NSError!) { if (error != nil) { println("アドバタイズ開始失敗! error: \(error)") return } println("アドバタイズ開始成功!") } // Readリクエスト受信時に呼ばれる func peripheralManager(peripheral: CBPeripheralManager!, didReceiveReadRequest request: CBATTRequest!) { println("Readリクエスト受信! requested service uuid:\(request.characteristic.service.UUID) characteristic uuid:\(request.characteristic.UUID) value:\(request.characteristic.value)") // プロパティで保持しているキャラクタリスティックへのReadリクエストかどうかを判定 if request.characteristic.UUID.isEqual(self.characteristic.UUID) { // CBMutableCharacteristicのvalueをCBATTRequestのvalueにセット request.value = self.characteristic.value; // リクエストに応答 self.peripheralManager.respondToRequest(request, withResult: CBATTError.Success) } } // Writeリクエスト受信時に呼ばれる func peripheralManager(peripheral: CBPeripheralManager!, didReceiveWriteRequests requests: [AnyObject]!) { println("\(requests.count) 件のWriteリクエストを受信!") for obj in requests { if let request = obj as? CBATTRequest { println("Requested value:\(request.value) service uuid:\(request.characteristic.service.UUID) characteristic uuid:\(request.characteristic.UUID)") if request.characteristic.UUID.isEqual(self.characteristic.UUID) { // CBCharacteristicのvalueに、CBATTRequestのvalueをセット self.characteristic.value = request.value; } } } // リクエストに応答 self.peripheralManager.respondToRequest(requests[0] as! CBATTRequest, withResult: CBATTError.Success) } // Notify開始リクエスト受信時に呼ばれる func peripheralManager(peripheral: CBPeripheralManager!, central: CBCentral!, didSubscribeToCharacteristic characteristic: CBCharacteristic!) { println("Notify開始リクエストを受信") println("Notify中のセントラル: \(self.characteristic.subscribedCentrals)") } // Notify停止リクエスト受信時に呼ばれる func peripheralManager(peripheral: CBPeripheralManager!, central: CBCentral!, didUnsubscribeFromCharacteristic characteristic: CBCharacteristic!) { println("Notify停止リクエストを受信") println("Notify中のセントラル: \(self.characteristic.subscribedCentrals)") } @IBAction func advertiseBtnTap(sender: UIButton) { if (!self.peripheralManager.isAdvertising) { self.startAdvertise() } else { self.stopAdvertise() } } @IBAction func updateBtn1(sender: UIButton) { // 新しい値となるNSDataオブジェクトを生成 //1の値を送ったとき let valuemoto = 1 let value = UInt8(valuemoto & 0xFF) data = NSData(bytes: [value] as [UInt8], length: 1) // 値を更新 self.characteristic.value = data; let result = self.peripheralManager.updateValue( data, forCharacteristic: self.characteristic, onSubscribedCentrals: nil) println("resultだよ: \(result)") self.updateValueLabel() } @IBAction func updateBtn2(sender: UIButton) { // 新しい値となるNSDataオブジェクトを生成 //2の値を送ったとき let valuemoto = 2 let value = UInt8(valuemoto & 0xFF) data = NSData(bytes: [value] as [UInt8], length: 1) // 値を更新 self.characteristic.value = data; let result = self.peripheralManager.updateValue( data, forCharacteristic: self.characteristic, onSubscribedCentrals: nil) println("resultだよ: \(result)") self.updateValueLabel() } @IBAction func updateBtn3(sender: UIButton) { // 新しい値となるNSDataオブジェクトを生成 //3の値を送ったとき let valuemoto = 3 let value = UInt8(valuemoto & 0xFF) data = NSData(bytes: [value] as [UInt8], length: 1) // 値を更新 self.characteristic.value = data; let result = self.peripheralManager.updateValue( data, forCharacteristic: self.characteristic, onSubscribedCentrals: nil) println("resultだよ: \(result)") self.updateValueLabel() } @IBAction func updateBtnRan(sender: UIButton) { //ランダムな値を送ったとき let value = UInt8(arc4random() & 0xFF) let data = NSData(bytes: [value] as [UInt8], length: 1) self.characteristic.value = data; let result = self.peripheralManager.updateValue( data, forCharacteristic: self.characteristic, onSubscribedCentrals: nil) println("resultだよ: \(result)") self.updateValueLabel() } }
・セントラル(データを受信してそのデータに応じたアクションが起きるようにした)側
//データ受信側 import UIKit import CoreBluetooth //プロパティ定義 class ViewController: UIViewController, CBCentralManagerDelegate,CBPeripheralDelegate { @IBOutlet weak var valueLabel: UILabel! @IBOutlet weak var pictNumLabel: UILabel! @IBOutlet weak var myimageView: UIImageView! var isScanning = false var centralManager: CBCentralManager! var peripheral: CBPeripheral! var characteristic:CBCharacteristic! var aCharacteristic: CBCharacteristic! var outputString:String! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. //セントラルマネージャ初期化 self.centralManager = CBCentralManager(delegate: self, queue: nil) self.valueLabel.text = nil; } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } //データを表示 func updateValue() { var data2 = self.characteristic.value let reportData = UnsafePointer<UInt8>(data2.bytes) var bpm : UInt16 bpm = UInt16(reportData[0]) bpm = CFSwapInt16LittleToHost(bpm) let outputString = String(bpm) self.valueLabel.text = "文字変換: \(outputString)" switch outputString { case "1": pictNumLabel.text = "いちです" myimageView.image = UIImage(named: "testPic1.png") case "2": pictNumLabel.text = "にです" myimageView.image = UIImage(named: "testPic2.png") case "3": pictNumLabel.text = "さんです" myimageView.image = UIImage(named: "testPic3.png") case "4": pictNumLabel.text = "ランダム" myimageView.image = UIImage(named: "testPic4.png") default: pictNumLabel.text = "その他" myimageView.image = UIImage(named: "testPic1.png") } } //セントラルマネージャの状態が変化すると呼ばれる func centralManagerDidUpdateState(central: CBCentralManager!) { println("state: \(central.state)") } //周辺にあるデバイスを発見すると呼ばれる func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) { println("発見したBLEデバイス: \(peripheral)") self.peripheral = peripheral self.peripheral = peripheral // 接続開始 self.centralManager.connectPeripheral(self.peripheral, options: nil) } // ペリフェラルへの接続が成功すると呼ばれる func centralManager(central: CBCentralManager!, didConnectPeripheral peripheral: CBPeripheral!) { println("接続成功!") // サービス探索結果を受け取るためにデリゲートをセット peripheral.delegate = self // サービス探索開始 peripheral.discoverServices(nil) } // ペリフェラルへの接続が失敗すると呼ばれる func centralManager(central: CBCentralManager!, didFailToConnectPeripheral peripheral: CBPeripheral!, error: NSError!) { println("接続失敗・・・") } func centralManager(central: CBCentralManager!,didDisconnectPeripheral peripheral:CBPeripheral!,error: NSError!) { println("接続が切断されました。") if error != nil { println("エラー: \(error)") } self.peripheral = nil; self.characteristic = nil; self.valueLabel.text = nil; } // サービス発見時に呼ばれる func peripheral(peripheral: CBPeripheral!, didDiscoverServices error: NSError!) { if error != nil { println("エラー: \(error)") return } let services: NSArray = peripheral.services println("\(services.count) 個のサービスを発見! \(services)") for obj in services { if let service = obj as? CBService { // キャラクタリスティック探索開始 peripheral.discoverCharacteristics(nil, forService: service) } } } // キャラクタリスティック発見時に呼ばれる func peripheral(peripheral: CBPeripheral!, didDiscoverCharacteristicsForService service: CBService!, error: NSError!) { if error != nil { println("エラー: \(error)") return } let characteristics: NSArray = service.characteristics println("\(characteristics.count) 個のキャラクタリスティックを発見! \(characteristics)") // 特定のキャラクタリスティックをプロパティに保持 let uuid = CBUUID(string:"0001") for aCharacteristic in characteristics { if aCharacteristic.UUID == uuid { self.characteristic = aCharacteristic as! CBCharacteristic break; } } } // Notify開始/停止時に呼ばれる func peripheral(peripheral: CBPeripheral!, didUpdateNotificationStateForCharacteristic characteristic:CBCharacteristic!, error: NSError!) { if error != nil { println("Notify状態更新失敗...error:%@", error) } else { println("Notify状態更新成功!characteristic UUID:\(characteristic.UUID), isNotifying: \(characteristic.isNotifying)") } } // データ更新時に呼ばれる func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) { if error != nil { println("データ更新通知エラー:%@", error) return } else { println("データ更新! characteristic UUID: \(characteristic.UUID), value: \(characteristic.value)") updateValue() } } func peripheral(peripheral: CBPeripheral!, didWriteValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) { if error != nil { println("Write失敗...error:%@", error) } else { println("Write成功!") // このキャラクタリスティックの値には実はまだ更新が反映されていない updateValue() } } @IBAction func scanBtn(sender: UIButton) { if !isScanning { isScanning = true // スキャン開始(特定サービスを持つペリフェラルに限定) let serviceUUIDs:[AnyObject] = [CBUUID(string:"0000")] self.centralManager.scanForPeripheralsWithServices(serviceUUIDs, options: nil) sender.setTitle("STOP SCAN", forState: UIControlState.Normal) } else { // スキャン停止 self.centralManager.stopScan() sender.setTitle("START SCAN", forState: UIControlState.Normal) isScanning = false } } @IBAction func writeBtnTapped(sender: UIButton) { //13の値を送ったとき var valuemoto2 = 13 var value: UInt8 = UInt8(valuemoto2 & 0xFF) var data = NSData(bytes: [value] as [UInt8], length: 1) peripheral .writeValue(data, forCharacteristic: characteristic, type: CBCharacteristicWriteType.WithResponse) } @IBAction func notifyBtn1(sender: UIButton) { if !self.characteristic.isNotifying { // Notify開始をリクエスト self.peripheral .setNotifyValue(true, forCharacteristic: self.characteristic) sender.setTitle("STOP NOTIFY",forState:UIControlState.Normal) } else { // Notify停止をリクエスト self.peripheral .setNotifyValue(false, forCharacteristic: self.characteristic) sender.setTitle("START NOTIFY",forState:UIControlState.Normal) } } }
Google検索を使ってTwitter検索してヒット数を表示
以前Objective-C用に書いたモノのSwift移植です。辞書と配列は大変だった・・・
TwitterSearchAPIはヒット数まで出してくれないっぽいので、強引にGoogle検索に突っ込んでます。
println(responseData)とやると検索結果すべてのデータが取れるので、そこから余分な部分をカットします。
検索ヒット数=パワーみたいな。結果はすごく正確ではないと思われます。
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. //つぶやきを検索してヒット数を出す searchTw() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func searchTw() { //キーワード var searchKey: String = "荀イク" //日本語の場合は文字コードを変換 let searchQuery: String = searchKey.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)! var urlString1 = "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=" var urlString2 = "+site:http://twitter.com" //デフォのGoogle検索はhttp://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=荀イク //Google検索でTwitterを検索する用URL(ajax)、実際はhttp://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=荀イク+site:http://twitter.com var urlStringAll:String = urlString1 + searchQuery + urlString2 //urlStringAllで設定したアドレスにアクセスする設定をする var searchURL1 = NSURL(string: urlStringAll) if let searchURL2 = searchURL1 { var searchURLReq = NSURLRequest(URL: searchURL2) println("OK") NSURLConnection.sendAsynchronousRequest(searchURLReq, queue: NSOperationQueue.mainQueue(), completionHandler: self.getHttp) } else { // URLがなかったときの処理 println("NG") } } func getHttp(res:NSURLResponse?,data:NSData?,error:NSError?){ //jsonで解析する var searchdict = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary //「responseData」キーを取り出す var responseData = searchdict["responseData"] as! NSDictionary //「cursor」キーを取り出す var cursor = responseData["cursor"] as! NSDictionary //ヒット数に近いと思われる「estimatedResultCount」キーを取り出す var countData: NSString = cursor.objectForKey("estimatedResultCount") as! NSString //アバウトなヒット数表示 println(countData) } }
スクリーンセーバー・スライドショーもどき:テキストのフェードイン/アウト
以前Objective-c用に書いたもの(テキストアニメーション部分のみ)をSwift用に移植します。
テキストが一定時間ごとにフェードイン/アウトして、これもなんちゃってスクリーンセーバーです。スライドショーかな、むしろ。テキストを絵に変換してあげてもいけるかと。
QuartzCore.freamworkを使わなくてもいけます。
テキストラベルとボタンを設置して、結びつけておきます。
配列の数やタイマー用のカウントをもう少しちゃんとすれば、きちんとしたものができると思います。
下のですと最初の「いち」から「に」にかけての表示だけ、フェードインアウト処理の挙動が少しおかしいです。すみません。
import UIKit class ViewController: UIViewController { //フェードインアウト用タイマー var fadeInOutTimer: NSTimer? //テキストチェンジ用 var textTimer: NSTimer? //フェードインアウト用タイマー変数 var countTime = 0 //テキストチェンジ用変数 var textIndex: Int = 0 //テキストチェンジ用配列 let tenko = ["いち","に","さん","し","ご","ろく"] @IBOutlet weak var kabegami: UIImageView! @IBOutlet weak var sampleText: UILabel! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. kabegami.image = UIImage(named: "TestAppPict1.png") sampleText.text = "いち" } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } @IBAction func timerBtn(sender: AnyObject) { //フェードインアウト用タイマー fadeInOutTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "cdTimer:", userInfo: nil, repeats: true) //テキストチェンジタイミング用タイマー textTimer = NSTimer.scheduledTimerWithTimeInterval(8, target: self, selector: "textload:", userInfo: nil, repeats: true) } //フェードインアウト用タイマー func cdTimer(timer : NSTimer) { countTime += 1 //countTime == 8はフェードインアウトのNSTimeIntervalの合計数 if countTime == 8 { fadein() countTime = 0 } } //テキストチェンジ用 func textload(timer : NSTimer) { textIndex += 1 //textIndex > 5の5は配列の数-1(配列の5番目までいったら最初の0番目に戻る) if textIndex > 5 { textIndex = 0 } //表示したいテキストを格納した配列の中で何番目(textIndex)を読み込むか let textArray = tenko[textIndex] //配列の中で該当するものをテキストラベルに表示 sampleText.text = textArray } //フェードイン処理 func fadein() { //4秒かけてフェードイン処理を行う var changeFadeIn: NSTimeInterval = 4 UIView.animateWithDuration( NSTimeInterval(changeFadeIn), animations: { //透明度が1になったらフェードアウト処理を行う self.sampleText.alpha = 1 } , completion: { (finished: Bool) in self.fadeout() }) } //フェードアウト処理 func fadeout(){ //4秒かけてフェードアウト処理を行う var changeFadeOut: NSTimeInterval = 4 UIView.animateWithDuration( NSTimeInterval(changeFadeOut), animations: { //透明度が0になったらフェードアウト処理終了 self.sampleText.alpha = 0 } , completion: { (finished: Bool) in }) } }
Swift目次を作成しました
Swiftも目次を作成しました。ほぼ逆引きですね。随時追加していきます。
・タップした座標を獲得し、特定の範囲内かどうか検出する
http://d.hatena.ne.jp/prince9/20150517/1431817999
・スクリーンセーバー的なものを作る
http://d.hatena.ne.jp/prince9/20150518/1431897234
・スクリーンセーバー・スライドショーもどき:テキストのフェードイン/アウト
http://d.hatena.ne.jp/prince9/20150518/1431948860
・Google検索を使ってTwitter検索してヒット数を表示
http://d.hatena.ne.jp/prince9/20150519/1432003880
・Bluetoothでデータ送受信
http://d.hatena.ne.jp/prince9/20150526/1432625630
・OpenCVを使ってリアルタイムに顔認識
http://d.hatena.ne.jp/prince9/20150609/1433871814
スクリーンセーバー的なものを作る
しばらくプログラミングから離れていたので、これもまた地味に時間かかった・・・
あまりよくない書き方をしているような気がするので、もし訂正箇所があればコメント等でお願いします。
NSTimerがもっと正確な時間で作動して欲しいという場合は、
・var timeCount : Int = 0 のIntをFloatに
・NSTimer.scheduledTimerWithTimeInterval(1, target: self ...の1を0.1に
・timeCount += 1 を0.1に
・timeCount = 0 を0.0に
・if touchCount == 1 && timeCount == 4 { ... のtimeCountを4.0に
してあげれば良いかと思います(未検証)。もちろん、4秒はお好みで。
流れとしては、
1.起動して画像1表示
2.タッチすると画像2を表示
3.4秒経つと画像3を表示、タッチされなければこのまま画像3を表示
4.2と3を繰り返す
となっています。画像3のところでアニメーションを再生してあげるようにすれば、それっぽくなるのかな。
もちろん、1と3(画像1と3)の画像を同じにしてあげても良いと思います。今回は区別がつきやすいように変えてみました。
import UIKit class ViewController: UIViewController { @IBOutlet weak var screensaver: UIImageView! //タッチされた回数を示す変数 var touchCount = 0 //時間を示す変数 var timeCount : Int = 0 //タイマー var timer: NSTimer? override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. screensaver.image = UIImage(named: "iPhone4ViewPic.png") } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } //タッチされたか検知する override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) { for touch: AnyObject in touches { //タッチされたらタイマー始動(1秒ごと・整数) timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timeUpdate:", userInfo: nil, repeats: true) //タッチされたら1足す touchCount += 1 //スクリーンセーバーが起動していないときの画像 screensaver.image = UIImage(named: "iPhone4ViewPic2.png") } } func timeUpdate(timer : NSTimer){ //1秒ごとに1足す timeCount += 1 println("タイム= \(timeCount)") //タッチされてかつ4秒以上たったら、スクリーンセーバー始動&タイマー止まる。またタッチされたらタイマー始動 if touchCount == 1 && timeCount == 4 { touchCount = 0 timeCount = 0 //タイマー停止 self.timer?.invalidate() self.timer = nil //スクリーンセーバーの画像表示 screensaver.image = UIImage(named: "iPhone4ViewPic3.png") } } }